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
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "special-vars.h"
29 #include "chat-protocols.h"
31 #include "servers-setup.h"
32 #include "servers-reconnect.h"
35 #include "window-item-def.h"
38 static SERVER_CONNECT_REC *get_server_connect(const char *data, int *plus_addr,
41 CHAT_PROTOCOL_REC *proto;
42 SERVER_CONNECT_REC *conn;
44 char *addr, *portstr, *password, *nick, *chatnet, *host, *tmp;
47 g_return_val_if_fail(data != NULL, NULL);
49 if (!cmd_get_params(data, &free_arg, 4 | PARAM_FLAG_OPTIONS,
50 "connect", &optlist, &addr, &portstr,
53 if (plus_addr != NULL) *plus_addr = *addr == '+';
54 if (*addr == '+') addr++;
56 signal_emit("error command", 1,
57 GINT_TO_POINTER(CMDERR_NOT_ENOUGH_PARAMS));
58 cmd_params_free(free_arg);
62 if (strcmp(password, "-") == 0)
65 /* check if -<chatnet> option is used to specify chat protocol */
66 proto = chat_protocol_find_net(optlist);
68 /* connect to server */
69 chatnet = proto == NULL ? NULL :
70 g_hash_table_lookup(optlist, proto->chatnet);
73 chatnet = g_hash_table_lookup(optlist, "network");
75 conn = server_create_conn(proto != NULL ? proto->id : -1, addr,
76 atoi(portstr), chatnet, password, nick);
78 proto = chat_protocol_find_id(conn->chat_type);
80 if (proto->not_initialized) {
81 /* trying to use protocol that isn't yet initialized */
82 signal_emit("chat protocol unknown", 1, proto->name);
83 server_connect_unref(conn);
84 cmd_params_free(free_arg);
88 if (strchr(addr, '/') != NULL)
89 conn->unix_socket = TRUE;
91 if (g_hash_table_lookup(optlist, "6") != NULL)
92 conn->family = AF_INET6;
93 else if (g_hash_table_lookup(optlist, "4") != NULL)
94 conn->family = AF_INET;
96 if (g_hash_table_lookup(optlist, "ssl") != NULL)
98 if ((tmp = g_hash_table_lookup(optlist, "ssl_cert")) != NULL)
99 conn->ssl_cert = g_strdup(tmp);
100 if ((tmp = g_hash_table_lookup(optlist, "ssl_pkey")) != NULL)
101 conn->ssl_pkey = g_strdup(tmp);
102 if (g_hash_table_lookup(optlist, "ssl_verify") != NULL)
103 conn->ssl_verify = TRUE;
104 if ((tmp = g_hash_table_lookup(optlist, "ssl_cafile")) != NULL)
105 conn->ssl_cafile = g_strdup(tmp);
106 if ((tmp = g_hash_table_lookup(optlist, "ssl_capath")) != NULL)
107 conn->ssl_capath = g_strdup(tmp);
108 if ((conn->ssl_capath != NULL && conn->ssl_capath[0] != '\0')
109 || (conn->ssl_cafile != NULL && conn->ssl_cafile[0] != '\0'))
110 conn->ssl_verify = TRUE;
111 if ((conn->ssl_cert != NULL && conn->ssl_cert[0] != '\0') || conn->ssl_verify)
112 conn->use_ssl = TRUE;
114 if (g_hash_table_lookup(optlist, "!") != NULL)
115 conn->no_autojoin_channels = TRUE;
117 if (g_hash_table_lookup(optlist, "noproxy") != NULL)
118 g_free_and_null(conn->proxy);
121 *rawlog_file = g_strdup(g_hash_table_lookup(optlist, "rawlog"));
123 host = g_hash_table_lookup(optlist, "host");
124 if (host != NULL && *host != '\0') {
127 if (net_gethostbyname(host, &ip4, &ip6) == 0)
128 server_connect_own_ip_save(conn, &ip4, &ip6);
131 cmd_params_free(free_arg);
135 /* SYNTAX: CONNECT [-4 | -6] [-ssl] [-ssl_cert <cert>] [-ssl_pkey <pkey>]
136 [-ssl_verify] [-ssl_cafile <cafile>] [-ssl_capath <capath>]
137 [-noproxy] [-network <network>] [-host <hostname>]
139 <address>|<chatnet> [<port> [<password> [<nick>]]] */
140 /* NOTE: -network replaces the old -ircnet flag. */
141 static void cmd_connect(const char *data)
143 SERVER_CONNECT_REC *conn;
147 conn = get_server_connect(data, NULL, &rawlog_file);
149 server = server_connect(conn);
150 server_connect_unref(conn);
152 if (server != NULL && rawlog_file != NULL)
153 rawlog_open(server->rawlog, rawlog_file);
159 static RECONNECT_REC *find_reconnect_server(int chat_type,
160 const char *addr, int port)
162 RECONNECT_REC *match, *last_proto_match;
166 g_return_val_if_fail(addr != NULL, NULL);
168 /* check if there's a reconnection to the same host and maybe even
170 match = last_proto_match = NULL; count = 0;
171 for (tmp = reconnects; tmp != NULL; tmp = tmp->next) {
172 RECONNECT_REC *rec = tmp->data;
174 if (rec->conn->chat_type == chat_type) {
175 count++; last_proto_match = rec;
176 if (g_strcasecmp(rec->conn->address, addr) == 0) {
177 if (rec->conn->port == port)
185 /* only one reconnection with wanted protocol,
186 we probably want to use it */
187 return last_proto_match;
193 static void update_reconnection(SERVER_CONNECT_REC *conn, SERVER_REC *server)
195 SERVER_CONNECT_REC *oldconn;
196 RECONNECT_REC *recon;
198 if (server != NULL) {
199 oldconn = server->connrec;
200 server_connect_ref(oldconn);
201 reconnect_save_status(conn, server);
203 /* maybe we can reconnect some server from
204 reconnection queue */
205 recon = find_reconnect_server(conn->chat_type,
206 conn->address, conn->port);
207 if (recon == NULL) return;
209 oldconn = recon->conn;
210 server_connect_ref(oldconn);
211 server_reconnect_destroy(recon);
213 conn->away_reason = g_strdup(oldconn->away_reason);
214 conn->channels = g_strdup(oldconn->channels);
217 conn->reconnection = TRUE;
219 if (conn->chatnet == NULL && oldconn->chatnet != NULL)
220 conn->chatnet = g_strdup(oldconn->chatnet);
222 server_connect_unref(oldconn);
223 if (server != NULL) {
224 signal_emit("command disconnect", 2,
225 "* Changing server", server);
229 static void cmd_server(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
231 command_runsub("server", data, server, item);
234 static void sig_default_command_server(const char *data, SERVER_REC *server,
237 signal_emit("command server connect", 3, data, server, item);
240 /* SYNTAX: SERVER [-4 | -6] [-ssl] [-ssl_cert <cert>] [-ssl_pkey <pkey>]
241 [-ssl_verify] [-ssl_cafile <cafile>] [-ssl_capath <capath>]
242 [-noproxy] [-network <network>] [-host <hostname>]
244 [+]<address>|<chatnet> [<port> [<password> [<nick>]]] */
245 /* NOTE: -network replaces the old -ircnet flag. */
246 static void cmd_server_connect(const char *data, SERVER_REC *server)
248 SERVER_CONNECT_REC *conn;
252 g_return_if_fail(data != NULL);
254 /* create connection record */
255 conn = get_server_connect(data, &plus_addr, &rawlog_file);
258 update_reconnection(conn, server);
259 server = server_connect(conn);
260 server_connect_unref(conn);
262 if (server != NULL && rawlog_file != NULL)
263 rawlog_open(server->rawlog, rawlog_file);
269 /* SYNTAX: DISCONNECT *|<tag> [<message>] */
270 static void cmd_disconnect(const char *data, SERVER_REC *server)
275 g_return_if_fail(data != NULL);
277 if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST, &tag, &msg))
280 if (*tag != '\0' && strcmp(tag, "*") != 0) {
281 server = server_find_tag(tag);
283 server = server_find_lookup_tag(tag);
285 if (server == NULL) cmd_param_error(CMDERR_NOT_CONNECTED);
287 if (*msg == '\0') msg = (char *) settings_get_str("quit_message");
288 signal_emit("server quit", 2, server, msg);
290 cmd_params_free(free_arg);
291 server_disconnect(server);
294 /* SYNTAX: QUIT [<message>] */
295 static void cmd_quit(const char *data)
301 g_return_if_fail(data != NULL);
303 quitmsg = *data != '\0' ? data :
304 settings_get_str("quit_message");
306 /* disconnect from every server */
307 for (tmp = servers; tmp != NULL; tmp = next) {
310 str = g_strdup_printf("* %s", quitmsg);
311 cmd_disconnect(str, tmp->data);
315 signal_emit("gui exit", 0);
318 /* SYNTAX: JOIN [-invite] [-<server tag>] <channels> [<keys>] */
319 static void cmd_join(const char *data, SERVER_REC *server)
325 g_return_if_fail(data != NULL);
327 if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS |
328 PARAM_FLAG_UNKNOWN_OPTIONS | PARAM_FLAG_GETREST,
329 "join", &optlist, &channels))
333 server = cmd_options_get_server("join", optlist, server);
334 if (server == NULL || !server->connected)
335 cmd_param_error(CMDERR_NOT_CONNECTED);
337 if (g_hash_table_lookup(optlist, "invite"))
338 channels = server->last_invite;
340 if (*channels == '\0')
341 cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
344 if (channels != NULL)
345 server->channels_join(server, channels, FALSE);
346 cmd_params_free(free_arg);
349 /* SYNTAX: MSG [-<server tag>] [-channel | -nick] <targets> <message> */
350 static void cmd_msg(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
353 char *target, *origtarget, *msg, *recoded;
355 int free_ret, target_type = SEND_TARGET_NICK;
357 g_return_if_fail(data != NULL);
359 if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS |
360 PARAM_FLAG_UNKNOWN_OPTIONS | PARAM_FLAG_GETREST,
361 "msg", &optlist, &target, &msg))
363 if (*target == '\0' || *msg == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
365 server = cmd_options_get_server("msg", optlist, server);
366 if (server == NULL || !server->connected)
367 cmd_param_error(CMDERR_NOT_CONNECTED);
371 if (strcmp(target, ",") == 0 || strcmp(target, ".") == 0) {
372 target = parse_special(&target, server, item,
373 NULL, &free_ret, NULL, 0);
374 if (target != NULL && *target == '\0') {
382 if (target != NULL) {
383 if (strcmp(target, "*") == 0) {
384 /* send to active channel/query */
386 cmd_param_error(CMDERR_NOT_JOINED);
388 target_type = IS_CHANNEL(item) ?
389 SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
390 target = (char *) window_item_get_target(item);
391 } else if (g_hash_table_lookup(optlist, "channel") != NULL)
392 target_type = SEND_TARGET_CHANNEL;
393 else if (g_hash_table_lookup(optlist, "nick") != NULL)
394 target_type = SEND_TARGET_NICK;
396 /* Need to rely on server_ischannel(). If the protocol
397 doesn't really know if it's channel or nick based on
398 the name, it should just assume it's nick, because
399 when typing text to channels it's always sent with
401 target_type = server_ischannel(server, target) ?
402 SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
405 recoded = recode_out(server, msg, target);
406 if (target != NULL) {
407 signal_emit("server sendmsg", 4, server, target, recoded,
408 GINT_TO_POINTER(target_type));
410 signal_emit(target != NULL && target_type == SEND_TARGET_CHANNEL ?
411 "message own_public" : "message own_private", 4,
412 server, recoded, target, origtarget);
415 if (free_ret && target != NULL) g_free(target);
416 cmd_params_free(free_arg);
419 static void sig_server_sendmsg(SERVER_REC *server, const char *target,
420 const char *msg, void *target_type_p)
422 server->send_message(server, target, msg,
423 GPOINTER_TO_INT(target_type_p));
426 static void cmd_foreach(const char *data, SERVER_REC *server,
429 command_runsub("foreach", data, server, item);
432 /* SYNTAX: FOREACH SERVER <command> */
433 static void cmd_foreach_server(const char *data, SERVER_REC *server)
437 list = g_slist_copy(servers);
438 while (list != NULL) {
439 signal_emit("send command", 3, data, list->data, NULL);
440 list = g_slist_remove(list, list->data);
444 /* SYNTAX: FOREACH CHANNEL <command> */
445 static void cmd_foreach_channel(const char *data)
449 list = g_slist_copy(channels);
450 while (list != NULL) {
451 CHANNEL_REC *rec = list->data;
453 signal_emit("send command", 3, data, rec->server, rec);
454 list = g_slist_remove(list, list->data);
458 /* SYNTAX: FOREACH QUERY <command> */
459 static void cmd_foreach_query(const char *data)
463 list = g_slist_copy(queries);
464 while (list != NULL) {
465 QUERY_REC *rec = list->data;
467 signal_emit("send command", 3, data, rec->server, rec);
468 list = g_slist_remove(list, list->data);
472 void chat_commands_init(void)
474 settings_add_str("misc", "quit_message", "leaving");
476 command_bind("server", NULL, (SIGNAL_FUNC) cmd_server);
477 command_bind("server connect", NULL, (SIGNAL_FUNC) cmd_server_connect);
478 command_bind("connect", NULL, (SIGNAL_FUNC) cmd_connect);
479 command_bind("disconnect", NULL, (SIGNAL_FUNC) cmd_disconnect);
480 command_bind("quit", NULL, (SIGNAL_FUNC) cmd_quit);
481 command_bind("join", NULL, (SIGNAL_FUNC) cmd_join);
482 command_bind("msg", NULL, (SIGNAL_FUNC) cmd_msg);
483 command_bind("foreach", NULL, (SIGNAL_FUNC) cmd_foreach);
484 command_bind("foreach server", NULL, (SIGNAL_FUNC) cmd_foreach_server);
485 command_bind("foreach channel", NULL, (SIGNAL_FUNC) cmd_foreach_channel);
486 command_bind("foreach query", NULL, (SIGNAL_FUNC) cmd_foreach_query);
488 signal_add("default command server", (SIGNAL_FUNC) sig_default_command_server);
489 signal_add("server sendmsg", (SIGNAL_FUNC) sig_server_sendmsg);
491 command_set_options("connect", "4 6 !! -network ssl +ssl_cert +ssl_pkey ssl_verify +ssl_cafile +ssl_capath +host noproxy -rawlog");
492 command_set_options("join", "invite");
493 command_set_options("msg", "channel nick");
496 void chat_commands_deinit(void)
498 command_unbind("server", (SIGNAL_FUNC) cmd_server);
499 command_unbind("server connect", (SIGNAL_FUNC) cmd_server_connect);
500 command_unbind("connect", (SIGNAL_FUNC) cmd_connect);
501 command_unbind("disconnect", (SIGNAL_FUNC) cmd_disconnect);
502 command_unbind("quit", (SIGNAL_FUNC) cmd_quit);
503 command_unbind("join", (SIGNAL_FUNC) cmd_join);
504 command_unbind("msg", (SIGNAL_FUNC) cmd_msg);
505 command_unbind("foreach", (SIGNAL_FUNC) cmd_foreach);
506 command_unbind("foreach server", (SIGNAL_FUNC) cmd_foreach_server);
507 command_unbind("foreach channel", (SIGNAL_FUNC) cmd_foreach_channel);
508 command_unbind("foreach query", (SIGNAL_FUNC) cmd_foreach_query);
510 signal_remove("default command server", (SIGNAL_FUNC) sig_default_command_server);
511 signal_remove("server sendmsg", (SIGNAL_FUNC) sig_server_sendmsg);