2 chat-commands.c : irssi
4 Copyright (C) 2000 Timo Sirainen
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include "special-vars.h"
28 #include "chat-protocols.h"
30 #include "servers-setup.h"
31 #include "servers-reconnect.h"
34 #include "window-item-def.h"
37 static SERVER_CONNECT_REC *get_server_connect(const char *data, int *plus_addr,
40 CHAT_PROTOCOL_REC *proto;
41 SERVER_CONNECT_REC *conn;
43 char *addr, *portstr, *password, *nick, *chatnet, *host, *tmp;
46 g_return_val_if_fail(data != NULL, NULL);
48 if (!cmd_get_params(data, &free_arg, 4 | PARAM_FLAG_OPTIONS,
49 "connect", &optlist, &addr, &portstr,
52 if (plus_addr != NULL) *plus_addr = *addr == '+';
53 if (*addr == '+') addr++;
55 signal_emit("error command", 1,
56 GINT_TO_POINTER(CMDERR_NOT_ENOUGH_PARAMS));
57 cmd_params_free(free_arg);
61 if (strcmp(password, "-") == 0)
64 /* check if -<chatnet> option is used to specify chat protocol */
65 proto = chat_protocol_find_net(optlist);
67 /* connect to server */
68 chatnet = proto == NULL ? NULL :
69 g_hash_table_lookup(optlist, proto->chatnet);
72 chatnet = g_hash_table_lookup(optlist, "network");
74 conn = server_create_conn(proto != NULL ? proto->id : -1, addr,
75 atoi(portstr), chatnet, password, nick);
77 proto = chat_protocol_find_id(conn->chat_type);
79 if (proto->not_initialized) {
80 /* trying to use protocol that isn't yet initialized */
81 signal_emit("chat protocol unknown", 1, proto->name);
82 server_connect_unref(conn);
83 cmd_params_free(free_arg);
87 if (strchr(addr, '/') != NULL)
88 conn->unix_socket = TRUE;
90 if (g_hash_table_lookup(optlist, "6") != NULL)
91 conn->family = AF_INET6;
92 else if (g_hash_table_lookup(optlist, "4") != NULL)
93 conn->family = AF_INET;
95 if (g_hash_table_lookup(optlist, "ssl") != NULL)
97 if ((tmp = g_hash_table_lookup(optlist, "ssl_cert")) != NULL)
98 conn->ssl_cert = g_strdup(tmp);
99 if ((tmp = g_hash_table_lookup(optlist, "ssl_pkey")) != NULL)
100 conn->ssl_pkey = g_strdup(tmp);
101 if (g_hash_table_lookup(optlist, "ssl_verify") != NULL)
102 conn->ssl_verify = TRUE;
103 if ((tmp = g_hash_table_lookup(optlist, "ssl_cafile")) != NULL)
104 conn->ssl_cafile = g_strdup(tmp);
105 if ((tmp = g_hash_table_lookup(optlist, "ssl_capath")) != NULL)
106 conn->ssl_capath = g_strdup(tmp);
107 if ((conn->ssl_capath != NULL && conn->ssl_capath[0] != '\0')
108 || (conn->ssl_cafile != NULL && conn->ssl_cafile[0] != '\0'))
109 conn->ssl_verify = TRUE;
110 if ((conn->ssl_cert != NULL && conn->ssl_cert[0] != '\0') || conn->ssl_verify)
111 conn->use_ssl = TRUE;
113 if (g_hash_table_lookup(optlist, "!") != NULL)
114 conn->no_autojoin_channels = TRUE;
116 if (g_hash_table_lookup(optlist, "noautosendcmd") != NULL)
117 conn->no_autosendcmd = TRUE;
119 if (g_hash_table_lookup(optlist, "noproxy") != NULL)
120 g_free_and_null(conn->proxy);
123 *rawlog_file = g_strdup(g_hash_table_lookup(optlist, "rawlog"));
125 host = g_hash_table_lookup(optlist, "host");
126 if (host != NULL && *host != '\0') {
129 if (net_gethostbyname(host, &ip4, &ip6) == 0)
130 server_connect_own_ip_save(conn, &ip4, &ip6);
133 cmd_params_free(free_arg);
137 /* SYNTAX: CONNECT [-4 | -6] [-ssl] [-ssl_cert <cert>] [-ssl_pkey <pkey>]
138 [-ssl_verify] [-ssl_cafile <cafile>] [-ssl_capath <capath>]
139 [-!] [-noautosendcmd]
140 [-noproxy] [-network <network>] [-host <hostname>]
142 <address>|<chatnet> [<port> [<password> [<nick>]]] */
143 /* NOTE: -network replaces the old -ircnet flag. */
144 static void cmd_connect(const char *data)
146 SERVER_CONNECT_REC *conn;
150 conn = get_server_connect(data, NULL, &rawlog_file);
152 server = server_connect(conn);
153 server_connect_unref(conn);
155 if (server != NULL && rawlog_file != NULL)
156 rawlog_open(server->rawlog, rawlog_file);
162 static RECONNECT_REC *find_reconnect_server(int chat_type,
163 const char *addr, int port)
165 RECONNECT_REC *match, *last_proto_match;
169 g_return_val_if_fail(addr != NULL, NULL);
171 /* check if there's a reconnection to the same host and maybe even
173 match = last_proto_match = NULL; count = 0;
174 for (tmp = reconnects; tmp != NULL; tmp = tmp->next) {
175 RECONNECT_REC *rec = tmp->data;
177 if (rec->conn->chat_type == chat_type) {
178 count++; last_proto_match = rec;
179 if (g_strcasecmp(rec->conn->address, addr) == 0) {
180 if (rec->conn->port == port)
188 /* only one reconnection with wanted protocol,
189 we probably want to use it */
190 return last_proto_match;
196 static void update_reconnection(SERVER_CONNECT_REC *conn, SERVER_REC *server)
198 SERVER_CONNECT_REC *oldconn;
199 RECONNECT_REC *recon;
201 if (server != NULL) {
202 oldconn = server->connrec;
203 server_connect_ref(oldconn);
204 reconnect_save_status(conn, server);
206 /* maybe we can reconnect some server from
207 reconnection queue */
208 recon = find_reconnect_server(conn->chat_type,
209 conn->address, conn->port);
210 if (recon == NULL) return;
212 oldconn = recon->conn;
213 server_connect_ref(oldconn);
214 server_reconnect_destroy(recon);
216 conn->away_reason = g_strdup(oldconn->away_reason);
217 conn->channels = g_strdup(oldconn->channels);
220 conn->reconnection = TRUE;
222 if (conn->chatnet == NULL && oldconn->chatnet != NULL)
223 conn->chatnet = g_strdup(oldconn->chatnet);
225 server_connect_unref(oldconn);
226 if (server != NULL) {
227 signal_emit("command disconnect", 2,
228 "* Changing server", server);
232 static void cmd_server(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
234 command_runsub("server", data, server, item);
237 static void sig_default_command_server(const char *data, SERVER_REC *server,
240 signal_emit("command server connect", 3, data, server, item);
243 /* SYNTAX: SERVER [-4 | -6] [-ssl] [-ssl_cert <cert>] [-ssl_pkey <pkey>]
244 [-ssl_verify] [-ssl_cafile <cafile>] [-ssl_capath <capath>]
245 [-!] [-noautosendcmd]
246 [-noproxy] [-network <network>] [-host <hostname>]
248 [+]<address>|<chatnet> [<port> [<password> [<nick>]]] */
249 /* NOTE: -network replaces the old -ircnet flag. */
250 static void cmd_server_connect(const char *data, SERVER_REC *server)
252 SERVER_CONNECT_REC *conn;
256 g_return_if_fail(data != NULL);
258 /* create connection record */
259 conn = get_server_connect(data, &plus_addr, &rawlog_file);
262 update_reconnection(conn, server);
263 server = server_connect(conn);
264 server_connect_unref(conn);
266 if (server != NULL && rawlog_file != NULL)
267 rawlog_open(server->rawlog, rawlog_file);
273 /* SYNTAX: DISCONNECT *|<tag> [<message>] */
274 static void cmd_disconnect(const char *data, SERVER_REC *server)
279 g_return_if_fail(data != NULL);
281 if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST, &tag, &msg))
284 if (*tag != '\0' && strcmp(tag, "*") != 0) {
285 server = server_find_tag(tag);
287 server = server_find_lookup_tag(tag);
289 if (server == NULL) cmd_param_error(CMDERR_NOT_CONNECTED);
291 if (*msg == '\0') msg = (char *) settings_get_str("quit_message");
292 signal_emit("server quit", 2, server, msg);
294 cmd_params_free(free_arg);
295 server_disconnect(server);
298 /* SYNTAX: QUIT [<message>] */
299 static void cmd_quit(const char *data)
305 g_return_if_fail(data != NULL);
307 quitmsg = *data != '\0' ? data :
308 settings_get_str("quit_message");
310 /* disconnect from every server */
311 for (tmp = servers; tmp != NULL; tmp = next) {
314 str = g_strdup_printf("* %s", quitmsg);
315 cmd_disconnect(str, tmp->data);
319 signal_emit("gui exit", 0);
322 /* SYNTAX: MSG [-<server tag>] [-channel | -nick] <targets> <message> */
323 static void cmd_msg(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
326 char *target, *origtarget, *msg;
328 int free_ret, target_type = SEND_TARGET_NICK;
330 g_return_if_fail(data != NULL);
332 if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS |
333 PARAM_FLAG_UNKNOWN_OPTIONS | PARAM_FLAG_GETREST,
334 "msg", &optlist, &target, &msg))
336 if (*target == '\0' || *msg == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
338 server = cmd_options_get_server("msg", optlist, server);
339 if (server == NULL || !server->connected)
340 cmd_param_error(CMDERR_NOT_CONNECTED);
344 if (strcmp(target, ",") == 0 || strcmp(target, ".") == 0) {
345 target = parse_special(&target, server, item,
346 NULL, &free_ret, NULL, 0);
347 if (target != NULL && *target == '\0') {
355 if (target != NULL) {
356 if (strcmp(target, "*") == 0) {
357 /* send to active channel/query */
359 cmd_param_error(CMDERR_NOT_JOINED);
361 target_type = IS_CHANNEL(item) ?
362 SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
363 target = (char *) window_item_get_target(item);
364 } else if (g_hash_table_lookup(optlist, "channel") != NULL)
365 target_type = SEND_TARGET_CHANNEL;
366 else if (g_hash_table_lookup(optlist, "nick") != NULL)
367 target_type = SEND_TARGET_NICK;
369 /* Need to rely on server_ischannel(). If the protocol
370 doesn't really know if it's channel or nick based on
371 the name, it should just assume it's nick, because
372 when typing text to channels it's always sent with
374 target_type = server_ischannel(server, target) ?
375 SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
378 if (target != NULL) {
379 signal_emit("server sendmsg", 4, server, target, msg,
380 GINT_TO_POINTER(target_type));
382 signal_emit(target != NULL && target_type == SEND_TARGET_CHANNEL ?
383 "message own_public" : "message own_private", 4,
384 server, msg, target, origtarget);
386 if (free_ret && target != NULL) g_free(target);
387 cmd_params_free(free_arg);
390 static void sig_server_sendmsg(SERVER_REC *server, const char *target,
391 const char *msg, void *target_type_p)
393 server->send_message(server, target, msg,
394 GPOINTER_TO_INT(target_type_p));
397 static void cmd_foreach(const char *data, SERVER_REC *server,
400 command_runsub("foreach", data, server, item);
403 /* SYNTAX: FOREACH SERVER <command> */
404 static void cmd_foreach_server(const char *data, SERVER_REC *server)
408 list = g_slist_copy(servers);
409 while (list != NULL) {
410 signal_emit("send command", 3, data, list->data, NULL);
411 list = g_slist_remove(list, list->data);
415 /* SYNTAX: FOREACH CHANNEL <command> */
416 static void cmd_foreach_channel(const char *data)
420 list = g_slist_copy(channels);
421 while (list != NULL) {
422 CHANNEL_REC *rec = list->data;
424 signal_emit("send command", 3, data, rec->server, rec);
425 list = g_slist_remove(list, list->data);
429 /* SYNTAX: FOREACH QUERY <command> */
430 static void cmd_foreach_query(const char *data)
434 list = g_slist_copy(queries);
435 while (list != NULL) {
436 QUERY_REC *rec = list->data;
438 signal_emit("send command", 3, data, rec->server, rec);
439 list = g_slist_remove(list, list->data);
443 void chat_commands_init(void)
445 settings_add_str("misc", "quit_message", "leaving");
447 command_bind("server", NULL, (SIGNAL_FUNC) cmd_server);
448 command_bind("server connect", NULL, (SIGNAL_FUNC) cmd_server_connect);
449 command_bind("connect", NULL, (SIGNAL_FUNC) cmd_connect);
450 command_bind("disconnect", NULL, (SIGNAL_FUNC) cmd_disconnect);
451 command_bind("quit", NULL, (SIGNAL_FUNC) cmd_quit);
452 command_bind("msg", NULL, (SIGNAL_FUNC) cmd_msg);
453 command_bind("foreach", NULL, (SIGNAL_FUNC) cmd_foreach);
454 command_bind("foreach server", NULL, (SIGNAL_FUNC) cmd_foreach_server);
455 command_bind("foreach channel", NULL, (SIGNAL_FUNC) cmd_foreach_channel);
456 command_bind("foreach query", NULL, (SIGNAL_FUNC) cmd_foreach_query);
458 signal_add("default command server", (SIGNAL_FUNC) sig_default_command_server);
459 signal_add("server sendmsg", (SIGNAL_FUNC) sig_server_sendmsg);
461 command_set_options("connect", "4 6 !! -network ssl +ssl_cert +ssl_pkey ssl_verify +ssl_cafile +ssl_capath +host noproxy -rawlog noautosendcmd");
462 command_set_options("msg", "channel nick");
465 void chat_commands_deinit(void)
467 command_unbind("server", (SIGNAL_FUNC) cmd_server);
468 command_unbind("server connect", (SIGNAL_FUNC) cmd_server_connect);
469 command_unbind("connect", (SIGNAL_FUNC) cmd_connect);
470 command_unbind("disconnect", (SIGNAL_FUNC) cmd_disconnect);
471 command_unbind("quit", (SIGNAL_FUNC) cmd_quit);
472 command_unbind("msg", (SIGNAL_FUNC) cmd_msg);
473 command_unbind("foreach", (SIGNAL_FUNC) cmd_foreach);
474 command_unbind("foreach server", (SIGNAL_FUNC) cmd_foreach_server);
475 command_unbind("foreach channel", (SIGNAL_FUNC) cmd_foreach_channel);
476 command_unbind("foreach query", (SIGNAL_FUNC) cmd_foreach_query);
478 signal_remove("default command server", (SIGNAL_FUNC) sig_default_command_server);
479 signal_remove("server sendmsg", (SIGNAL_FUNC) sig_server_sendmsg);