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 #include "silc-commands.h"
48 SILC_CHANNEL_REC *silc_channel_create(SILC_SERVER_REC *server,
49 const char *name, int automatic)
51 SILC_CHANNEL_REC *rec;
53 g_return_val_if_fail(server == NULL || IS_SILC_SERVER(server), NULL);
54 g_return_val_if_fail(name != NULL, NULL);
56 rec = g_new0(SILC_CHANNEL_REC, 1);
57 rec->chat_type = SILC_PROTOCOL;
58 rec->name = g_strdup(name);
61 channel_init((CHANNEL_REC *) rec, automatic);
65 static void sig_channel_destroyed(SILC_CHANNEL_REC *channel)
67 if (!IS_SILC_CHANNEL(channel))
70 if (channel->server != NULL && !channel->left && !channel->kicked) {
71 /* destroying channel record without actually
72 having left the channel yet */
73 silc_command_exec(channel->server, "PART", channel->name);
77 static void silc_channels_join(SILC_SERVER_REC *server,
78 const char *channels, int automatic)
81 SILC_CHANNEL_REC *chanrec;
83 list = g_strsplit(channels, ",", -1);
84 for (tmp = list; *tmp != NULL; tmp++) {
85 chanrec = silc_channel_find(server, *tmp);
89 silc_command_exec(server, "JOIN", *tmp);
95 static void sig_connected(SILC_SERVER_REC *server)
97 if (IS_SILC_SERVER(server))
98 server->channels_join = (void *) silc_channels_join;
101 /* "server quit" signal from the core to indicate that QUIT command
104 static void sig_server_quit(SILC_SERVER_REC *server, const char *msg)
106 if (IS_SILC_SERVER(server) && server->conn && server->conn->sock)
107 silc_command_exec(server, "QUIT", msg);
110 /* Find Irssi channel entry by SILC channel entry */
112 SILC_CHANNEL_REC *silc_channel_find_entry(SILC_SERVER_REC *server,
113 SilcChannelEntry entry)
117 g_return_val_if_fail(IS_SILC_SERVER(server), NULL);
119 for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
120 SILC_CHANNEL_REC *rec = tmp->data;
122 if (rec->entry == entry)
129 /* PART (LEAVE) command. */
131 static void command_part(const char *data, SILC_SERVER_REC *server,
134 SILC_CHANNEL_REC *chanrec;
137 CMD_SILC_SERVER(server);
139 if (!IS_SILC_SERVER(server) || !server->connected)
140 cmd_return_error(CMDERR_NOT_CONNECTED);
142 if (!strcmp(data, "*") || *data == '\0') {
143 if (!IS_SILC_CHANNEL(item))
144 cmd_return_error(CMDERR_NOT_JOINED);
148 chanrec = silc_channel_find(server, data);
150 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
152 memset(userhost, 0, sizeof(userhost));
153 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
154 server->conn->local_entry->username,
155 server->conn->local_entry->hostname);
156 signal_emit("message part", 5, server, chanrec->name,
157 server->nick, userhost, "");
159 silc_command_exec(server, "LEAVE", chanrec->name);
162 channel_destroy(CHANNEL(chanrec));
165 /* ME local command. */
167 static void command_me(const char *data, SILC_SERVER_REC *server,
170 SILC_CHANNEL_REC *chanrec;
171 char *tmpcmd = "ME", *tmp;
173 unsigned char **argv;
174 SilcUInt32 *argv_lens, *argv_types;
177 CMD_SILC_SERVER(server);
179 if (!IS_SILC_SERVER(server) || !server->connected)
180 cmd_return_error(CMDERR_NOT_CONNECTED);
182 if (!IS_SILC_CHANNEL(item))
183 cmd_return_error(CMDERR_NOT_JOINED);
185 /* Now parse all arguments */
186 tmp = g_strconcat(tmpcmd, " ", data, NULL);
187 silc_parse_command_line(tmp, &argv, &argv_lens,
188 &argv_types, &argc, 2);
192 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
194 chanrec = silc_channel_find(server, item->name);
196 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
198 /* Send the action message */
199 silc_client_send_channel_message(silc_client, server->conn,
200 chanrec->entry, NULL,
201 SILC_MESSAGE_FLAG_ACTION,
202 argv[1], argv_lens[1], TRUE);
204 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
205 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
206 server->conn->local_entry->nickname, argv[1]);
208 for (i = 0; i < argc; i++)
210 silc_free(argv_lens);
211 silc_free(argv_types);
214 /* ACTION local command. Same as ME but takes the channel as mandatory
217 static void command_action(const char *data, SILC_SERVER_REC *server,
220 SILC_CHANNEL_REC *chanrec;
221 char *tmpcmd = "ME", *tmp;
223 unsigned char **argv;
224 SilcUInt32 *argv_lens, *argv_types;
227 CMD_SILC_SERVER(server);
228 if (!IS_SILC_SERVER(server) || !server->connected)
229 cmd_return_error(CMDERR_NOT_CONNECTED);
231 if (!IS_SILC_CHANNEL(item))
232 cmd_return_error(CMDERR_NOT_JOINED);
234 /* Now parse all arguments */
235 tmp = g_strconcat(tmpcmd, " ", data, NULL);
236 silc_parse_command_line(tmp, &argv, &argv_lens,
237 &argv_types, &argc, 3);
241 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
243 chanrec = silc_channel_find(server, argv[1]);
245 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
247 /* Send the action message */
248 silc_client_send_channel_message(silc_client, server->conn,
249 chanrec->entry, NULL,
250 SILC_MESSAGE_FLAG_ACTION,
251 argv[2], argv_lens[2], TRUE);
253 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
254 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
255 server->conn->local_entry->nickname, argv[2]);
257 for (i = 0; i < argc; i++)
259 silc_free(argv_lens);
260 silc_free(argv_types);
263 /* NOTICE local command. */
265 static void command_notice(const char *data, SILC_SERVER_REC *server,
268 SILC_CHANNEL_REC *chanrec;
269 char *tmpcmd = "ME", *tmp;
271 unsigned char **argv;
272 SilcUInt32 *argv_lens, *argv_types;
275 CMD_SILC_SERVER(server);
276 if (!IS_SILC_SERVER(server) || !server->connected)
277 cmd_return_error(CMDERR_NOT_CONNECTED);
279 if (!IS_SILC_CHANNEL(item))
280 cmd_return_error(CMDERR_NOT_JOINED);
282 /* Now parse all arguments */
283 tmp = g_strconcat(tmpcmd, " ", data, NULL);
284 silc_parse_command_line(tmp, &argv, &argv_lens,
285 &argv_types, &argc, 2);
289 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
291 chanrec = silc_channel_find(server, item->name);
293 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
295 /* Send the action message */
296 silc_client_send_channel_message(silc_client, server->conn,
297 chanrec->entry, NULL,
298 SILC_MESSAGE_FLAG_NOTICE,
299 argv[1], argv_lens[1], TRUE);
301 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
302 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_OWNNOTICE,
303 server->conn->local_entry->nickname, argv[1]);
305 for (i = 0; i < argc; i++)
307 silc_free(argv_lens);
308 silc_free(argv_types);
311 /* AWAY local command. Sends UMODE command that sets the SILC_UMODE_GONE
314 static void command_away(const char *data, SILC_SERVER_REC *server,
319 CMD_SILC_SERVER(server);
321 if (!IS_SILC_SERVER(server) || !server->connected)
322 cmd_return_error(CMDERR_NOT_CONNECTED);
325 /* Remove any possible away message */
326 silc_client_set_away_message(silc_client, server->conn, NULL);
329 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
332 /* Set the away message */
333 silc_client_set_away_message(silc_client, server->conn, (char *)data);
336 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
337 SILCTXT_SET_AWAY, data);
340 signal_emit("away mode changed", 1, server);
342 silc_command_exec(server, "UMODE", set ? "+g" : "-g");
346 int type; /* 1 = msg, 2 = channel */
348 SILC_SERVER_REC *server;
351 /* Key agreement callback that is called after the key agreement protocol
352 has been performed. This is called also if error occured during the
353 key agreement protocol. The `key' is the allocated key material and
354 the caller is responsible of freeing it. The `key' is NULL if error
355 has occured. The application can freely use the `key' to whatever
356 purpose it needs. See lib/silcske/silcske.h for the definition of
357 the SilcSKEKeyMaterial structure. */
359 static void keyagr_completion(SilcClient client,
360 SilcClientConnection conn,
361 SilcClientEntry client_entry,
362 SilcKeyAgreementStatus status,
363 SilcSKEKeyMaterial *key,
366 KeyInternal i = (KeyInternal)context;
369 case SILC_KEY_AGREEMENT_OK:
370 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
371 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
374 /* Set the private key for this client */
375 silc_client_del_private_message_key(client, conn, client_entry);
376 silc_client_add_private_message_key_ske(client, conn, client_entry,
377 NULL, key, i->responder);
378 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
379 SILCTXT_KEY_AGREEMENT_PRIVMSG,
380 client_entry->nickname);
381 silc_ske_free_key_material(key);
386 case SILC_KEY_AGREEMENT_ERROR:
387 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
388 SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
391 case SILC_KEY_AGREEMENT_FAILURE:
392 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
393 SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
396 case SILC_KEY_AGREEMENT_TIMEOUT:
397 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
398 SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
401 case SILC_KEY_AGREEMENT_ABORTED:
402 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
403 SILCTXT_KEY_AGREEMENT_ABORTED, client_entry->nickname);
414 /* Local command KEY. This command is used to set and unset private
415 keys for channels, set and unset private keys for private messages
416 with remote clients and to send key agreement requests and
417 negotiate the key agreement protocol with remote client. The
418 key agreement is supported only to negotiate private message keys,
419 it currently cannot be used to negotiate private keys for channels,
420 as it is not convenient for that purpose. */
423 SILC_SERVER_REC *server;
429 /* Callback to be called after client information is resolved from the
432 static void silc_client_command_key_get_clients(SilcClient client,
433 SilcClientConnection conn,
434 SilcClientEntry *clients,
435 SilcUInt32 clients_count,
438 KeyGetClients internal = (KeyGetClients)context;
441 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s",
443 silc_free(internal->data);
444 silc_free(internal->nick);
449 signal_emit("command key", 3, internal->data, internal->server,
452 silc_free(internal->data);
453 silc_free(internal->nick);
457 static void command_key(const char *data, SILC_SERVER_REC *server,
460 SilcClientConnection conn;
461 SilcClientEntry *entrys, client_entry = NULL;
462 SilcUInt32 entry_count;
463 SILC_CHANNEL_REC *chanrec = NULL;
464 SilcChannelEntry channel_entry = NULL;
465 char *nickname = NULL, *tmp;
466 int command = 0, port = 0, type = 0;
467 char *hostname = NULL;
468 KeyInternal internal = NULL;
470 unsigned char **argv;
471 SilcUInt32 *argv_lens, *argv_types;
472 char *bindhost = NULL;
474 CMD_SILC_SERVER(server);
476 if (!server || !IS_SILC_SERVER(server) || !server->connected)
477 cmd_return_error(CMDERR_NOT_CONNECTED);
481 /* Now parse all arguments */
482 tmp = g_strconcat("KEY", " ", data, NULL);
483 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
487 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
490 if (!strcasecmp(argv[1], "msg"))
492 if (!strcasecmp(argv[1], "channel"))
496 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
499 if (argv[2][0] == '*') {
500 nickname = strdup("*");
502 /* Parse the typed nickname. */
503 if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
504 printformat_module("fe-common/silc", server, NULL,
505 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
509 /* Find client entry */
510 entrys = silc_client_get_clients_local(silc_client, conn, nickname,
511 argv[2], &entry_count);
513 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
514 inter->server = server;
515 inter->data = strdup(data);
516 inter->nick = strdup(nickname);
518 silc_client_get_clients(silc_client, conn, nickname, argv[2],
519 silc_client_command_key_get_clients, inter);
522 client_entry = entrys[0];
528 /* Get channel entry */
531 if (argv[2][0] == '*') {
532 if (!conn->current_channel) {
534 cmd_return_error(CMDERR_NOT_JOINED);
536 name = conn->current_channel->channel_name;
541 chanrec = silc_channel_find(server, name);
542 if (chanrec == NULL) {
544 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
546 channel_entry = chanrec->entry;
550 if (!strcasecmp(argv[3], "set")) {
554 if (type == 1 && client_entry) {
555 /* Set private message key */
557 silc_client_del_private_message_key(silc_client, conn, client_entry);
560 silc_client_add_private_message_key(silc_client, conn, client_entry,
564 TRUE : FALSE), FALSE);
566 silc_client_add_private_message_key(silc_client, conn, client_entry,
570 TRUE : FALSE), FALSE);
572 /* Send the key to the remote client so that it starts using it
574 silc_client_send_private_message_key(silc_client, conn,
576 } else if (type == 2) {
577 /* Set private channel key */
578 char *cipher = NULL, *hmac = NULL;
580 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
581 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
582 SILCTXT_CH_PRIVATE_KEY_NOMODE,
583 channel_entry->channel_name);
592 if (!silc_client_add_channel_private_key(silc_client, conn,
597 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
598 SILCTXT_CH_PRIVATE_KEY_ERROR,
599 channel_entry->channel_name);
603 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
604 SILCTXT_CH_PRIVATE_KEY_ADD,
605 channel_entry->channel_name);
613 if (!strcasecmp(argv[3], "unset")) {
616 if (type == 1 && client_entry) {
617 /* Unset private message key */
618 silc_client_del_private_message_key(silc_client, conn, client_entry);
619 } else if (type == 2) {
620 /* Unset channel key(s) */
621 SilcChannelPrivateKey *keys;
622 SilcUInt32 keys_count;
626 silc_client_del_channel_private_keys(silc_client, conn,
630 number = atoi(argv[4]);
631 keys = silc_client_list_channel_private_keys(silc_client, conn,
637 if (!number || number > keys_count) {
638 silc_client_free_channel_private_keys(keys, keys_count);
642 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
644 silc_client_free_channel_private_keys(keys, keys_count);
652 if (!strcasecmp(argv[3], "list")) {
656 SilcPrivateMessageKeys keys;
657 SilcUInt32 keys_count;
661 keys = silc_client_list_private_message_keys(silc_client, conn,
666 /* list the private message key(s) */
667 if (nickname[0] == '*') {
668 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
669 SILCTXT_PRIVATE_KEY_LIST);
670 for (k = 0; k < keys_count; k++) {
671 memset(buf, 0, sizeof(buf));
672 strncat(buf, " ", 2);
673 len = strlen(keys[k].client_entry->nickname);
674 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
676 for (i = 0; i < 30 - len; i++)
680 len = strlen(keys[k].cipher);
681 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
683 for (i = 0; i < 14 - len; i++)
688 strcat(buf, "<hidden>");
690 strcat(buf, "*generated*");
692 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
695 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
696 SILCTXT_PRIVATE_KEY_LIST_NICK,
697 client_entry->nickname);
698 for (k = 0; k < keys_count; k++) {
699 if (keys[k].client_entry != client_entry)
702 memset(buf, 0, sizeof(buf));
703 strncat(buf, " ", 2);
704 len = strlen(keys[k].client_entry->nickname);
705 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
707 for (i = 0; i < 30 - len; i++)
711 len = strlen(keys[k].cipher);
712 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
714 for (i = 0; i < 14 - len; i++)
719 strcat(buf, "<hidden>");
721 strcat(buf, "*generated*");
723 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
727 silc_client_free_private_message_keys(keys, keys_count);
729 } else if (type == 2) {
730 SilcChannelPrivateKey *keys;
731 SilcUInt32 keys_count;
735 keys = silc_client_list_channel_private_keys(silc_client, conn,
739 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
740 SILCTXT_CH_PRIVATE_KEY_LIST,
741 channel_entry->channel_name);
746 for (k = 0; k < keys_count; k++) {
747 memset(buf, 0, sizeof(buf));
748 strncat(buf, " ", 2);
750 len = strlen(keys[k]->cipher->cipher->name);
751 strncat(buf, keys[k]->cipher->cipher->name, len > 16 ? 16 : len);
753 for (i = 0; i < 16 - len; i++)
757 len = strlen(silc_hmac_get_name(keys[k]->hmac));
758 strncat(buf, silc_hmac_get_name(keys[k]->hmac), len > 16 ? 16 : len);
760 for (i = 0; i < 16 - len; i++)
764 strcat(buf, "<hidden>");
766 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
769 silc_client_free_channel_private_keys(keys, keys_count);
775 /* Send command is used to send key agreement */
776 if (!strcasecmp(argv[3], "agreement")) {
782 port = atoi(argv[5]);
784 internal = silc_calloc(1, sizeof(*internal));
785 internal->type = type;
786 internal->server = server;
789 if (settings_get_bool("use_auto_addr")) {
791 hostname = (char *)settings_get_str("auto_public_ip");
793 /* If the hostname isn't set, treat this case as if auto_public_ip
795 if ((hostname) && (*hostname == '\0')) {
798 bindhost = (char *)settings_get_str("auto_bind_ip");
800 /* if the bind_ip isn't set, but the public_ip IS, then assume then
801 public_ip is the same value as the bind_ip. */
802 if ((bindhost) && (*bindhost == '\0'))
804 port = settings_get_int("auto_bind_port");
806 } /* if use_auto_addr */
810 /* Start command is used to start key agreement (after receiving the
811 key_agreement client operation). */
812 if (!strcasecmp(argv[3], "negotiate")) {
818 port = atoi(argv[5]);
820 internal = silc_calloc(1, sizeof(*internal));
821 internal->type = type;
822 internal->server = server;
825 /* Change current channel private key */
826 if (!strcasecmp(argv[3], "change")) {
829 /* Unset channel key(s) */
830 SilcChannelPrivateKey *keys;
831 SilcUInt32 keys_count;
834 keys = silc_client_list_channel_private_keys(silc_client, conn,
842 if (chanrec->cur_key >= keys_count)
843 chanrec->cur_key = 0;
847 number = atoi(argv[4]);
848 if (!number || number > keys_count)
849 chanrec->cur_key = 0;
851 chanrec->cur_key = number - 1;
854 /* Set the current channel private key */
855 silc_client_current_channel_private_key(silc_client, conn,
857 keys[chanrec->cur_key]);
858 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
859 SILCTXT_CH_PRIVATE_KEY_CHANGE, chanrec->cur_key + 1,
860 channel_entry->channel_name);
862 silc_client_free_channel_private_keys(keys, keys_count);
868 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
869 "Usage: /KEY msg|channel <nickname|channel> "
870 "set|unset|agreement|negotiate [<arguments>]");
874 if (command == 4 && client_entry) {
875 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
876 SILCTXT_KEY_AGREEMENT, argv[2]);
877 internal->responder = TRUE;
878 silc_client_send_key_agreement(
879 silc_client, conn, client_entry, hostname,
881 settings_get_int("key_exchange_timeout_secs"),
882 keyagr_completion, internal);
888 if (command == 5 && client_entry && hostname) {
889 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
890 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
891 internal->responder = FALSE;
892 silc_client_perform_key_agreement(silc_client, conn, client_entry,
893 hostname, port, keyagr_completion,
902 /* Lists locally saved client and server public keys. */
904 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
910 void silc_channels_init(void)
912 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
913 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
914 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
916 command_bind_silc("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
917 command_bind_silc("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
918 command_bind_silc("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
919 command_bind_silc("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
920 command_bind_silc("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
921 command_bind_silc("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
922 command_bind_silc("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
924 silc_nicklist_init();
927 void silc_channels_deinit(void)
929 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
930 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
931 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
933 command_unbind("part", (SIGNAL_FUNC) command_part);
934 command_unbind("me", (SIGNAL_FUNC) command_me);
935 command_unbind("action", (SIGNAL_FUNC) command_action);
936 command_unbind("notice", (SIGNAL_FUNC) command_notice);
937 command_unbind("away", (SIGNAL_FUNC) command_away);
938 command_unbind("key", (SIGNAL_FUNC) command_key);
939 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
941 silc_nicklist_deinit();