2 silc-channels.c : irssi
4 Copyright (C) 2000 - 2001 Timo Sirainen
5 Pekka Riikonen <priikone@poseidon.pspt.fi>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "net-nonblock.h"
25 #include "net-sendbuffer.h"
35 #include "channels-setup.h"
37 #include "silc-servers.h"
38 #include "silc-channels.h"
39 #include "silc-queries.h"
40 #include "silc-nicklist.h"
41 #include "window-item-def.h"
43 #include "fe-common/core/printtext.h"
44 #include "fe-common/silc/module-formats.h"
46 SILC_CHANNEL_REC *silc_channel_create(SILC_SERVER_REC *server,
47 const char *name, int automatic)
49 SILC_CHANNEL_REC *rec;
51 g_return_val_if_fail(server == NULL || IS_SILC_SERVER(server), NULL);
52 g_return_val_if_fail(name != NULL, NULL);
54 rec = g_new0(SILC_CHANNEL_REC, 1);
55 rec->chat_type = SILC_PROTOCOL;
56 rec->name = g_strdup(name);
59 channel_init((CHANNEL_REC *) rec, automatic);
63 static void sig_channel_destroyed(SILC_CHANNEL_REC *channel)
65 if (!IS_SILC_CHANNEL(channel))
68 if (channel->server != NULL && !channel->left && !channel->kicked) {
69 /* destroying channel record without actually
70 having left the channel yet */
71 silc_command_exec(channel->server, "PART", channel->name);
75 static void silc_channels_join(SILC_SERVER_REC *server,
76 const char *channels, int automatic)
78 char **list, **tmp, *channel;
80 list = g_strsplit(channels, ",", -1);
81 for (tmp = list; *tmp != NULL; tmp++) {
82 channel = **tmp == '#' ? g_strdup(*tmp) :
83 g_strconcat("#", *tmp, NULL);
84 silc_channel_create(server, channel, FALSE);
85 silc_command_exec(server, "JOIN", channel);
91 static void sig_connected(SILC_SERVER_REC *server)
93 if (IS_SILC_SERVER(server))
94 server->channels_join = (void *) silc_channels_join;
97 /* "server quit" signal from the core to indicate that QUIT command
100 static void sig_server_quit(SILC_SERVER_REC *server, const char *msg)
102 if (IS_SILC_SERVER(server))
103 silc_command_exec(server, "QUIT", msg);
107 * "event join". Joined to a channel.
110 SILC_CHANNEL_REC *silc_channel_find_entry(SILC_SERVER_REC *server,
111 SilcChannelEntry entry)
115 g_return_val_if_fail(IS_SILC_SERVER(server), NULL);
117 for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
118 SILC_CHANNEL_REC *rec = tmp->data;
120 if (rec->entry == entry)
127 static void event_join(SILC_SERVER_REC *server, va_list va)
129 SILC_CHANNEL_REC *chanrec;
130 SILC_NICK_REC *nickrec;
131 SilcClientEntry client;
132 SilcChannelEntry channel;
134 client = va_arg(va, SilcClientEntry);
135 channel = va_arg(va, SilcChannelEntry);
137 if (client == server->conn->local_entry) {
138 /* You joined to channel */
139 chanrec = silc_channel_find(server, channel->channel_name);
140 if (chanrec != NULL && !chanrec->joined)
141 chanrec->entry = channel;
143 chanrec = silc_channel_find_entry(server, channel);
144 if (chanrec != NULL) {
145 SilcChannelUser user;
147 silc_list_start(chanrec->entry->clients);
148 while ((user = silc_list_get(chanrec->entry->clients)) != NULL)
149 if (user->client == client) {
150 nickrec = silc_nicklist_insert(chanrec, user, TRUE);
156 signal_emit("message join", 4, server, channel->channel_name,
158 client->username == NULL ? "" : client->username);
162 * "event leave". Left a channel.
165 static void event_leave(SILC_SERVER_REC *server, va_list va)
167 SILC_CHANNEL_REC *chanrec;
168 SILC_NICK_REC *nickrec;
169 SilcClientEntry client;
170 SilcChannelEntry channel;
172 client = va_arg(va, SilcClientEntry);
173 channel = va_arg(va, SilcChannelEntry);
175 signal_emit("message part", 5, server, channel->channel_name,
176 client->nickname, client->username ? client->username : "",
179 chanrec = silc_channel_find_entry(server, channel);
180 if (chanrec != NULL) {
181 nickrec = silc_nicklist_find(chanrec, client);
183 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
188 * "event signoff". Left the network.
191 static void event_signoff(SILC_SERVER_REC *server, va_list va)
193 SilcClientEntry client;
197 client = va_arg(va, SilcClientEntry);
198 message = va_arg(va, char *);
200 signal_emit("message quit", 4, server, client->nickname,
201 client->username ? client->username : "",
202 message ? message : "");
204 nicks = nicklist_get_same_unique(SERVER(server), client);
205 for (tmp = nicks; tmp != NULL; tmp = tmp->next->next) {
206 CHANNEL_REC *channel = tmp->data;
207 NICK_REC *nickrec = tmp->next->data;
209 nicklist_remove(channel, nickrec);
214 * "event topic". Changed topic.
217 static void event_topic(SILC_SERVER_REC *server, va_list va)
219 SILC_CHANNEL_REC *chanrec;
220 SilcClientEntry client;
221 SilcChannelEntry channel;
224 client = va_arg(va, SilcClientEntry);
225 topic = va_arg(va, char *);
226 channel = va_arg(va, SilcChannelEntry);
228 chanrec = silc_channel_find_entry(server, channel);
229 if (chanrec != NULL) {
230 g_free_not_null(chanrec->topic);
231 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
232 signal_emit("channel topic changed", 1, chanrec);
235 signal_emit("message topic", 5, server, channel->channel_name,
236 topic, client->nickname, client->username);
240 * "event invite". Invited or modified invite list.
243 static void event_invite(SILC_SERVER_REC *server, va_list va)
245 SilcClientEntry client;
246 SilcChannelEntry channel;
248 client = va_arg(va, SilcClientEntry);
249 channel = va_arg(va, SilcChannelEntry);
251 signal_emit("message invite", 4, server, channel->channel_name,
252 client->nickname, client->username);
256 * "event nick". Changed nickname.
259 static void event_nick(SILC_SERVER_REC *server, va_list va)
261 SilcClientEntry oldclient, newclient;
263 oldclient = va_arg(va, SilcClientEntry);
264 newclient = va_arg(va, SilcClientEntry);
266 nicklist_rename_unique(SERVER(server),
267 oldclient, oldclient->nickname,
268 newclient, newclient->nickname);
270 signal_emit("message nick", 4, server, newclient->nickname,
271 oldclient->nickname, newclient->username);
275 * "event cmode". Changed channel mode.
278 static void event_cmode(SILC_SERVER_REC *server, va_list va)
280 SILC_CHANNEL_REC *chanrec;
281 SilcClientEntry client;
282 SilcChannelEntry channel;
286 client = va_arg(va, SilcClientEntry);
287 modei = va_arg(va, uint32);
288 (void)va_arg(va, char *);
289 (void)va_arg(va, char *);
290 channel = va_arg(va, SilcChannelEntry);
292 mode = silc_client_chmode(modei, channel);
294 chanrec = silc_channel_find_entry(server, channel);
295 if (chanrec != NULL) {
296 g_free_not_null(chanrec->mode);
297 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
298 signal_emit("channel mode changed", 1, chanrec);
301 printformat_module("fe-common/silc", server, channel->channel_name,
302 MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
303 channel->channel_name, mode ? mode : "removed all",
310 * "event cumode". Changed user's mode on channel.
313 static void event_cumode(SILC_SERVER_REC *server, va_list va)
315 SILC_CHANNEL_REC *chanrec;
316 SilcClientEntry client, destclient;
317 SilcChannelEntry channel;
321 client = va_arg(va, SilcClientEntry);
322 mode = va_arg(va, uint32);
323 destclient = va_arg(va, SilcClientEntry);
324 channel = va_arg(va, SilcChannelEntry);
326 modestr = silc_client_chumode(mode);
327 chanrec = silc_channel_find_entry(server, channel);
328 if (chanrec != NULL) {
331 if (destclient == server->conn->local_entry) {
333 (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
336 nick = silc_nicklist_find(chanrec, destclient);
338 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
339 signal_emit("nick mode changed", 2, chanrec, nick);
343 printformat_module("fe-common/silc", server, channel->channel_name,
344 MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
345 channel->channel_name, destclient->nickname,
346 modestr ? modestr : "removed all",
349 if (mode & SILC_CHANNEL_UMODE_CHANFO)
350 printformat_module("fe-common/silc",
351 server, channel->channel_name, MSGLEVEL_CRAP,
352 SILCTXT_CHANNEL_FOUNDER,
353 channel->channel_name, destclient->nickname);
359 * "event motd". Received MOTD.
362 static void event_motd(SILC_SERVER_REC *server, va_list va)
364 char *text = va_arg(va, char *);
366 if (!settings_get_bool("skip_motd"))
367 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", text);
371 * "event channel_change". Channel ID has changed.
374 static void event_channel_change(SILC_SERVER_REC *server, va_list va)
380 * "event server_signoff". Server has quit the network.
383 static void event_server_signoff(SILC_SERVER_REC *server, va_list va)
389 * "event kick". Someone was kicked from channel.
392 static void event_kick(SILC_SERVER_REC *server, va_list va)
398 * "event kill". Someone was killed from the network.
401 static void event_kill(SILC_SERVER_REC *server, va_list va)
407 * "event ban". Someone was banned or ban list was modified.
410 static void event_ban(SILC_SERVER_REC *server, va_list va)
415 /* PART (LEAVE) command. */
417 static void command_part(const char *data, SILC_SERVER_REC *server,
420 SILC_CHANNEL_REC *chanrec;
422 if (!IS_SILC_SERVER(server) || !server->connected)
423 cmd_return_error(CMDERR_NOT_CONNECTED);
426 if (!IS_SILC_CHANNEL(item))
427 cmd_return_error(CMDERR_NOT_JOINED);
431 chanrec = silc_channel_find(server, data);
433 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
435 signal_emit("message part", 5, server, chanrec->name,
436 server->nick, server->conn->local_entry->username, "");
438 silc_command_exec(server, "LEAVE", chanrec->name);
441 channel_destroy(CHANNEL(chanrec));
444 /* ME local command. */
446 static void command_me(const char *data, SILC_SERVER_REC *server,
449 SILC_CHANNEL_REC *chanrec;
450 char *tmpcmd = "ME", *tmp;
452 unsigned char **argv;
453 uint32 *argv_lens, *argv_types;
456 if (!IS_SILC_SERVER(server) || !server->connected)
457 cmd_return_error(CMDERR_NOT_CONNECTED);
459 if (!IS_SILC_CHANNEL(item))
460 cmd_return_error(CMDERR_NOT_JOINED);
462 /* Now parse all arguments */
463 tmp = g_strconcat(tmpcmd, " ", data, NULL);
464 silc_parse_command_line(tmp, &argv, &argv_lens,
465 &argv_types, &argc, 2);
469 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
471 chanrec = silc_channel_find(server, item->name);
473 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
475 /* Send the action message */
476 silc_client_send_channel_message(silc_client, server->conn,
477 chanrec->entry, NULL,
478 SILC_MESSAGE_FLAG_ACTION,
479 argv[1], argv_lens[1], TRUE);
481 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
482 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION, argv[1]);
484 for (i = 0; i < argc; i++)
486 silc_free(argv_lens);
487 silc_free(argv_types);
490 /* NOTICE local command. */
492 static void command_notice(const char *data, SILC_SERVER_REC *server,
495 SILC_CHANNEL_REC *chanrec;
496 char *tmpcmd = "ME", *tmp;
498 unsigned char **argv;
499 uint32 *argv_lens, *argv_types;
502 if (!IS_SILC_SERVER(server) || !server->connected)
503 cmd_return_error(CMDERR_NOT_CONNECTED);
505 if (!IS_SILC_CHANNEL(item))
506 cmd_return_error(CMDERR_NOT_JOINED);
508 /* Now parse all arguments */
509 tmp = g_strconcat(tmpcmd, " ", data, NULL);
510 silc_parse_command_line(tmp, &argv, &argv_lens,
511 &argv_types, &argc, 2);
515 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
517 chanrec = silc_channel_find(server, item->name);
519 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
521 /* Send the action message */
522 silc_client_send_channel_message(silc_client, server->conn,
523 chanrec->entry, NULL,
524 SILC_MESSAGE_FLAG_NOTICE,
525 argv[1], argv_lens[1], TRUE);
527 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
528 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_OWNNOTICE, argv[1]);
530 for (i = 0; i < argc; i++)
532 silc_free(argv_lens);
533 silc_free(argv_types);
536 /* AWAY local command. Sends UMODE command that sets the SILC_UMODE_GONE
539 static void command_away(const char *data, SILC_SERVER_REC *server,
542 if (!IS_SILC_SERVER(server) || !server->connected)
543 cmd_return_error(CMDERR_NOT_CONNECTED);
548 void silc_channels_init(void)
550 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
551 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
552 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
554 signal_add("silc event join", (SIGNAL_FUNC) event_join);
555 signal_add("silc event leave", (SIGNAL_FUNC) event_leave);
556 signal_add("silc event signoff", (SIGNAL_FUNC) event_signoff);
557 signal_add("silc event topic", (SIGNAL_FUNC) event_topic);
558 signal_add("silc event invite", (SIGNAL_FUNC) event_invite);
559 signal_add("silc event nick", (SIGNAL_FUNC) event_nick);
560 signal_add("silc event cmode", (SIGNAL_FUNC) event_cmode);
561 signal_add("silc event cumode", (SIGNAL_FUNC) event_cumode);
562 signal_add("silc event motd", (SIGNAL_FUNC) event_motd);
563 signal_add("silc event channel_change", (SIGNAL_FUNC) event_channel_change);
564 signal_add("silc event server_signoff", (SIGNAL_FUNC) event_server_signoff);
565 signal_add("silc event kick", (SIGNAL_FUNC) event_kick);
566 signal_add("silc event kill", (SIGNAL_FUNC) event_kill);
567 signal_add("silc event ban", (SIGNAL_FUNC) event_ban);
569 command_bind("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
570 command_bind("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
571 command_bind("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
572 command_bind("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
574 silc_nicklist_init();
577 void silc_channels_deinit(void)
579 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
580 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
581 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
583 signal_remove("silc event join", (SIGNAL_FUNC) event_join);
584 signal_remove("silc event leave", (SIGNAL_FUNC) event_leave);
585 signal_remove("silc event signoff", (SIGNAL_FUNC) event_signoff);
586 signal_remove("silc event topic", (SIGNAL_FUNC) event_topic);
587 signal_remove("silc event invite", (SIGNAL_FUNC) event_invite);
588 signal_remove("silc event nick", (SIGNAL_FUNC) event_nick);
589 signal_remove("silc event cmode", (SIGNAL_FUNC) event_cmode);
590 signal_remove("silc event cumode", (SIGNAL_FUNC) event_cumode);
591 signal_remove("silc event motd", (SIGNAL_FUNC) event_motd);
592 signal_remove("silc event channel_change",
593 (SIGNAL_FUNC) event_channel_change);
594 signal_remove("silc event server_signoff",
595 (SIGNAL_FUNC) event_server_signoff);
596 signal_remove("silc event kick", (SIGNAL_FUNC) event_kick);
597 signal_remove("silc event kill", (SIGNAL_FUNC) event_kill);
598 signal_remove("silc event ban", (SIGNAL_FUNC) event_ban);
600 command_unbind("part", (SIGNAL_FUNC) command_part);
601 command_unbind("me", (SIGNAL_FUNC) command_me);
602 command_unbind("notice", (SIGNAL_FUNC) command_notice);
603 command_unbind("away", (SIGNAL_FUNC) command_away);
605 silc_nicklist_deinit();