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"
45 SILC_CHANNEL_REC *silc_channel_create(SILC_SERVER_REC *server,
46 const char *name, int automatic)
48 SILC_CHANNEL_REC *rec;
50 g_return_val_if_fail(server == NULL || IS_SILC_SERVER(server), NULL);
51 g_return_val_if_fail(name != NULL, NULL);
53 rec = g_new0(SILC_CHANNEL_REC, 1);
54 rec->chat_type = SILC_PROTOCOL;
55 rec->name = g_strdup(name);
58 channel_init((CHANNEL_REC *) rec, automatic);
62 static void sig_channel_destroyed(SILC_CHANNEL_REC *channel)
64 if (!IS_SILC_CHANNEL(channel))
67 if (channel->server != NULL && !channel->left && !channel->kicked) {
68 /* destroying channel record without actually
69 having left the channel yet */
70 silc_command_exec(channel->server, "PART", channel->name);
74 static void silc_channels_join(SILC_SERVER_REC *server,
75 const char *channels, int automatic)
77 char **list, **tmp, *channel;
79 list = g_strsplit(channels, ",", -1);
80 for (tmp = list; *tmp != NULL; tmp++) {
81 channel = **tmp == '#' ? g_strdup(*tmp) :
82 g_strconcat("#", *tmp, NULL);
83 silc_channel_create(server, channel, FALSE);
84 silc_command_exec(server, "JOIN", channel);
90 static void sig_connected(SILC_SERVER_REC *server)
92 if (IS_SILC_SERVER(server))
93 server->channels_join = (void *) silc_channels_join;
96 /* "server quit" signal from the core to indicate that QUIT command
99 static void sig_server_quit(SILC_SERVER_REC *server, const char *msg)
101 if (IS_SILC_SERVER(server))
102 silc_command_exec(server, "QUIT", msg);
106 * "event join". Joined to a channel.
109 SILC_CHANNEL_REC *silc_channel_find_entry(SILC_SERVER_REC *server,
110 SilcChannelEntry entry)
114 g_return_val_if_fail(IS_SILC_SERVER(server), NULL);
116 for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
117 SILC_CHANNEL_REC *rec = tmp->data;
119 if (rec->entry == entry)
126 static void event_join(SILC_SERVER_REC *server, va_list va)
128 SILC_CHANNEL_REC *chanrec;
129 SILC_NICK_REC *nickrec;
130 SilcClientEntry client;
131 SilcChannelEntry channel;
133 client = va_arg(va, SilcClientEntry);
134 channel = va_arg(va, SilcChannelEntry);
136 if (client == server->conn->local_entry) {
137 /* You joined to channel */
138 chanrec = silc_channel_find(server, channel->channel_name);
139 if (chanrec != NULL && !chanrec->joined)
140 chanrec->entry = channel;
142 chanrec = silc_channel_find_entry(server, channel);
143 if (chanrec != NULL) {
144 SilcChannelUser user;
146 silc_list_start(chanrec->entry->clients);
147 while ((user = silc_list_get(chanrec->entry->clients)) != NULL)
148 if (user->client == client) {
149 nickrec = silc_nicklist_insert(chanrec, user, TRUE);
155 signal_emit("message join", 4, server, channel->channel_name,
157 client->username == NULL ? "" : client->username);
161 * "event leave". Left a channel.
164 static void event_leave(SILC_SERVER_REC *server, va_list va)
166 SILC_CHANNEL_REC *chanrec;
167 SILC_NICK_REC *nickrec;
168 SilcClientEntry client;
169 SilcChannelEntry channel;
171 client = va_arg(va, SilcClientEntry);
172 channel = va_arg(va, SilcChannelEntry);
174 signal_emit("message part", 5, server, channel->channel_name,
175 client->nickname, client->username ? client->username : "",
178 chanrec = silc_channel_find_entry(server, channel);
179 if (chanrec != NULL) {
180 nickrec = silc_nicklist_find(chanrec, client);
182 nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
187 * "event signoff". Left the network.
190 static void event_signoff(SILC_SERVER_REC *server, va_list va)
192 SilcClientEntry client;
196 client = va_arg(va, SilcClientEntry);
197 message = va_arg(va, char *);
199 signal_emit("message quit", 4, server, client->nickname,
200 client->username ? client->username : "",
201 message ? message : "");
203 nicks = nicklist_get_same_unique(SERVER(server), client);
204 for (tmp = nicks; tmp != NULL; tmp = tmp->next->next) {
205 CHANNEL_REC *channel = tmp->data;
206 NICK_REC *nickrec = tmp->next->data;
208 nicklist_remove(channel, nickrec);
213 * "event topic". Changed topic.
216 static void event_topic(SILC_SERVER_REC *server, va_list va)
218 SILC_CHANNEL_REC *chanrec;
219 SilcClientEntry client;
220 SilcChannelEntry channel;
223 client = va_arg(va, SilcClientEntry);
224 topic = va_arg(va, char *);
225 channel = va_arg(va, SilcChannelEntry);
227 chanrec = silc_channel_find_entry(server, channel);
228 if (chanrec != NULL) {
229 g_free_not_null(chanrec->topic);
230 chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
231 signal_emit("channel topic changed", 1, chanrec);
234 signal_emit("message topic", 5, server, channel->channel_name,
235 topic, client->nickname, client->username);
239 * "event invite". Invited or modified invite list.
242 static void event_invite(SILC_SERVER_REC *server, va_list va)
244 SilcClientEntry client;
245 SilcChannelEntry channel;
247 client = va_arg(va, SilcClientEntry);
248 channel = va_arg(va, SilcChannelEntry);
250 signal_emit("message invite", 4, server, channel->channel_name,
251 client->nickname, client->username);
255 * "event nick". Changed nickname.
258 static void event_nick(SILC_SERVER_REC *server, va_list va)
260 SilcClientEntry oldclient, newclient;
262 oldclient = va_arg(va, SilcClientEntry);
263 newclient = va_arg(va, SilcClientEntry);
265 nicklist_rename_unique(SERVER(server),
266 oldclient, oldclient->nickname,
267 newclient, newclient->nickname);
269 signal_emit("message nick", 4, server, newclient->nickname,
270 oldclient->nickname, newclient->username);
274 * "event cmode". Changed channel mode.
277 static void event_cmode(SILC_SERVER_REC *server, va_list va)
279 SILC_CHANNEL_REC *chanrec;
280 SilcClientEntry client;
281 SilcChannelEntry channel;
285 client = va_arg(va, SilcClientEntry);
286 modei = va_arg(va, uint32);
287 channel = va_arg(va, SilcChannelEntry);
288 mode = silc_client_chmode(modei, channel);
290 chanrec = silc_channel_find_entry(server, channel);
291 if (chanrec != NULL) {
292 g_free_not_null(chanrec->mode);
293 chanrec->mode = g_strdup(mode == NULL ? "" : mode);
294 signal_emit("channel mode changed", 1, chanrec);
297 printtext(server, channel->channel_name, MSGLEVEL_MODES,
298 "cmode/%s [%s] by %s", channel->channel_name, mode,
305 * "event cumode". Changed user's mode on channel.
308 static void event_cumode(SILC_SERVER_REC *server, va_list va)
310 SILC_CHANNEL_REC *chanrec;
311 SilcClientEntry client, destclient;
312 SilcChannelEntry channel;
316 client = va_arg(va, SilcClientEntry);
317 mode = va_arg(va, uint32);
318 destclient = va_arg(va, SilcClientEntry);
319 channel = va_arg(va, SilcChannelEntry);
321 modestr = silc_client_chumode(mode);
322 chanrec = silc_channel_find_entry(server, channel);
323 if (chanrec != NULL) {
326 if (destclient == server->conn->local_entry) {
328 (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
331 nick = silc_nicklist_find(chanrec, client);
333 nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
334 signal_emit("nick mode changed", 2, chanrec, nick);
338 printtext(server, channel->channel_name, MSGLEVEL_MODES,
339 "cumode/%s/%s [%s] by %s", destclient->nickname,
340 channel->channel_name, modestr, client->nickname);
346 * "event motd". Received MOTD.
349 static void event_motd(SILC_SERVER_REC *server, va_list va)
351 char *text = va_arg(va, char *);
353 if (!settings_get_bool("skip_motd"))
354 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", text);
358 * "event channel_change". Channel ID has changed.
361 static void event_channel_change(SILC_SERVER_REC *server, va_list va)
367 * "event server_signoff". Server has quit the network.
370 static void event_server_signoff(SILC_SERVER_REC *server, va_list va)
376 * "event kick". Someone was kicked from channel.
379 static void event_kick(SILC_SERVER_REC *server, va_list va)
385 * "event kill". Someone was killed from the network.
388 static void event_kill(SILC_SERVER_REC *server, va_list va)
394 * "event ban". Someone was banned or ban list was modified.
397 static void event_ban(SILC_SERVER_REC *server, va_list va)
402 /* PART (LEAVE) command. */
404 static void command_part(const char *data, SILC_SERVER_REC *server,
407 SILC_CHANNEL_REC *chanrec;
409 if (!IS_SILC_SERVER(server) || !server->connected)
410 cmd_return_error(CMDERR_NOT_CONNECTED);
413 if (!IS_SILC_CHANNEL(item))
414 cmd_return_error(CMDERR_NOT_JOINED);
418 chanrec = silc_channel_find(server, data);
420 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
422 signal_emit("message part", 5, server, chanrec->name,
423 server->nick, server->conn->local_entry->username, "");
425 silc_command_exec(server, "LEAVE", chanrec->name);
428 channel_destroy(CHANNEL(chanrec));
431 /* ME local command. */
433 static void command_me(const char *data, SILC_SERVER_REC *server,
436 SILC_CHANNEL_REC *chanrec;
437 char *tmpcmd = "ME", *tmp;
439 unsigned char **argv;
440 uint32 *argv_lens, *argv_types;
443 if (!IS_SILC_SERVER(server) || !server->connected)
444 cmd_return_error(CMDERR_NOT_CONNECTED);
446 if (!IS_SILC_CHANNEL(item))
447 cmd_return_error(CMDERR_NOT_JOINED);
449 /* Now parse all arguments */
450 tmp = g_strconcat(tmpcmd, " ", data, NULL);
451 silc_parse_command_line(tmp, &argv, &argv_lens,
452 &argv_types, &argc, 2);
456 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
458 chanrec = silc_channel_find(server, item->name);
460 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
462 /* Send the action message */
463 silc_client_send_channel_message(silc_client, server->conn,
464 chanrec->entry, NULL,
465 SILC_MESSAGE_FLAG_ACTION,
466 argv[1], argv_lens[1], TRUE);
468 for (i = 0; i < argc; i++)
470 silc_free(argv_lens);
471 silc_free(argv_types);
474 /* NOTICE local command. */
476 static void command_notice(const char *data, SILC_SERVER_REC *server,
479 SILC_CHANNEL_REC *chanrec;
480 char *tmpcmd = "ME", *tmp;
482 unsigned char **argv;
483 uint32 *argv_lens, *argv_types;
486 if (!IS_SILC_SERVER(server) || !server->connected)
487 cmd_return_error(CMDERR_NOT_CONNECTED);
489 if (!IS_SILC_CHANNEL(item))
490 cmd_return_error(CMDERR_NOT_JOINED);
492 /* Now parse all arguments */
493 tmp = g_strconcat(tmpcmd, " ", data, NULL);
494 silc_parse_command_line(tmp, &argv, &argv_lens,
495 &argv_types, &argc, 2);
499 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
501 chanrec = silc_channel_find(server, item->name);
503 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
505 /* Send the action message */
506 silc_client_send_channel_message(silc_client, server->conn,
507 chanrec->entry, NULL,
508 SILC_MESSAGE_FLAG_NOTICE,
509 argv[1], argv_lens[1], TRUE);
511 for (i = 0; i < argc; i++)
513 silc_free(argv_lens);
514 silc_free(argv_types);
517 void silc_channels_init(void)
519 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
520 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
521 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
523 signal_add("silc event join", (SIGNAL_FUNC) event_join);
524 signal_add("silc event leave", (SIGNAL_FUNC) event_leave);
525 signal_add("silc event signoff", (SIGNAL_FUNC) event_signoff);
526 signal_add("silc event topic", (SIGNAL_FUNC) event_topic);
527 signal_add("silc event invite", (SIGNAL_FUNC) event_invite);
528 signal_add("silc event nick", (SIGNAL_FUNC) event_nick);
529 signal_add("silc event cmode", (SIGNAL_FUNC) event_cmode);
530 signal_add("silc event cumode", (SIGNAL_FUNC) event_cumode);
531 signal_add("silc event motd", (SIGNAL_FUNC) event_motd);
532 signal_add("silc event channel_change", (SIGNAL_FUNC) event_channel_change);
533 signal_add("silc event server_signoff", (SIGNAL_FUNC) event_server_signoff);
534 signal_add("silc event kick", (SIGNAL_FUNC) event_kick);
535 signal_add("silc event kill", (SIGNAL_FUNC) event_kill);
536 signal_add("silc event ban", (SIGNAL_FUNC) event_ban);
538 command_bind("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
539 command_bind("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
540 command_bind("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
542 silc_nicklist_init();
545 void silc_channels_deinit(void)
547 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
548 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
549 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
551 signal_remove("silc event join", (SIGNAL_FUNC) event_join);
552 signal_remove("silc event leave", (SIGNAL_FUNC) event_leave);
553 signal_remove("silc event signoff", (SIGNAL_FUNC) event_signoff);
554 signal_remove("silc event topic", (SIGNAL_FUNC) event_topic);
555 signal_remove("silc event invite", (SIGNAL_FUNC) event_invite);
556 signal_remove("silc event nick", (SIGNAL_FUNC) event_nick);
557 signal_remove("silc event cmode", (SIGNAL_FUNC) event_cmode);
558 signal_remove("silc event cumode", (SIGNAL_FUNC) event_cumode);
559 signal_remove("silc event motd", (SIGNAL_FUNC) event_motd);
560 signal_remove("silc event channel_change",
561 (SIGNAL_FUNC) event_channel_change);
562 signal_remove("silc event server_signoff",
563 (SIGNAL_FUNC) event_server_signoff);
564 signal_remove("silc event kick", (SIGNAL_FUNC) event_kick);
565 signal_remove("silc event kill", (SIGNAL_FUNC) event_kill);
566 signal_remove("silc event ban", (SIGNAL_FUNC) event_ban);
568 command_unbind("part", (SIGNAL_FUNC) command_part);
569 command_unbind("me", (SIGNAL_FUNC) command_me);
570 command_unbind("notice", (SIGNAL_FUNC) command_notice);
572 silc_nicklist_deinit();