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] [-ircnet <ircnet>]
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] [-ircnet <ircnet>]
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 /* SYNTAX: JOIN [-invite] [-<server tag>] <channels> [<keys>] */
293 static void cmd_join(const char *data, SERVER_REC *server)
299 g_return_if_fail(data != NULL);
301 if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS |
302 PARAM_FLAG_UNKNOWN_OPTIONS | PARAM_FLAG_GETREST,
303 "join", &optlist, &channels))
307 server = cmd_options_get_server("join", optlist, server);
308 if (server == NULL || !server->connected)
309 cmd_param_error(CMDERR_NOT_CONNECTED);
311 if (g_hash_table_lookup(optlist, "invite"))
312 channels = server->last_invite;
314 if (*channels == '\0')
315 cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
318 if (channels != NULL)
319 server->channels_join(server, channels, FALSE);
320 cmd_params_free(free_arg);
323 /* SYNTAX: MSG [-<server tag>] [-channel | -nick] <targets> <message> */
324 static void cmd_msg(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
327 char *target, *origtarget, *msg;
329 int free_ret, target_type;
331 g_return_if_fail(data != NULL);
333 if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS |
334 PARAM_FLAG_UNKNOWN_OPTIONS | PARAM_FLAG_GETREST,
335 "msg", &optlist, &target, &msg))
337 if (*target == '\0' || *msg == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
339 server = cmd_options_get_server("msg", optlist, server);
340 if (server == NULL || !server->connected)
341 cmd_param_error(CMDERR_NOT_CONNECTED);
345 if (strcmp(target, ",") == 0 || strcmp(target, ".") == 0) {
346 target = parse_special(&target, server, item,
347 NULL, &free_ret, NULL, 0);
348 if (target != NULL && *target == '\0')
352 if (strcmp(target, "*") == 0) {
353 /* send to active channel/query */
355 cmd_param_error(CMDERR_NOT_JOINED);
357 target_type = IS_CHANNEL(item) ?
358 SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
359 target = (char *) window_item_get_target(item);
360 } else if (g_hash_table_lookup(optlist, "channel") != NULL)
361 target_type = SEND_TARGET_CHANNEL;
362 else if (g_hash_table_lookup(optlist, "nick") != NULL)
363 target_type = SEND_TARGET_NICK;
365 /* Need to rely on server_ischannel(). If the protocol
366 doesn't really know if it's channel or nick based on the
367 name, it should just assume it's nick, because when typing
368 text to channels it's always sent with /MSG -channel. */
369 target_type = server_ischannel(server, target) ?
370 SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
374 server->send_message(server, target, msg, target_type);
376 signal_emit(target != NULL && target_type == SEND_TARGET_CHANNEL ?
377 "message own_public" : "message own_private", 4,
378 server, msg, target, origtarget);
380 if (free_ret && target != NULL) g_free(target);
381 cmd_params_free(free_arg);
384 static void cmd_foreach(const char *data, SERVER_REC *server,
387 command_runsub("foreach", data, server, item);
390 /* SYNTAX: FOREACH SERVER <command> */
391 static void cmd_foreach_server(const char *data, SERVER_REC *server)
395 list = g_slist_copy(servers);
396 while (list != NULL) {
397 signal_emit("send command", 3, data, list->data, NULL);
398 list = g_slist_remove(list, list->data);
402 /* SYNTAX: FOREACH CHANNEL <command> */
403 static void cmd_foreach_channel(const char *data)
407 list = g_slist_copy(channels);
408 while (list != NULL) {
409 CHANNEL_REC *rec = list->data;
411 signal_emit("send command", 3, data, rec->server, rec);
412 list = g_slist_remove(list, list->data);
416 /* SYNTAX: FOREACH QUERY <command> */
417 static void cmd_foreach_query(const char *data)
421 list = g_slist_copy(queries);
422 while (list != NULL) {
423 QUERY_REC *rec = list->data;
425 signal_emit("send command", 3, data, rec->server, rec);
426 list = g_slist_remove(list, list->data);
430 void chat_commands_init(void)
432 settings_add_str("misc", "quit_message", "leaving");
434 command_bind("server", NULL, (SIGNAL_FUNC) cmd_server);
435 command_bind("server connect", NULL, (SIGNAL_FUNC) cmd_server_connect);
436 command_bind("connect", NULL, (SIGNAL_FUNC) cmd_connect);
437 command_bind("disconnect", NULL, (SIGNAL_FUNC) cmd_disconnect);
438 command_bind("quit", NULL, (SIGNAL_FUNC) cmd_quit);
439 command_bind("join", NULL, (SIGNAL_FUNC) cmd_join);
440 command_bind("msg", NULL, (SIGNAL_FUNC) cmd_msg);
441 command_bind("foreach", NULL, (SIGNAL_FUNC) cmd_foreach);
442 command_bind("foreach server", NULL, (SIGNAL_FUNC) cmd_foreach_server);
443 command_bind("foreach channel", NULL, (SIGNAL_FUNC) cmd_foreach_channel);
444 command_bind("foreach query", NULL, (SIGNAL_FUNC) cmd_foreach_query);
446 signal_add("default command server", (SIGNAL_FUNC) sig_default_command_server);
448 command_set_options("connect", "4 6 !! ssl +host noproxy -rawlog");
449 command_set_options("join", "invite");
450 command_set_options("msg", "channel nick");
453 void chat_commands_deinit(void)
455 command_unbind("server", (SIGNAL_FUNC) cmd_server);
456 command_unbind("server connect", (SIGNAL_FUNC) cmd_server_connect);
457 command_unbind("connect", (SIGNAL_FUNC) cmd_connect);
458 command_unbind("disconnect", (SIGNAL_FUNC) cmd_disconnect);
459 command_unbind("quit", (SIGNAL_FUNC) cmd_quit);
460 command_unbind("join", (SIGNAL_FUNC) cmd_join);
461 command_unbind("msg", (SIGNAL_FUNC) cmd_msg);
462 command_unbind("foreach", (SIGNAL_FUNC) cmd_foreach);
463 command_unbind("foreach server", (SIGNAL_FUNC) cmd_foreach_server);
464 command_unbind("foreach channel", (SIGNAL_FUNC) cmd_foreach_channel);
465 command_unbind("foreach query", (SIGNAL_FUNC) cmd_foreach_query);
467 signal_remove("default command server", (SIGNAL_FUNC) sig_default_command_server);