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] [-ircnet <ircnet>] [-host <hostname>]
116 <address>|<chatnet> [<port> [<password> [<nick>]]] */
117 static void cmd_connect(const char *data)
119 SERVER_CONNECT_REC *conn;
123 conn = get_server_connect(data, NULL, &rawlog_file);
125 server = server_connect(conn);
126 server_connect_unref(conn);
128 if (server != NULL && rawlog_file != NULL)
129 rawlog_open(server->rawlog, rawlog_file);
135 static RECONNECT_REC *find_reconnect_server(int chat_type,
136 const char *addr, int port)
138 RECONNECT_REC *match, *last_proto_match;
142 g_return_val_if_fail(addr != NULL, NULL);
144 /* check if there's a reconnection to the same host and maybe even
146 match = last_proto_match = NULL; count = 0;
147 for (tmp = reconnects; tmp != NULL; tmp = tmp->next) {
148 RECONNECT_REC *rec = tmp->data;
150 if (rec->conn->chat_type == chat_type) {
151 count++; last_proto_match = rec;
152 if (g_strcasecmp(rec->conn->address, addr) == 0) {
153 if (rec->conn->port == port)
161 /* only one reconnection with wanted protocol,
162 we probably want to use it */
163 return last_proto_match;
169 static void update_reconnection(SERVER_CONNECT_REC *conn, SERVER_REC *server)
171 SERVER_CONNECT_REC *oldconn;
172 RECONNECT_REC *recon;
174 if (server != NULL) {
175 oldconn = server->connrec;
176 server_connect_ref(oldconn);
177 reconnect_save_status(conn, server);
179 /* maybe we can reconnect some server from
180 reconnection queue */
181 recon = find_reconnect_server(conn->chat_type,
182 conn->address, conn->port);
183 if (recon == NULL) return;
185 oldconn = recon->conn;
186 server_connect_ref(oldconn);
187 server_reconnect_destroy(recon);
189 conn->away_reason = g_strdup(oldconn->away_reason);
190 conn->channels = g_strdup(oldconn->channels);
193 conn->reconnection = TRUE;
195 if (conn->chatnet == NULL && oldconn->chatnet != NULL)
196 conn->chatnet = g_strdup(oldconn->chatnet);
198 server_connect_unref(oldconn);
199 if (server != NULL) {
200 signal_emit("command disconnect", 2,
201 "* Changing server", server);
205 static void cmd_server(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
207 command_runsub("server", data, server, item);
210 static void sig_default_command_server(const char *data, SERVER_REC *server,
213 signal_emit("command server connect", 3, data, server, item);
216 /* SYNTAX: SERVER [-4 | -6] [-ssl] [-ircnet <ircnet>] [-host <hostname>]
217 [+]<address>|<chatnet> [<port> [<password> [<nick>]]] */
218 static void cmd_server_connect(const char *data, SERVER_REC *server)
220 SERVER_CONNECT_REC *conn;
224 g_return_if_fail(data != NULL);
226 /* create connection record */
227 conn = get_server_connect(data, &plus_addr, &rawlog_file);
230 update_reconnection(conn, server);
231 server = server_connect(conn);
232 server_connect_unref(conn);
234 if (server != NULL && rawlog_file != NULL)
235 rawlog_open(server->rawlog, rawlog_file);
241 /* SYNTAX: DISCONNECT *|<tag> [<message>] */
242 static void cmd_disconnect(const char *data, SERVER_REC *server)
247 g_return_if_fail(data != NULL);
249 if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST, &tag, &msg))
252 if (*tag != '\0' && strcmp(tag, "*") != 0) {
253 server = server_find_tag(tag);
255 server = server_find_lookup_tag(tag);
257 if (server == NULL) cmd_param_error(CMDERR_NOT_CONNECTED);
259 if (*msg == '\0') msg = (char *) settings_get_str("quit_message");
260 signal_emit("server quit", 2, server, msg);
262 cmd_params_free(free_arg);
263 server_disconnect(server);
266 /* SYNTAX: QUIT [<message>] */
267 static void cmd_quit(const char *data)
273 g_return_if_fail(data != NULL);
275 quitmsg = *data != '\0' ? data :
276 settings_get_str("quit_message");
278 /* disconnect from every server */
279 for (tmp = servers; tmp != NULL; tmp = next) {
282 str = g_strdup_printf("* %s", quitmsg);
283 cmd_disconnect(str, tmp->data);
287 signal_emit("gui exit", 0);
290 /* SYNTAX: JOIN [-invite] [-<server tag>] <channels> [<keys>] */
291 static void cmd_join(const char *data, SERVER_REC *server)
297 g_return_if_fail(data != NULL);
299 if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS |
300 PARAM_FLAG_UNKNOWN_OPTIONS | PARAM_FLAG_GETREST,
301 "join", &optlist, &channels))
305 server = cmd_options_get_server("join", optlist, server);
306 if (server == NULL || !server->connected)
307 cmd_param_error(CMDERR_NOT_CONNECTED);
309 if (g_hash_table_lookup(optlist, "invite"))
310 channels = server->last_invite;
312 if (*channels == '\0')
313 cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
316 if (channels != NULL)
317 server->channels_join(server, channels, FALSE);
318 cmd_params_free(free_arg);
321 /* SYNTAX: MSG [-<server tag>] [-channel | -nick] <targets> <message> */
322 static void cmd_msg(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
325 char *target, *origtarget, *msg;
327 int free_ret, target_type;
329 g_return_if_fail(data != NULL);
331 if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS |
332 PARAM_FLAG_UNKNOWN_OPTIONS | PARAM_FLAG_GETREST,
333 "msg", &optlist, &target, &msg))
335 if (*target == '\0' || *msg == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
337 server = cmd_options_get_server("msg", optlist, server);
338 if (server == NULL || !server->connected)
339 cmd_param_error(CMDERR_NOT_CONNECTED);
343 if (strcmp(target, ",") == 0 || strcmp(target, ".") == 0) {
344 target = parse_special(&target, server, item,
345 NULL, &free_ret, NULL, 0);
346 if (target != NULL && *target == '\0')
350 if (strcmp(target, "*") == 0) {
351 /* send to active channel/query */
353 cmd_param_error(CMDERR_NOT_JOINED);
355 target_type = IS_CHANNEL(item) ?
356 SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
357 target = (char *) window_item_get_target(item);
358 } else if (g_hash_table_lookup(optlist, "channel") != NULL)
359 target_type = SEND_TARGET_CHANNEL;
360 else if (g_hash_table_lookup(optlist, "nick") != NULL)
361 target_type = SEND_TARGET_NICK;
363 /* Need to rely on server_ischannel(). If the protocol
364 doesn't really know if it's channel or nick based on the
365 name, it should just assume it's nick, because when typing
366 text to channels it's always sent with /MSG -channel. */
367 target_type = server_ischannel(server, target) ?
368 SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
372 server->send_message(server, target, msg, target_type);
374 signal_emit(target != NULL && target_type == SEND_TARGET_CHANNEL ?
375 "message own_public" : "message own_private", 4,
376 server, msg, target, origtarget);
378 if (free_ret && target != NULL) g_free(target);
379 cmd_params_free(free_arg);
382 static void cmd_foreach(const char *data, SERVER_REC *server,
385 command_runsub("foreach", data, server, item);
388 /* SYNTAX: FOREACH SERVER <command> */
389 static void cmd_foreach_server(const char *data, SERVER_REC *server)
393 list = g_slist_copy(servers);
394 while (list != NULL) {
395 signal_emit("send command", 3, data, list->data, NULL);
396 list = g_slist_remove(list, list->data);
400 /* SYNTAX: FOREACH CHANNEL <command> */
401 static void cmd_foreach_channel(const char *data)
405 list = g_slist_copy(channels);
406 while (list != NULL) {
407 CHANNEL_REC *rec = list->data;
409 signal_emit("send command", 3, data, rec->server, rec);
410 list = g_slist_remove(list, list->data);
414 /* SYNTAX: FOREACH QUERY <command> */
415 static void cmd_foreach_query(const char *data)
419 list = g_slist_copy(queries);
420 while (list != NULL) {
421 QUERY_REC *rec = list->data;
423 signal_emit("send command", 3, data, rec->server, rec);
424 list = g_slist_remove(list, list->data);
428 void chat_commands_init(void)
430 settings_add_str("misc", "quit_message", "leaving");
432 command_bind("server", NULL, (SIGNAL_FUNC) cmd_server);
433 command_bind("server connect", NULL, (SIGNAL_FUNC) cmd_server_connect);
434 command_bind("connect", NULL, (SIGNAL_FUNC) cmd_connect);
435 command_bind("disconnect", NULL, (SIGNAL_FUNC) cmd_disconnect);
436 command_bind("quit", NULL, (SIGNAL_FUNC) cmd_quit);
437 command_bind("join", NULL, (SIGNAL_FUNC) cmd_join);
438 command_bind("msg", NULL, (SIGNAL_FUNC) cmd_msg);
439 command_bind("foreach", NULL, (SIGNAL_FUNC) cmd_foreach);
440 command_bind("foreach server", NULL, (SIGNAL_FUNC) cmd_foreach_server);
441 command_bind("foreach channel", NULL, (SIGNAL_FUNC) cmd_foreach_channel);
442 command_bind("foreach query", NULL, (SIGNAL_FUNC) cmd_foreach_query);
444 signal_add("default command server", (SIGNAL_FUNC) sig_default_command_server);
446 command_set_options("connect", "4 6 !! ssl +host noproxy -rawlog");
447 command_set_options("join", "invite");
448 command_set_options("msg", "channel nick");
451 void chat_commands_deinit(void)
453 command_unbind("server", (SIGNAL_FUNC) cmd_server);
454 command_unbind("server connect", (SIGNAL_FUNC) cmd_server_connect);
455 command_unbind("connect", (SIGNAL_FUNC) cmd_connect);
456 command_unbind("disconnect", (SIGNAL_FUNC) cmd_disconnect);
457 command_unbind("quit", (SIGNAL_FUNC) cmd_quit);
458 command_unbind("join", (SIGNAL_FUNC) cmd_join);
459 command_unbind("msg", (SIGNAL_FUNC) cmd_msg);
460 command_unbind("foreach", (SIGNAL_FUNC) cmd_foreach);
461 command_unbind("foreach server", (SIGNAL_FUNC) cmd_foreach_server);
462 command_unbind("foreach channel", (SIGNAL_FUNC) cmd_foreach_channel);
463 command_unbind("foreach query", (SIGNAL_FUNC) cmd_foreach_query);
465 signal_remove("default command server", (SIGNAL_FUNC) sig_default_command_server);