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)
79 SILC_CHANNEL_REC *chanrec;
81 list = g_strsplit(channels, ",", -1);
82 for (tmp = list; *tmp != NULL; tmp++) {
83 chanrec = silc_channel_find(server, *tmp);
87 silc_command_exec(server, "JOIN", *tmp);
93 static void sig_connected(SILC_SERVER_REC *server)
95 if (IS_SILC_SERVER(server))
96 server->channels_join = (void *) silc_channels_join;
99 /* "server quit" signal from the core to indicate that QUIT command
102 static void sig_server_quit(SILC_SERVER_REC *server, const char *msg)
104 if (IS_SILC_SERVER(server) && server->conn && server->conn->sock)
105 silc_command_exec(server, "QUIT", msg);
108 /* Find Irssi channel entry by SILC channel entry */
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 /* PART (LEAVE) command. */
129 static void command_part(const char *data, SILC_SERVER_REC *server,
132 SILC_CHANNEL_REC *chanrec;
135 if (!IS_SILC_SERVER(server) || !server->connected)
136 cmd_return_error(CMDERR_NOT_CONNECTED);
138 if (!strcmp(data, "*") || *data == '\0') {
139 if (!IS_SILC_CHANNEL(item))
140 cmd_return_error(CMDERR_NOT_JOINED);
144 chanrec = silc_channel_find(server, data);
146 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
148 memset(userhost, 0, sizeof(userhost));
149 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
150 server->conn->local_entry->username,
151 server->conn->local_entry->hostname);
152 signal_emit("message part", 5, server, chanrec->name,
153 server->nick, userhost, "");
155 silc_command_exec(server, "LEAVE", chanrec->name);
158 channel_destroy(CHANNEL(chanrec));
161 /* ME local command. */
163 static void command_me(const char *data, SILC_SERVER_REC *server,
166 SILC_CHANNEL_REC *chanrec;
167 char *tmpcmd = "ME", *tmp;
169 unsigned char **argv;
170 SilcUInt32 *argv_lens, *argv_types;
173 if (!IS_SILC_SERVER(server) || !server->connected)
174 cmd_return_error(CMDERR_NOT_CONNECTED);
176 if (!IS_SILC_CHANNEL(item))
177 cmd_return_error(CMDERR_NOT_JOINED);
179 /* Now parse all arguments */
180 tmp = g_strconcat(tmpcmd, " ", data, NULL);
181 silc_parse_command_line(tmp, &argv, &argv_lens,
182 &argv_types, &argc, 2);
186 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
188 chanrec = silc_channel_find(server, item->name);
190 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
192 /* Send the action message */
193 silc_client_send_channel_message(silc_client, server->conn,
194 chanrec->entry, NULL,
195 SILC_MESSAGE_FLAG_ACTION,
196 argv[1], argv_lens[1], TRUE);
198 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
199 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
200 server->conn->local_entry->nickname, argv[1]);
202 for (i = 0; i < argc; i++)
204 silc_free(argv_lens);
205 silc_free(argv_types);
208 /* ACTION local command. Same as ME but takes the channel as mandatory
211 static void command_action(const char *data, SILC_SERVER_REC *server,
214 SILC_CHANNEL_REC *chanrec;
215 char *tmpcmd = "ME", *tmp;
217 unsigned char **argv;
218 SilcUInt32 *argv_lens, *argv_types;
221 if (!IS_SILC_SERVER(server) || !server->connected)
222 cmd_return_error(CMDERR_NOT_CONNECTED);
224 if (!IS_SILC_CHANNEL(item))
225 cmd_return_error(CMDERR_NOT_JOINED);
227 /* Now parse all arguments */
228 tmp = g_strconcat(tmpcmd, " ", data, NULL);
229 silc_parse_command_line(tmp, &argv, &argv_lens,
230 &argv_types, &argc, 3);
234 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
236 chanrec = silc_channel_find(server, argv[1]);
238 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
240 /* Send the action message */
241 silc_client_send_channel_message(silc_client, server->conn,
242 chanrec->entry, NULL,
243 SILC_MESSAGE_FLAG_ACTION,
244 argv[2], argv_lens[2], TRUE);
246 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
247 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
248 server->conn->local_entry->nickname, argv[2]);
250 for (i = 0; i < argc; i++)
252 silc_free(argv_lens);
253 silc_free(argv_types);
256 /* NOTICE local command. */
258 static void command_notice(const char *data, SILC_SERVER_REC *server,
261 SILC_CHANNEL_REC *chanrec;
262 char *tmpcmd = "ME", *tmp;
264 unsigned char **argv;
265 SilcUInt32 *argv_lens, *argv_types;
268 if (!IS_SILC_SERVER(server) || !server->connected)
269 cmd_return_error(CMDERR_NOT_CONNECTED);
271 if (!IS_SILC_CHANNEL(item))
272 cmd_return_error(CMDERR_NOT_JOINED);
274 /* Now parse all arguments */
275 tmp = g_strconcat(tmpcmd, " ", data, NULL);
276 silc_parse_command_line(tmp, &argv, &argv_lens,
277 &argv_types, &argc, 2);
281 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
283 chanrec = silc_channel_find(server, item->name);
285 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
287 /* Send the action message */
288 silc_client_send_channel_message(silc_client, server->conn,
289 chanrec->entry, NULL,
290 SILC_MESSAGE_FLAG_NOTICE,
291 argv[1], argv_lens[1], TRUE);
293 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
294 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_OWNNOTICE,
295 server->conn->local_entry->nickname, argv[1]);
297 for (i = 0; i < argc; i++)
299 silc_free(argv_lens);
300 silc_free(argv_types);
303 /* AWAY local command. Sends UMODE command that sets the SILC_UMODE_GONE
306 static void command_away(const char *data, SILC_SERVER_REC *server,
311 if (!IS_SILC_SERVER(server) || !server->connected)
312 cmd_return_error(CMDERR_NOT_CONNECTED);
315 /* Remove any possible away message */
316 silc_client_set_away_message(silc_client, server->conn, NULL);
319 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
322 /* Set the away message */
323 silc_client_set_away_message(silc_client, server->conn, (char *)data);
326 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
327 SILCTXT_SET_AWAY, data);
330 signal_emit("away mode changed", 1, server);
332 silc_command_exec(server, "UMODE", set ? "+g" : "-g");
336 int type; /* 1 = msg, 2 = channel */
338 SILC_SERVER_REC *server;
341 /* Key agreement callback that is called after the key agreement protocol
342 has been performed. This is called also if error occured during the
343 key agreement protocol. The `key' is the allocated key material and
344 the caller is responsible of freeing it. The `key' is NULL if error
345 has occured. The application can freely use the `key' to whatever
346 purpose it needs. See lib/silcske/silcske.h for the definition of
347 the SilcSKEKeyMaterial structure. */
349 static void keyagr_completion(SilcClient client,
350 SilcClientConnection conn,
351 SilcClientEntry client_entry,
352 SilcKeyAgreementStatus status,
353 SilcSKEKeyMaterial *key,
356 KeyInternal i = (KeyInternal)context;
359 case SILC_KEY_AGREEMENT_OK:
360 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
361 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
364 /* Set the private key for this client */
365 silc_client_del_private_message_key(client, conn, client_entry);
366 silc_client_add_private_message_key_ske(client, conn, client_entry,
367 NULL, key, i->responder);
368 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
369 SILCTXT_KEY_AGREEMENT_PRIVMSG,
370 client_entry->nickname);
371 silc_ske_free_key_material(key);
376 case SILC_KEY_AGREEMENT_ERROR:
377 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
378 SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
381 case SILC_KEY_AGREEMENT_FAILURE:
382 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
383 SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
386 case SILC_KEY_AGREEMENT_TIMEOUT:
387 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
388 SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
391 case SILC_KEY_AGREEMENT_ABORTED:
392 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
393 SILCTXT_KEY_AGREEMENT_ABORTED, client_entry->nickname);
404 /* Local command KEY. This command is used to set and unset private
405 keys for channels, set and unset private keys for private messages
406 with remote clients and to send key agreement requests and
407 negotiate the key agreement protocol with remote client. The
408 key agreement is supported only to negotiate private message keys,
409 it currently cannot be used to negotiate private keys for channels,
410 as it is not convenient for that purpose. */
413 SILC_SERVER_REC *server;
419 /* Callback to be called after client information is resolved from the
422 static void silc_client_command_key_get_clients(SilcClient client,
423 SilcClientConnection conn,
424 SilcClientEntry *clients,
425 SilcUInt32 clients_count,
428 KeyGetClients internal = (KeyGetClients)context;
431 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s",
433 silc_free(internal->data);
434 silc_free(internal->nick);
439 signal_emit("command key", 3, internal->data, internal->server,
442 silc_free(internal->data);
443 silc_free(internal->nick);
447 static void command_key(const char *data, SILC_SERVER_REC *server,
450 SilcClientConnection conn;
451 SilcClientEntry *entrys, client_entry = NULL;
452 SilcUInt32 entry_count;
453 SILC_CHANNEL_REC *chanrec = NULL;
454 SilcChannelEntry channel_entry = NULL;
455 char *nickname = NULL, *tmp;
456 int command = 0, port = 0, type = 0;
457 char *hostname = NULL;
458 KeyInternal internal = NULL;
460 unsigned char **argv;
461 SilcUInt32 *argv_lens, *argv_types;
462 char *bindhost = NULL;
464 if (!server || !IS_SILC_SERVER(server) || !server->connected)
465 cmd_return_error(CMDERR_NOT_CONNECTED);
469 /* Now parse all arguments */
470 tmp = g_strconcat("KEY", " ", data, NULL);
471 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
475 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
478 if (!strcasecmp(argv[1], "msg"))
480 if (!strcasecmp(argv[1], "channel"))
484 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
487 if (argv[2][0] == '*') {
488 nickname = strdup("*");
490 /* Parse the typed nickname. */
491 if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
492 printformat_module("fe-common/silc", server, NULL,
493 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
497 /* Find client entry */
498 entrys = silc_client_get_clients_local(silc_client, conn, nickname,
499 argv[2], &entry_count);
501 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
502 inter->server = server;
503 inter->data = strdup(data);
504 inter->nick = strdup(nickname);
506 silc_client_get_clients(silc_client, conn, nickname, argv[2],
507 silc_client_command_key_get_clients, inter);
510 client_entry = entrys[0];
516 /* Get channel entry */
519 if (argv[2][0] == '*') {
520 if (!conn->current_channel) {
522 cmd_return_error(CMDERR_NOT_JOINED);
524 name = conn->current_channel->channel_name;
529 chanrec = silc_channel_find(server, name);
530 if (chanrec == NULL) {
532 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
534 channel_entry = chanrec->entry;
538 if (!strcasecmp(argv[3], "set")) {
542 if (type == 1 && client_entry) {
543 /* Set private message key */
545 silc_client_del_private_message_key(silc_client, conn, client_entry);
548 silc_client_add_private_message_key(silc_client, conn, client_entry,
552 TRUE : FALSE), FALSE);
554 silc_client_add_private_message_key(silc_client, conn, client_entry,
558 TRUE : FALSE), FALSE);
560 /* Send the key to the remote client so that it starts using it
562 silc_client_send_private_message_key(silc_client, conn,
564 } else if (type == 2) {
565 /* Set private channel key */
566 char *cipher = NULL, *hmac = NULL;
568 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
569 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
570 SILCTXT_CH_PRIVATE_KEY_NOMODE,
571 channel_entry->channel_name);
580 if (!silc_client_add_channel_private_key(silc_client, conn,
585 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
586 SILCTXT_CH_PRIVATE_KEY_ERROR,
587 channel_entry->channel_name);
591 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
592 SILCTXT_CH_PRIVATE_KEY_ADD,
593 channel_entry->channel_name);
601 if (!strcasecmp(argv[3], "unset")) {
604 if (type == 1 && client_entry) {
605 /* Unset private message key */
606 silc_client_del_private_message_key(silc_client, conn, client_entry);
607 } else if (type == 2) {
608 /* Unset channel key(s) */
609 SilcChannelPrivateKey *keys;
610 SilcUInt32 keys_count;
614 silc_client_del_channel_private_keys(silc_client, conn,
618 number = atoi(argv[4]);
619 keys = silc_client_list_channel_private_keys(silc_client, conn,
625 if (!number || number > keys_count) {
626 silc_client_free_channel_private_keys(keys, keys_count);
630 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
632 silc_client_free_channel_private_keys(keys, keys_count);
640 if (!strcasecmp(argv[3], "list")) {
644 SilcPrivateMessageKeys keys;
645 SilcUInt32 keys_count;
649 keys = silc_client_list_private_message_keys(silc_client, conn,
654 /* list the private message key(s) */
655 if (nickname[0] == '*') {
656 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
657 SILCTXT_PRIVATE_KEY_LIST);
658 for (k = 0; k < keys_count; k++) {
659 memset(buf, 0, sizeof(buf));
660 strncat(buf, " ", 2);
661 len = strlen(keys[k].client_entry->nickname);
662 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
664 for (i = 0; i < 30 - len; i++)
668 len = strlen(keys[k].cipher);
669 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
671 for (i = 0; i < 14 - len; i++)
676 strcat(buf, "<hidden>");
678 strcat(buf, "*generated*");
680 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
683 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
684 SILCTXT_PRIVATE_KEY_LIST_NICK,
685 client_entry->nickname);
686 for (k = 0; k < keys_count; k++) {
687 if (keys[k].client_entry != client_entry)
690 memset(buf, 0, sizeof(buf));
691 strncat(buf, " ", 2);
692 len = strlen(keys[k].client_entry->nickname);
693 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
695 for (i = 0; i < 30 - len; i++)
699 len = strlen(keys[k].cipher);
700 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
702 for (i = 0; i < 14 - len; i++)
707 strcat(buf, "<hidden>");
709 strcat(buf, "*generated*");
711 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
715 silc_client_free_private_message_keys(keys, keys_count);
717 } else if (type == 2) {
718 SilcChannelPrivateKey *keys;
719 SilcUInt32 keys_count;
723 keys = silc_client_list_channel_private_keys(silc_client, conn,
727 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
728 SILCTXT_CH_PRIVATE_KEY_LIST,
729 channel_entry->channel_name);
734 for (k = 0; k < keys_count; k++) {
735 memset(buf, 0, sizeof(buf));
736 strncat(buf, " ", 2);
738 len = strlen(keys[k]->cipher->cipher->name);
739 strncat(buf, keys[k]->cipher->cipher->name, len > 16 ? 16 : len);
741 for (i = 0; i < 16 - len; i++)
745 len = strlen(silc_hmac_get_name(keys[k]->hmac));
746 strncat(buf, silc_hmac_get_name(keys[k]->hmac), len > 16 ? 16 : len);
748 for (i = 0; i < 16 - len; i++)
752 strcat(buf, "<hidden>");
754 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
757 silc_client_free_channel_private_keys(keys, keys_count);
763 /* Send command is used to send key agreement */
764 if (!strcasecmp(argv[3], "agreement")) {
770 port = atoi(argv[5]);
772 internal = silc_calloc(1, sizeof(*internal));
773 internal->type = type;
774 internal->server = server;
777 if (settings_get_bool("use_auto_addr")) {
779 hostname = (char *)settings_get_str("auto_public_ip");
781 /* If the hostname isn't set, treat this case as if auto_public_ip
783 if ((hostname) && (*hostname == '\0')) {
786 bindhost = (char *)settings_get_str("auto_bind_ip");
788 /* if the bind_ip isn't set, but the public_ip IS, then assume then
789 public_ip is the same value as the bind_ip. */
790 if ((bindhost) && (*bindhost == '\0'))
792 port = settings_get_int("auto_bind_port");
794 } /* if use_auto_addr */
798 /* Start command is used to start key agreement (after receiving the
799 key_agreement client operation). */
800 if (!strcasecmp(argv[3], "negotiate")) {
806 port = atoi(argv[5]);
808 internal = silc_calloc(1, sizeof(*internal));
809 internal->type = type;
810 internal->server = server;
813 /* Change current channel private key */
814 if (!strcasecmp(argv[3], "change")) {
817 /* Unset channel key(s) */
818 SilcChannelPrivateKey *keys;
819 SilcUInt32 keys_count;
822 keys = silc_client_list_channel_private_keys(silc_client, conn,
830 if (chanrec->cur_key >= keys_count)
831 chanrec->cur_key = 0;
835 number = atoi(argv[4]);
836 if (!number || number > keys_count)
837 chanrec->cur_key = 0;
839 chanrec->cur_key = number - 1;
842 /* Set the current channel private key */
843 silc_client_current_channel_private_key(silc_client, conn,
845 keys[chanrec->cur_key]);
846 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
847 SILCTXT_CH_PRIVATE_KEY_CHANGE, chanrec->cur_key + 1,
848 channel_entry->channel_name);
850 silc_client_free_channel_private_keys(keys, keys_count);
856 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
857 "Usage: /KEY msg|channel <nickname|channel> "
858 "set|unset|agreement|negotiate [<arguments>]");
862 if (command == 4 && client_entry) {
863 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
864 SILCTXT_KEY_AGREEMENT, argv[2]);
865 internal->responder = TRUE;
866 silc_client_send_key_agreement(
867 silc_client, conn, client_entry, hostname,
869 settings_get_int("key_exchange_timeout_secs"),
870 keyagr_completion, internal);
876 if (command == 5 && client_entry && hostname) {
877 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
878 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
879 internal->responder = FALSE;
880 silc_client_perform_key_agreement(silc_client, conn, client_entry,
881 hostname, port, keyagr_completion,
890 /* Lists locally saved client and server public keys. */
892 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
898 void silc_channels_init(void)
900 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
901 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
902 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
904 command_bind("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
905 command_bind("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
906 command_bind("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
907 command_bind("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
908 command_bind("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
909 command_bind("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
910 command_bind("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
912 silc_nicklist_init();
915 void silc_channels_deinit(void)
917 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
918 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
919 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
921 command_unbind("part", (SIGNAL_FUNC) command_part);
922 command_unbind("me", (SIGNAL_FUNC) command_me);
923 command_unbind("action", (SIGNAL_FUNC) command_action);
924 command_unbind("notice", (SIGNAL_FUNC) command_notice);
925 command_unbind("away", (SIGNAL_FUNC) command_away);
926 command_unbind("key", (SIGNAL_FUNC) command_key);
927 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
929 silc_nicklist_deinit();