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"
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;
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);
70 conn = server_create_conn(proto != NULL ? proto->id : -1, addr,
71 atoi(portstr), chatnet, password, nick);
73 proto = chat_protocol_find_id(conn->chat_type);
75 if (proto->not_initialized) {
76 /* trying to use protocol that isn't yet initialized */
77 signal_emit("chat protocol unknown", 1, proto->name);
78 server_connect_unref(conn);
79 cmd_params_free(free_arg);
83 if (strchr(addr, '/') != NULL)
84 conn->unix_socket = TRUE;
86 if (g_hash_table_lookup(optlist, "6") != NULL)
87 conn->family = AF_INET6;
88 else if (g_hash_table_lookup(optlist, "4") != NULL)
89 conn->family = AF_INET;
91 if(g_hash_table_lookup(optlist, "ssl") != NULL)
94 if (g_hash_table_lookup(optlist, "!") != NULL)
95 conn->no_autojoin_channels = TRUE;
97 if (g_hash_table_lookup(optlist, "noproxy") != NULL)
98 g_free_and_null(conn->proxy);
101 *rawlog_file = g_strdup(g_hash_table_lookup(optlist, "rawlog"));
103 host = g_hash_table_lookup(optlist, "host");
104 if (host != NULL && *host != '\0') {
107 if (net_gethostbyname(host, &ip4, &ip6) == 0)
108 server_connect_own_ip_save(conn, &ip4, &ip6);
111 cmd_params_free(free_arg);
115 /* SYNTAX: CONNECT [-4 | -6] [-ssl] [-noproxy] [-silcnet <silcnet>]
116 [-host <hostname>] [-rawlog <file>]
117 <address>|<chatnet> [<port> [<password> [<nick>]]] */
118 static void cmd_connect(const char *data)
120 SERVER_CONNECT_REC *conn;
124 conn = get_server_connect(data, NULL, &rawlog_file);
126 server = server_connect(conn);
127 server_connect_unref(conn);
129 if (server != NULL && rawlog_file != NULL)
130 rawlog_open(server->rawlog, rawlog_file);
136 static RECONNECT_REC *find_reconnect_server(int chat_type,
137 const char *addr, int port)
139 RECONNECT_REC *match, *last_proto_match;
143 g_return_val_if_fail(addr != NULL, NULL);
145 /* check if there's a reconnection to the same host and maybe even
147 match = last_proto_match = NULL; count = 0;
148 for (tmp = reconnects; tmp != NULL; tmp = tmp->next) {
149 RECONNECT_REC *rec = tmp->data;
151 if (rec->conn->chat_type == chat_type) {
152 count++; last_proto_match = rec;
153 if (g_strcasecmp(rec->conn->address, addr) == 0) {
154 if (rec->conn->port == port)
162 /* only one reconnection with wanted protocol,
163 we probably want to use it */
164 return last_proto_match;
170 static void update_reconnection(SERVER_CONNECT_REC *conn, SERVER_REC *server)
172 SERVER_CONNECT_REC *oldconn;
173 RECONNECT_REC *recon;
175 if (server != NULL) {
176 oldconn = server->connrec;
177 server_connect_ref(oldconn);
178 reconnect_save_status(conn, server);
180 /* maybe we can reconnect some server from
181 reconnection queue */
182 recon = find_reconnect_server(conn->chat_type,
183 conn->address, conn->port);
184 if (recon == NULL) return;
186 oldconn = recon->conn;
187 server_connect_ref(oldconn);
188 server_reconnect_destroy(recon);
190 conn->away_reason = g_strdup(oldconn->away_reason);
191 conn->channels = g_strdup(oldconn->channels);
194 conn->reconnection = TRUE;
196 if (conn->chatnet == NULL && oldconn->chatnet != NULL)
197 conn->chatnet = g_strdup(oldconn->chatnet);
199 server_connect_unref(oldconn);
200 if (server != NULL) {
201 signal_emit("command disconnect", 2,
202 "* Changing server", server);
206 static void cmd_server(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
208 command_runsub("server", data, server, item);
211 static void sig_default_command_server(const char *data, SERVER_REC *server,
214 signal_emit("command server connect", 3, data, server, item);
217 /* SYNTAX: SERVER [-4 | -6] [-ssl] [-noproxy] [-silcnet <silcnet>]
218 [-host <hostname>] [-rawlog <file>]
219 [+]<address>|<chatnet> [<port> [<password> [<nick>]]] */
220 static void cmd_server_connect(const char *data, SERVER_REC *server)
222 SERVER_CONNECT_REC *conn;
226 g_return_if_fail(data != NULL);
228 /* create connection record */
229 conn = get_server_connect(data, &plus_addr, &rawlog_file);
232 update_reconnection(conn, server);
233 server = server_connect(conn);
234 server_connect_unref(conn);
236 if (server != NULL && rawlog_file != NULL)
237 rawlog_open(server->rawlog, rawlog_file);
243 /* SYNTAX: DISCONNECT *|<tag> [<message>] */
244 static void cmd_disconnect(const char *data, SERVER_REC *server)
249 g_return_if_fail(data != NULL);
251 if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST, &tag, &msg))
254 if (*tag != '\0' && strcmp(tag, "*") != 0) {
255 server = server_find_tag(tag);
257 server = server_find_lookup_tag(tag);
259 if (server == NULL) cmd_param_error(CMDERR_NOT_CONNECTED);
261 if (*msg == '\0') msg = (char *) settings_get_str("quit_message");
262 signal_emit("server quit", 2, server, msg);
264 cmd_params_free(free_arg);
265 server_disconnect(server);
268 /* SYNTAX: QUIT [<message>] */
269 static void cmd_quit(const char *data)
275 g_return_if_fail(data != NULL);
277 quitmsg = *data != '\0' ? data :
278 settings_get_str("quit_message");
280 /* disconnect from every server */
281 for (tmp = servers; tmp != NULL; tmp = next) {
284 str = g_strdup_printf("* %s", quitmsg);
285 cmd_disconnect(str, tmp->data);
289 signal_emit("gui exit", 0);
292 static void cmd_join(const char *data, SERVER_REC *server)
298 g_return_if_fail(data != NULL);
300 if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS |
301 PARAM_FLAG_UNKNOWN_OPTIONS | PARAM_FLAG_GETREST,
302 "join", &optlist, &channels))
306 server = cmd_options_get_server("join", optlist, server);
307 if (server == NULL || !server->connected)
308 cmd_param_error(CMDERR_NOT_CONNECTED);
310 if (g_hash_table_lookup(optlist, "invite"))
311 channels = server->last_invite;
313 if (*channels == '\0')
314 cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
317 if (channels != NULL)
318 server->channels_join(server, channels, FALSE);
319 cmd_params_free(free_arg);
322 /* SYNTAX: MSG [-channel] <target> <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;
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')
351 if (strcmp(target, "*") == 0) {
352 /* send to active channel/query */
354 cmd_param_error(CMDERR_NOT_JOINED);
356 target_type = IS_CHANNEL(item) ?
357 SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
358 target = (char *) window_item_get_target(item);
359 } else if (g_hash_table_lookup(optlist, "channel") != NULL)
360 target_type = SEND_TARGET_CHANNEL;
361 else if (g_hash_table_lookup(optlist, "nick") != NULL)
362 target_type = SEND_TARGET_NICK;
364 /* Need to rely on server_ischannel(). If the protocol
365 doesn't really know if it's channel or nick based on the
366 name, it should just assume it's nick, because when typing
367 text to channels it's always sent with /MSG -channel. */
368 target_type = server_ischannel(server, target) ?
369 SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
373 server->send_message(server, target, msg, target_type);
375 signal_emit(target != NULL && target_type == SEND_TARGET_CHANNEL ?
376 "message own_public" : "message own_private", 4,
377 server, msg, target, origtarget);
379 if (free_ret && target != NULL) g_free(target);
380 cmd_params_free(free_arg);
383 static void cmd_foreach(const char *data, SERVER_REC *server,
386 command_runsub("foreach", data, server, item);
389 /* SYNTAX: FOREACH SERVER <command> */
390 static void cmd_foreach_server(const char *data, SERVER_REC *server)
394 list = g_slist_copy(servers);
395 while (list != NULL) {
396 signal_emit("send command", 3, data, list->data, NULL);
397 list = g_slist_remove(list, list->data);
401 /* SYNTAX: FOREACH CHANNEL <command> */
402 static void cmd_foreach_channel(const char *data)
406 list = g_slist_copy(channels);
407 while (list != NULL) {
408 CHANNEL_REC *rec = list->data;
410 signal_emit("send command", 3, data, rec->server, rec);
411 list = g_slist_remove(list, list->data);
415 /* SYNTAX: FOREACH QUERY <command> */
416 static void cmd_foreach_query(const char *data)
420 list = g_slist_copy(queries);
421 while (list != NULL) {
422 QUERY_REC *rec = list->data;
424 signal_emit("send command", 3, data, rec->server, rec);
425 list = g_slist_remove(list, list->data);
429 void chat_commands_init(void)
431 settings_add_str("misc", "quit_message", "leaving");
433 command_bind("server", NULL, (SIGNAL_FUNC) cmd_server);
434 command_bind("server connect", NULL, (SIGNAL_FUNC) cmd_server_connect);
435 command_bind("connect", NULL, (SIGNAL_FUNC) cmd_connect);
436 command_bind("disconnect", NULL, (SIGNAL_FUNC) cmd_disconnect);
437 command_bind("quit", NULL, (SIGNAL_FUNC) cmd_quit);
438 command_bind("join", NULL, (SIGNAL_FUNC) cmd_join);
439 command_bind("msg", NULL, (SIGNAL_FUNC) cmd_msg);
440 command_bind("foreach", NULL, (SIGNAL_FUNC) cmd_foreach);
441 command_bind("foreach server", NULL, (SIGNAL_FUNC) cmd_foreach_server);
442 command_bind("foreach channel", NULL, (SIGNAL_FUNC) cmd_foreach_channel);
443 command_bind("foreach query", NULL, (SIGNAL_FUNC) cmd_foreach_query);
445 signal_add("default command server", (SIGNAL_FUNC) sig_default_command_server);
447 command_set_options("connect", "4 6 !! ssl +host noproxy -rawlog");
448 command_set_options("join", "invite");
449 command_set_options("msg", "channel nick");
452 void chat_commands_deinit(void)
454 command_unbind("server", (SIGNAL_FUNC) cmd_server);
455 command_unbind("server connect", (SIGNAL_FUNC) cmd_server_connect);
456 command_unbind("connect", (SIGNAL_FUNC) cmd_connect);
457 command_unbind("disconnect", (SIGNAL_FUNC) cmd_disconnect);
458 command_unbind("quit", (SIGNAL_FUNC) cmd_quit);
459 command_unbind("join", (SIGNAL_FUNC) cmd_join);
460 command_unbind("msg", (SIGNAL_FUNC) cmd_msg);
461 command_unbind("foreach", (SIGNAL_FUNC) cmd_foreach);
462 command_unbind("foreach server", (SIGNAL_FUNC) cmd_foreach_server);
463 command_unbind("foreach channel", (SIGNAL_FUNC) cmd_foreach_channel);
464 command_unbind("foreach query", (SIGNAL_FUNC) cmd_foreach_query);
466 signal_remove("default command server", (SIGNAL_FUNC) sig_default_command_server);