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, "LEAVE", 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 chanrec->left = TRUE;
160 silc_command_exec(server, "LEAVE", chanrec->name);
163 channel_destroy(CHANNEL(chanrec));
166 /* ME local command. */
168 static void command_me(const char *data, SILC_SERVER_REC *server,
171 SILC_CHANNEL_REC *chanrec;
172 char *tmpcmd = "ME", *tmp;
174 unsigned char **argv;
175 SilcUInt32 *argv_lens, *argv_types;
178 CMD_SILC_SERVER(server);
180 if (!IS_SILC_SERVER(server) || !server->connected)
181 cmd_return_error(CMDERR_NOT_CONNECTED);
183 if (!IS_SILC_CHANNEL(item))
184 cmd_return_error(CMDERR_NOT_JOINED);
186 /* Now parse all arguments */
187 tmp = g_strconcat(tmpcmd, " ", data, NULL);
188 silc_parse_command_line(tmp, &argv, &argv_lens,
189 &argv_types, &argc, 2);
193 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
195 chanrec = silc_channel_find(server, item->name);
197 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
199 /* Send the action message */
200 silc_client_send_channel_message(silc_client, server->conn,
201 chanrec->entry, NULL,
202 SILC_MESSAGE_FLAG_ACTION,
203 argv[1], argv_lens[1], TRUE);
205 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
206 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
207 server->conn->local_entry->nickname, argv[1]);
209 for (i = 0; i < argc; i++)
211 silc_free(argv_lens);
212 silc_free(argv_types);
215 /* ACTION local command. Same as ME but takes the channel as mandatory
218 static void command_action(const char *data, SILC_SERVER_REC *server,
221 SILC_CHANNEL_REC *chanrec;
222 char *tmpcmd = "ME", *tmp;
224 unsigned char **argv;
225 SilcUInt32 *argv_lens, *argv_types;
228 CMD_SILC_SERVER(server);
229 if (!IS_SILC_SERVER(server) || !server->connected)
230 cmd_return_error(CMDERR_NOT_CONNECTED);
232 if (!IS_SILC_CHANNEL(item))
233 cmd_return_error(CMDERR_NOT_JOINED);
235 /* Now parse all arguments */
236 tmp = g_strconcat(tmpcmd, " ", data, NULL);
237 silc_parse_command_line(tmp, &argv, &argv_lens,
238 &argv_types, &argc, 3);
242 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
244 chanrec = silc_channel_find(server, argv[1]);
246 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
248 /* Send the action message */
249 silc_client_send_channel_message(silc_client, server->conn,
250 chanrec->entry, NULL,
251 SILC_MESSAGE_FLAG_ACTION,
252 argv[2], argv_lens[2], TRUE);
254 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
255 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
256 server->conn->local_entry->nickname, argv[2]);
258 for (i = 0; i < argc; i++)
260 silc_free(argv_lens);
261 silc_free(argv_types);
264 /* NOTICE local command. */
266 static void command_notice(const char *data, SILC_SERVER_REC *server,
269 SILC_CHANNEL_REC *chanrec;
270 char *tmpcmd = "ME", *tmp;
272 unsigned char **argv;
273 SilcUInt32 *argv_lens, *argv_types;
276 CMD_SILC_SERVER(server);
277 if (!IS_SILC_SERVER(server) || !server->connected)
278 cmd_return_error(CMDERR_NOT_CONNECTED);
280 if (!IS_SILC_CHANNEL(item))
281 cmd_return_error(CMDERR_NOT_JOINED);
283 /* Now parse all arguments */
284 tmp = g_strconcat(tmpcmd, " ", data, NULL);
285 silc_parse_command_line(tmp, &argv, &argv_lens,
286 &argv_types, &argc, 2);
290 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
292 chanrec = silc_channel_find(server, item->name);
294 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
296 /* Send the action message */
297 silc_client_send_channel_message(silc_client, server->conn,
298 chanrec->entry, NULL,
299 SILC_MESSAGE_FLAG_NOTICE,
300 argv[1], argv_lens[1], TRUE);
302 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
303 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_OWNNOTICE,
304 server->conn->local_entry->nickname, argv[1]);
306 for (i = 0; i < argc; i++)
308 silc_free(argv_lens);
309 silc_free(argv_types);
312 /* AWAY local command. Sends UMODE command that sets the SILC_UMODE_GONE
315 static void command_away(const char *data, SILC_SERVER_REC *server,
320 CMD_SILC_SERVER(server);
322 if (!IS_SILC_SERVER(server) || !server->connected)
323 cmd_return_error(CMDERR_NOT_CONNECTED);
326 /* Remove any possible away message */
327 silc_client_set_away_message(silc_client, server->conn, NULL);
330 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
333 /* Set the away message */
334 silc_client_set_away_message(silc_client, server->conn, (char *)data);
337 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
338 SILCTXT_SET_AWAY, data);
341 signal_emit("away mode changed", 1, server);
343 silc_command_exec(server, "UMODE", set ? "+g" : "-g");
347 int type; /* 1 = msg, 2 = channel */
349 SILC_SERVER_REC *server;
352 /* Key agreement callback that is called after the key agreement protocol
353 has been performed. This is called also if error occured during the
354 key agreement protocol. The `key' is the allocated key material and
355 the caller is responsible of freeing it. The `key' is NULL if error
356 has occured. The application can freely use the `key' to whatever
357 purpose it needs. See lib/silcske/silcske.h for the definition of
358 the SilcSKEKeyMaterial structure. */
360 static void keyagr_completion(SilcClient client,
361 SilcClientConnection conn,
362 SilcClientEntry client_entry,
363 SilcKeyAgreementStatus status,
364 SilcSKEKeyMaterial *key,
367 KeyInternal i = (KeyInternal)context;
370 case SILC_KEY_AGREEMENT_OK:
371 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
372 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
375 /* Set the private key for this client */
376 silc_client_del_private_message_key(client, conn, client_entry);
377 silc_client_add_private_message_key_ske(client, conn, client_entry,
378 NULL, key, i->responder);
379 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
380 SILCTXT_KEY_AGREEMENT_PRIVMSG,
381 client_entry->nickname);
382 silc_ske_free_key_material(key);
387 case SILC_KEY_AGREEMENT_ERROR:
388 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
389 SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
392 case SILC_KEY_AGREEMENT_FAILURE:
393 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
394 SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
397 case SILC_KEY_AGREEMENT_TIMEOUT:
398 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
399 SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
402 case SILC_KEY_AGREEMENT_ABORTED:
403 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
404 SILCTXT_KEY_AGREEMENT_ABORTED, client_entry->nickname);
415 /* Local command KEY. This command is used to set and unset private
416 keys for channels, set and unset private keys for private messages
417 with remote clients and to send key agreement requests and
418 negotiate the key agreement protocol with remote client. The
419 key agreement is supported only to negotiate private message keys,
420 it currently cannot be used to negotiate private keys for channels,
421 as it is not convenient for that purpose. */
424 SILC_SERVER_REC *server;
430 /* Callback to be called after client information is resolved from the
433 static void silc_client_command_key_get_clients(SilcClient client,
434 SilcClientConnection conn,
435 SilcClientEntry *clients,
436 SilcUInt32 clients_count,
439 KeyGetClients internal = (KeyGetClients)context;
442 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s",
444 silc_free(internal->data);
445 silc_free(internal->nick);
450 signal_emit("command key", 3, internal->data, internal->server,
453 silc_free(internal->data);
454 silc_free(internal->nick);
458 static void command_key(const char *data, SILC_SERVER_REC *server,
461 SilcClientConnection conn;
462 SilcClientEntry *entrys, client_entry = NULL;
463 SilcUInt32 entry_count;
464 SILC_CHANNEL_REC *chanrec = NULL;
465 SilcChannelEntry channel_entry = NULL;
466 char *nickname = NULL, *tmp;
467 int command = 0, port = 0, type = 0;
468 char *hostname = NULL;
469 KeyInternal internal = NULL;
471 unsigned char **argv;
472 SilcUInt32 *argv_lens, *argv_types;
473 char *bindhost = NULL;
475 CMD_SILC_SERVER(server);
477 if (!server || !IS_SILC_SERVER(server) || !server->connected)
478 cmd_return_error(CMDERR_NOT_CONNECTED);
482 /* Now parse all arguments */
483 tmp = g_strconcat("KEY", " ", data, NULL);
484 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
488 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
491 if (!strcasecmp(argv[1], "msg"))
493 if (!strcasecmp(argv[1], "channel"))
497 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
500 if (argv[2][0] == '*') {
501 nickname = strdup("*");
503 /* Parse the typed nickname. */
504 if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
505 printformat_module("fe-common/silc", server, NULL,
506 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
510 /* Find client entry */
511 entrys = silc_client_get_clients_local(silc_client, conn, nickname,
512 argv[2], &entry_count);
514 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
515 inter->server = server;
516 inter->data = strdup(data);
517 inter->nick = strdup(nickname);
519 silc_client_get_clients(silc_client, conn, nickname, argv[2],
520 silc_client_command_key_get_clients, inter);
523 client_entry = entrys[0];
529 /* Get channel entry */
532 if (argv[2][0] == '*') {
533 if (!conn->current_channel) {
535 cmd_return_error(CMDERR_NOT_JOINED);
537 name = conn->current_channel->channel_name;
542 chanrec = silc_channel_find(server, name);
543 if (chanrec == NULL) {
545 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
547 channel_entry = chanrec->entry;
551 if (!strcasecmp(argv[3], "set")) {
555 if (type == 1 && client_entry) {
556 /* Set private message key */
558 silc_client_del_private_message_key(silc_client, conn, client_entry);
561 silc_client_add_private_message_key(silc_client, conn, client_entry,
565 TRUE : FALSE), FALSE);
567 silc_client_add_private_message_key(silc_client, conn, client_entry,
571 TRUE : FALSE), FALSE);
573 /* Send the key to the remote client so that it starts using it
575 silc_client_send_private_message_key(silc_client, conn,
577 } else if (type == 2) {
578 /* Set private channel key */
579 char *cipher = NULL, *hmac = NULL;
581 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
582 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
583 SILCTXT_CH_PRIVATE_KEY_NOMODE,
584 channel_entry->channel_name);
593 if (!silc_client_add_channel_private_key(silc_client, conn,
598 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
599 SILCTXT_CH_PRIVATE_KEY_ERROR,
600 channel_entry->channel_name);
604 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
605 SILCTXT_CH_PRIVATE_KEY_ADD,
606 channel_entry->channel_name);
614 if (!strcasecmp(argv[3], "unset")) {
617 if (type == 1 && client_entry) {
618 /* Unset private message key */
619 silc_client_del_private_message_key(silc_client, conn, client_entry);
620 } else if (type == 2) {
621 /* Unset channel key(s) */
622 SilcChannelPrivateKey *keys;
623 SilcUInt32 keys_count;
627 silc_client_del_channel_private_keys(silc_client, conn,
631 number = atoi(argv[4]);
632 keys = silc_client_list_channel_private_keys(silc_client, conn,
638 if (!number || number > keys_count) {
639 silc_client_free_channel_private_keys(keys, keys_count);
643 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
645 silc_client_free_channel_private_keys(keys, keys_count);
653 if (!strcasecmp(argv[3], "list")) {
657 SilcPrivateMessageKeys keys;
658 SilcUInt32 keys_count;
662 keys = silc_client_list_private_message_keys(silc_client, conn,
667 /* list the private message key(s) */
668 if (nickname[0] == '*') {
669 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
670 SILCTXT_PRIVATE_KEY_LIST);
671 for (k = 0; k < keys_count; k++) {
672 memset(buf, 0, sizeof(buf));
673 strncat(buf, " ", 2);
674 len = strlen(keys[k].client_entry->nickname);
675 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
677 for (i = 0; i < 30 - len; i++)
681 len = strlen(keys[k].cipher);
682 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
684 for (i = 0; i < 14 - len; i++)
689 strcat(buf, "<hidden>");
691 strcat(buf, "*generated*");
693 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
696 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
697 SILCTXT_PRIVATE_KEY_LIST_NICK,
698 client_entry->nickname);
699 for (k = 0; k < keys_count; k++) {
700 if (keys[k].client_entry != client_entry)
703 memset(buf, 0, sizeof(buf));
704 strncat(buf, " ", 2);
705 len = strlen(keys[k].client_entry->nickname);
706 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
708 for (i = 0; i < 30 - len; i++)
712 len = strlen(keys[k].cipher);
713 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
715 for (i = 0; i < 14 - len; i++)
720 strcat(buf, "<hidden>");
722 strcat(buf, "*generated*");
724 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
728 silc_client_free_private_message_keys(keys, keys_count);
730 } else if (type == 2) {
731 SilcChannelPrivateKey *keys;
732 SilcUInt32 keys_count;
736 keys = silc_client_list_channel_private_keys(silc_client, conn,
740 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
741 SILCTXT_CH_PRIVATE_KEY_LIST,
742 channel_entry->channel_name);
747 for (k = 0; k < keys_count; k++) {
748 memset(buf, 0, sizeof(buf));
749 strncat(buf, " ", 2);
751 len = strlen(keys[k]->cipher->cipher->name);
752 strncat(buf, keys[k]->cipher->cipher->name, len > 16 ? 16 : len);
754 for (i = 0; i < 16 - len; i++)
758 len = strlen(silc_hmac_get_name(keys[k]->hmac));
759 strncat(buf, silc_hmac_get_name(keys[k]->hmac), len > 16 ? 16 : len);
761 for (i = 0; i < 16 - len; i++)
765 strcat(buf, "<hidden>");
767 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
770 silc_client_free_channel_private_keys(keys, keys_count);
776 /* Send command is used to send key agreement */
777 if (!strcasecmp(argv[3], "agreement")) {
783 port = atoi(argv[5]);
785 internal = silc_calloc(1, sizeof(*internal));
786 internal->type = type;
787 internal->server = server;
790 if (settings_get_bool("use_auto_addr")) {
792 hostname = (char *)settings_get_str("auto_public_ip");
794 /* If the hostname isn't set, treat this case as if auto_public_ip
796 if ((hostname) && (*hostname == '\0')) {
799 bindhost = (char *)settings_get_str("auto_bind_ip");
801 /* if the bind_ip isn't set, but the public_ip IS, then assume then
802 public_ip is the same value as the bind_ip. */
803 if ((bindhost) && (*bindhost == '\0'))
805 port = settings_get_int("auto_bind_port");
807 } /* if use_auto_addr */
811 /* Start command is used to start key agreement (after receiving the
812 key_agreement client operation). */
813 if (!strcasecmp(argv[3], "negotiate")) {
819 port = atoi(argv[5]);
821 internal = silc_calloc(1, sizeof(*internal));
822 internal->type = type;
823 internal->server = server;
826 /* Change current channel private key */
827 if (!strcasecmp(argv[3], "change")) {
830 /* Unset channel key(s) */
831 SilcChannelPrivateKey *keys;
832 SilcUInt32 keys_count;
835 keys = silc_client_list_channel_private_keys(silc_client, conn,
843 if (chanrec->cur_key >= keys_count)
844 chanrec->cur_key = 0;
848 number = atoi(argv[4]);
849 if (!number || number > keys_count)
850 chanrec->cur_key = 0;
852 chanrec->cur_key = number - 1;
855 /* Set the current channel private key */
856 silc_client_current_channel_private_key(silc_client, conn,
858 keys[chanrec->cur_key]);
859 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
860 SILCTXT_CH_PRIVATE_KEY_CHANGE, chanrec->cur_key + 1,
861 channel_entry->channel_name);
863 silc_client_free_channel_private_keys(keys, keys_count);
869 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
870 "Usage: /KEY msg|channel <nickname|channel> "
871 "set|unset|agreement|negotiate [<arguments>]");
875 if (command == 4 && client_entry) {
876 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
877 SILCTXT_KEY_AGREEMENT, argv[2]);
878 internal->responder = TRUE;
879 silc_client_send_key_agreement(
880 silc_client, conn, client_entry, hostname,
882 settings_get_int("key_exchange_timeout_secs"),
883 keyagr_completion, internal);
889 if (command == 5 && client_entry && hostname) {
890 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
891 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
892 internal->responder = FALSE;
893 silc_client_perform_key_agreement(silc_client, conn, client_entry,
894 hostname, port, keyagr_completion,
903 /* Lists locally saved client and server public keys. */
905 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
911 void silc_channels_init(void)
913 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
914 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
915 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
917 command_bind_silc("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
918 command_bind_silc("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
919 command_bind_silc("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
920 command_bind_silc("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
921 command_bind_silc("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
922 command_bind_silc("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
923 command_bind_silc("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
925 silc_nicklist_init();
928 void silc_channels_deinit(void)
930 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
931 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
932 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
934 command_unbind("part", (SIGNAL_FUNC) command_part);
935 command_unbind("me", (SIGNAL_FUNC) command_me);
936 command_unbind("action", (SIGNAL_FUNC) command_action);
937 command_unbind("notice", (SIGNAL_FUNC) command_notice);
938 command_unbind("away", (SIGNAL_FUNC) command_away);
939 command_unbind("key", (SIGNAL_FUNC) command_key);
940 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
942 silc_nicklist_deinit();