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 (g_hash_table_lookup(optlist, "6") != NULL)
84 conn->family = AF_INET6;
85 else if (g_hash_table_lookup(optlist, "4") != NULL)
86 conn->family = AF_INET;
88 if (g_hash_table_lookup(optlist, "!") != NULL)
89 conn->no_autojoin_channels = TRUE;
91 if (g_hash_table_lookup(optlist, "noproxy") != NULL)
92 g_free_and_null(conn->proxy);
94 *rawlog_file = g_strdup(g_hash_table_lookup(optlist, "rawlog"));
96 host = g_hash_table_lookup(optlist, "host");
97 if (host != NULL && *host != '\0') {
100 if (net_gethostbyname(host, &ip4, &ip6) == 0)
101 server_connect_own_ip_save(conn, &ip4, &ip6);
104 cmd_params_free(free_arg);
108 /* SYNTAX: CONNECT [-4 | -6] [-ircnet <ircnet>] [-host <hostname>]
109 <address>|<chatnet> [<port> [<password> [<nick>]]] */
110 static void cmd_connect(const char *data)
112 SERVER_CONNECT_REC *conn;
116 conn = get_server_connect(data, NULL, &rawlog_file);
118 server = CHAT_PROTOCOL(conn)->server_connect(conn);
119 server_connect_unref(conn);
121 if (server != NULL && rawlog_file != NULL)
122 rawlog_open(server->rawlog, rawlog_file);
128 static RECONNECT_REC *find_reconnect_server(int chat_type,
129 const char *addr, int port)
131 RECONNECT_REC *match, *last_proto_match;
135 g_return_val_if_fail(addr != NULL, NULL);
137 /* check if there's a reconnection to the same host and maybe even
139 match = last_proto_match = NULL; count = 0;
140 for (tmp = reconnects; tmp != NULL; tmp = tmp->next) {
141 RECONNECT_REC *rec = tmp->data;
143 if (rec->conn->chat_type == chat_type) {
144 count++; last_proto_match = rec;
145 if (g_strcasecmp(rec->conn->address, addr) == 0) {
146 if (rec->conn->port == port)
154 /* only one reconnection with wanted protocol,
155 we probably want to use it */
156 return last_proto_match;
162 static void update_reconnection(SERVER_CONNECT_REC *conn, SERVER_REC *server)
164 SERVER_CONNECT_REC *oldconn;
165 RECONNECT_REC *recon;
167 if (server != NULL) {
168 oldconn = server->connrec;
169 server_connect_ref(oldconn);
170 reconnect_save_status(conn, server);
172 /* maybe we can reconnect some server from
173 reconnection queue */
174 recon = find_reconnect_server(conn->chat_type,
175 conn->address, conn->port);
176 if (recon == NULL) return;
178 oldconn = recon->conn;
179 server_connect_ref(oldconn);
180 server_reconnect_destroy(recon);
182 conn->away_reason = g_strdup(oldconn->away_reason);
183 conn->channels = g_strdup(oldconn->channels);
186 conn->reconnection = TRUE;
188 if (conn->chatnet == NULL && oldconn->chatnet != NULL)
189 conn->chatnet = g_strdup(oldconn->chatnet);
191 server_connect_unref(oldconn);
192 if (server != NULL) {
193 signal_emit("command disconnect", 2,
194 "* Changing server", server);
198 static void cmd_server(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
200 command_runsub("server", data, server, item);
203 static void sig_default_command_server(const char *data, SERVER_REC *server,
206 signal_emit("command server connect", 3, data, server, item);
209 /* SYNTAX: SERVER [-4 | -6] [-ircnet <ircnet>] [-host <hostname>]
210 [+]<address>|<chatnet> [<port> [<password> [<nick>]]] */
211 static void cmd_server_connect(const char *data, SERVER_REC *server)
213 SERVER_CONNECT_REC *conn;
217 g_return_if_fail(data != NULL);
219 /* create connection record */
220 conn = get_server_connect(data, &plus_addr, &rawlog_file);
223 update_reconnection(conn, server);
224 server = CHAT_PROTOCOL(conn)->server_connect(conn);
225 server_connect_unref(conn);
227 if (server != NULL && rawlog_file != NULL)
228 rawlog_open(server->rawlog, rawlog_file);
234 /* SYNTAX: DISCONNECT *|<tag> [<message>] */
235 static void cmd_disconnect(const char *data, SERVER_REC *server)
240 g_return_if_fail(data != NULL);
242 if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST, &tag, &msg))
245 if (*tag != '\0' && strcmp(tag, "*") != 0)
246 server = server_find_tag(tag);
247 if (server == NULL) cmd_param_error(CMDERR_NOT_CONNECTED);
249 if (*msg == '\0') msg = (char *) settings_get_str("quit_message");
250 signal_emit("server quit", 2, server, msg);
252 cmd_params_free(free_arg);
253 server_disconnect(server);
256 /* SYNTAX: QUIT [<message>] */
257 static void cmd_quit(const char *data)
263 g_return_if_fail(data != NULL);
265 quitmsg = *data != '\0' ? data :
266 settings_get_str("quit_message");
268 /* disconnect from every server */
269 for (tmp = servers; tmp != NULL; tmp = next) {
272 str = g_strdup_printf("* %s", quitmsg);
273 cmd_disconnect(str, tmp->data);
277 signal_emit("gui exit", 0);
280 /* SYNTAX: JOIN [-invite] [-<server tag>] <channels> [<keys>] */
281 static void cmd_join(const char *data, SERVER_REC *server)
287 g_return_if_fail(data != NULL);
289 if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS |
290 PARAM_FLAG_UNKNOWN_OPTIONS | PARAM_FLAG_GETREST,
291 "join", &optlist, &channels))
295 server = cmd_options_get_server("join", optlist, server);
296 if (server == NULL || !server->connected)
297 cmd_param_error(CMDERR_NOT_CONNECTED);
299 if (g_hash_table_lookup(optlist, "invite"))
300 channels = server->last_invite;
302 if (*channels == '\0')
303 cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
306 if (channels != NULL)
307 server->channels_join(server, channels, FALSE);
308 cmd_params_free(free_arg);
311 /* SYNTAX: MSG [-<server tag>] [-channel | -nick] <targets> <message> */
312 static void cmd_msg(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
315 char *target, *origtarget, *msg;
317 int free_ret, target_type;
319 g_return_if_fail(data != NULL);
321 if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS |
322 PARAM_FLAG_UNKNOWN_OPTIONS | PARAM_FLAG_GETREST,
323 "msg", &optlist, &target, &msg))
325 if (*target == '\0' || *msg == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
327 server = cmd_options_get_server("msg", optlist, SERVER(server));
328 if (server == NULL || !server->connected)
329 cmd_param_error(CMDERR_NOT_CONNECTED);
333 if (strcmp(target, ",") == 0 || strcmp(target, ".") == 0) {
334 target = parse_special(&target, server, item,
335 NULL, &free_ret, NULL, 0);
336 if (target != NULL && *target == '\0')
340 if (strcmp(target, "*") == 0) {
341 /* send to active channel/query */
343 cmd_param_error(CMDERR_NOT_JOINED);
345 target_type = IS_CHANNEL(item) ?
346 SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
349 else if (g_hash_table_lookup(optlist, "channel") != NULL)
350 target_type = SEND_TARGET_CHANNEL;
351 else if (g_hash_table_lookup(optlist, "nick") != NULL)
352 target_type = SEND_TARGET_NICK;
354 /* Need to rely on server_ischannel(). If the protocol
355 doesn't really know if it's channel or nick based on the
356 name, it should just assume it's nick, because when typing
357 text to channels it's always sent with /MSG -channel. */
358 target_type = server_ischannel(server, target) ?
359 SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
363 server->send_message(server, target, msg, target_type);
365 signal_emit(target != NULL && target_type == SEND_TARGET_CHANNEL ?
366 "message own_public" : "message own_private", 4,
367 server, msg, target, origtarget);
369 if (free_ret && target != NULL) g_free(target);
370 cmd_params_free(free_arg);
373 static void cmd_foreach(const char *data, SERVER_REC *server,
376 command_runsub("foreach", data, server, item);
379 /* SYNTAX: FOREACH SERVER <command> */
380 static void cmd_foreach_server(const char *data, SERVER_REC *server)
384 list = g_slist_copy(servers);
385 while (list != NULL) {
386 signal_emit("send command", 3, data, list->data, NULL);
387 list = g_slist_remove(list, list->data);
391 /* SYNTAX: FOREACH CHANNEL <command> */
392 static void cmd_foreach_channel(const char *data)
396 list = g_slist_copy(channels);
397 while (list != NULL) {
398 CHANNEL_REC *rec = list->data;
400 signal_emit("send command", 3, data, rec->server, rec);
401 list = g_slist_remove(list, list->data);
405 /* SYNTAX: FOREACH QUERY <command> */
406 static void cmd_foreach_query(const char *data)
410 list = g_slist_copy(queries);
411 while (list != NULL) {
412 QUERY_REC *rec = list->data;
414 signal_emit("send command", 3, data, rec->server, rec);
415 list = g_slist_remove(list, list->data);
419 void chat_commands_init(void)
421 settings_add_str("misc", "quit_message", "leaving");
423 command_bind("server", NULL, (SIGNAL_FUNC) cmd_server);
424 command_bind("server connect", NULL, (SIGNAL_FUNC) cmd_server_connect);
425 command_bind("connect", NULL, (SIGNAL_FUNC) cmd_connect);
426 command_bind("disconnect", NULL, (SIGNAL_FUNC) cmd_disconnect);
427 command_bind("quit", NULL, (SIGNAL_FUNC) cmd_quit);
428 command_bind("join", NULL, (SIGNAL_FUNC) cmd_join);
429 command_bind("msg", NULL, (SIGNAL_FUNC) cmd_msg);
430 command_bind("foreach", NULL, (SIGNAL_FUNC) cmd_foreach);
431 command_bind("foreach server", NULL, (SIGNAL_FUNC) cmd_foreach_server);
432 command_bind("foreach channel", NULL, (SIGNAL_FUNC) cmd_foreach_channel);
433 command_bind("foreach query", NULL, (SIGNAL_FUNC) cmd_foreach_query);
435 signal_add("default command server", (SIGNAL_FUNC) sig_default_command_server);
437 command_set_options("connect", "4 6 !! +host noproxy -rawlog");
438 command_set_options("join", "invite");
439 command_set_options("msg", "channel nick");
442 void chat_commands_deinit(void)
444 command_unbind("server", (SIGNAL_FUNC) cmd_server);
445 command_unbind("server connect", (SIGNAL_FUNC) cmd_server_connect);
446 command_unbind("connect", (SIGNAL_FUNC) cmd_connect);
447 command_unbind("disconnect", (SIGNAL_FUNC) cmd_disconnect);
448 command_unbind("quit", (SIGNAL_FUNC) cmd_quit);
449 command_unbind("join", (SIGNAL_FUNC) cmd_join);
450 command_unbind("msg", (SIGNAL_FUNC) cmd_msg);
451 command_unbind("foreach", (SIGNAL_FUNC) cmd_foreach);
452 command_unbind("foreach server", (SIGNAL_FUNC) cmd_foreach_server);
453 command_unbind("foreach channel", (SIGNAL_FUNC) cmd_foreach_channel);
454 command_unbind("foreach query", (SIGNAL_FUNC) cmd_foreach_query);
456 signal_remove("default command server", (SIGNAL_FUNC) sig_default_command_server);