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))
69 if (channel->server && channel->server->disconnected)
72 if (channel->server != NULL && !channel->left && !channel->kicked) {
73 /* destroying channel record without actually
74 having left the channel yet */
75 silc_command_exec(channel->server, "LEAVE", channel->name);
79 static void silc_channels_join(SILC_SERVER_REC *server,
80 const char *channels, int automatic)
83 SILC_CHANNEL_REC *chanrec;
85 list = g_strsplit(channels, ",", -1);
86 for (tmp = list; *tmp != NULL; tmp++) {
87 chanrec = silc_channel_find(server, *tmp);
91 silc_command_exec(server, "JOIN", *tmp);
97 static void sig_connected(SILC_SERVER_REC *server)
99 if (IS_SILC_SERVER(server))
100 server->channels_join = (void *) silc_channels_join;
103 /* "server quit" signal from the core to indicate that QUIT command
106 static void sig_server_quit(SILC_SERVER_REC *server, const char *msg)
108 if (IS_SILC_SERVER(server) && server->conn && server->conn->sock)
109 silc_command_exec(server, "QUIT", msg);
112 /* Find Irssi channel entry by SILC channel entry */
114 SILC_CHANNEL_REC *silc_channel_find_entry(SILC_SERVER_REC *server,
115 SilcChannelEntry entry)
119 g_return_val_if_fail(IS_SILC_SERVER(server), NULL);
121 for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
122 SILC_CHANNEL_REC *rec = tmp->data;
124 if (rec->entry == entry)
131 /* PART (LEAVE) command. */
133 static void command_part(const char *data, SILC_SERVER_REC *server,
136 SILC_CHANNEL_REC *chanrec;
139 CMD_SILC_SERVER(server);
141 if (!IS_SILC_SERVER(server) || !server->connected)
142 cmd_return_error(CMDERR_NOT_CONNECTED);
144 if (!strcmp(data, "*") || *data == '\0') {
145 if (!IS_SILC_CHANNEL(item))
146 cmd_return_error(CMDERR_NOT_JOINED);
150 chanrec = silc_channel_find(server, data);
152 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
154 memset(userhost, 0, sizeof(userhost));
155 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
156 server->conn->local_entry->username,
157 server->conn->local_entry->hostname);
158 signal_emit("message part", 5, server, chanrec->name,
159 server->nick, userhost, "");
161 chanrec->left = TRUE;
162 silc_command_exec(server, "LEAVE", chanrec->name);
165 channel_destroy(CHANNEL(chanrec));
168 /* ME local command. */
170 static void command_me(const char *data, SILC_SERVER_REC *server,
173 SILC_CHANNEL_REC *chanrec;
174 char *tmpcmd = "ME", *tmp;
176 unsigned char **argv;
177 SilcUInt32 *argv_lens, *argv_types;
180 CMD_SILC_SERVER(server);
182 if (!IS_SILC_SERVER(server) || !server->connected)
183 cmd_return_error(CMDERR_NOT_CONNECTED);
185 if (!IS_SILC_CHANNEL(item))
186 cmd_return_error(CMDERR_NOT_JOINED);
188 /* Now parse all arguments */
189 tmp = g_strconcat(tmpcmd, " ", data, NULL);
190 silc_parse_command_line(tmp, &argv, &argv_lens,
191 &argv_types, &argc, 2);
195 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
197 chanrec = silc_channel_find(server, item->name);
199 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
201 /* Send the action message */
202 silc_client_send_channel_message(silc_client, server->conn,
203 chanrec->entry, NULL,
204 SILC_MESSAGE_FLAG_ACTION,
205 argv[1], argv_lens[1], TRUE);
207 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
208 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
209 server->conn->local_entry->nickname, argv[1]);
211 for (i = 0; i < argc; i++)
213 silc_free(argv_lens);
214 silc_free(argv_types);
217 /* ACTION local command. Same as ME but takes the channel as mandatory
220 static void command_action(const char *data, SILC_SERVER_REC *server,
223 SILC_CHANNEL_REC *chanrec;
224 char *tmpcmd = "ME", *tmp;
226 unsigned char **argv;
227 SilcUInt32 *argv_lens, *argv_types;
230 CMD_SILC_SERVER(server);
231 if (!IS_SILC_SERVER(server) || !server->connected)
232 cmd_return_error(CMDERR_NOT_CONNECTED);
234 if (!IS_SILC_CHANNEL(item))
235 cmd_return_error(CMDERR_NOT_JOINED);
237 /* Now parse all arguments */
238 tmp = g_strconcat(tmpcmd, " ", data, NULL);
239 silc_parse_command_line(tmp, &argv, &argv_lens,
240 &argv_types, &argc, 3);
244 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
246 chanrec = silc_channel_find(server, argv[1]);
248 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
250 /* Send the action message */
251 silc_client_send_channel_message(silc_client, server->conn,
252 chanrec->entry, NULL,
253 SILC_MESSAGE_FLAG_ACTION,
254 argv[2], argv_lens[2], TRUE);
256 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
257 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
258 server->conn->local_entry->nickname, argv[2]);
260 for (i = 0; i < argc; i++)
262 silc_free(argv_lens);
263 silc_free(argv_types);
266 /* NOTICE local command. */
268 static void command_notice(const char *data, SILC_SERVER_REC *server,
271 SILC_CHANNEL_REC *chanrec;
272 char *tmpcmd = "ME", *tmp;
274 unsigned char **argv;
275 SilcUInt32 *argv_lens, *argv_types;
278 CMD_SILC_SERVER(server);
279 if (!IS_SILC_SERVER(server) || !server->connected)
280 cmd_return_error(CMDERR_NOT_CONNECTED);
282 if (!IS_SILC_CHANNEL(item))
283 cmd_return_error(CMDERR_NOT_JOINED);
285 /* Now parse all arguments */
286 tmp = g_strconcat(tmpcmd, " ", data, NULL);
287 silc_parse_command_line(tmp, &argv, &argv_lens,
288 &argv_types, &argc, 2);
292 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
294 chanrec = silc_channel_find(server, item->name);
296 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
298 /* Send the action message */
299 silc_client_send_channel_message(silc_client, server->conn,
300 chanrec->entry, NULL,
301 SILC_MESSAGE_FLAG_NOTICE,
302 argv[1], argv_lens[1], TRUE);
304 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
305 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_OWNNOTICE,
306 server->conn->local_entry->nickname, argv[1]);
308 for (i = 0; i < argc; i++)
310 silc_free(argv_lens);
311 silc_free(argv_types);
314 /* AWAY local command. Sends UMODE command that sets the SILC_UMODE_GONE
317 static void command_away(const char *data, SILC_SERVER_REC *server,
322 CMD_SILC_SERVER(server);
324 if (!IS_SILC_SERVER(server) || !server->connected)
325 cmd_return_error(CMDERR_NOT_CONNECTED);
328 /* Remove any possible away message */
329 silc_client_set_away_message(silc_client, server->conn, NULL);
332 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
335 /* Set the away message */
336 silc_client_set_away_message(silc_client, server->conn, (char *)data);
339 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
340 SILCTXT_SET_AWAY, data);
343 signal_emit("away mode changed", 1, server);
345 silc_command_exec(server, "UMODE", set ? "+g" : "-g");
349 int type; /* 1 = msg, 2 = channel */
351 SILC_SERVER_REC *server;
354 /* Key agreement callback that is called after the key agreement protocol
355 has been performed. This is called also if error occured during the
356 key agreement protocol. The `key' is the allocated key material and
357 the caller is responsible of freeing it. The `key' is NULL if error
358 has occured. The application can freely use the `key' to whatever
359 purpose it needs. See lib/silcske/silcske.h for the definition of
360 the SilcSKEKeyMaterial structure. */
362 static void keyagr_completion(SilcClient client,
363 SilcClientConnection conn,
364 SilcClientEntry client_entry,
365 SilcKeyAgreementStatus status,
366 SilcSKEKeyMaterial *key,
369 KeyInternal i = (KeyInternal)context;
372 case SILC_KEY_AGREEMENT_OK:
373 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
374 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
377 /* Set the private key for this client */
378 silc_client_del_private_message_key(client, conn, client_entry);
379 silc_client_add_private_message_key_ske(client, conn, client_entry,
380 NULL, key, i->responder);
381 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
382 SILCTXT_KEY_AGREEMENT_PRIVMSG,
383 client_entry->nickname);
384 silc_ske_free_key_material(key);
389 case SILC_KEY_AGREEMENT_ERROR:
390 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
391 SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
394 case SILC_KEY_AGREEMENT_FAILURE:
395 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
396 SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
399 case SILC_KEY_AGREEMENT_TIMEOUT:
400 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
401 SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
404 case SILC_KEY_AGREEMENT_ABORTED:
405 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
406 SILCTXT_KEY_AGREEMENT_ABORTED, client_entry->nickname);
417 /* Local command KEY. This command is used to set and unset private
418 keys for channels, set and unset private keys for private messages
419 with remote clients and to send key agreement requests and
420 negotiate the key agreement protocol with remote client. The
421 key agreement is supported only to negotiate private message keys,
422 it currently cannot be used to negotiate private keys for channels,
423 as it is not convenient for that purpose. */
426 SILC_SERVER_REC *server;
432 /* Callback to be called after client information is resolved from the
435 static void silc_client_command_key_get_clients(SilcClient client,
436 SilcClientConnection conn,
437 SilcClientEntry *clients,
438 SilcUInt32 clients_count,
441 KeyGetClients internal = (KeyGetClients)context;
444 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s",
446 silc_free(internal->data);
447 silc_free(internal->nick);
452 signal_emit("command key", 3, internal->data, internal->server,
455 silc_free(internal->data);
456 silc_free(internal->nick);
460 static void command_key(const char *data, SILC_SERVER_REC *server,
463 SilcClientConnection conn;
464 SilcClientEntry *entrys, client_entry = NULL;
465 SilcUInt32 entry_count;
466 SILC_CHANNEL_REC *chanrec = NULL;
467 SilcChannelEntry channel_entry = NULL;
468 char *nickname = NULL, *tmp;
469 int command = 0, port = 0, type = 0;
470 char *hostname = NULL;
471 KeyInternal internal = NULL;
473 unsigned char **argv;
474 SilcUInt32 *argv_lens, *argv_types;
475 char *bindhost = NULL;
477 CMD_SILC_SERVER(server);
479 if (!server || !IS_SILC_SERVER(server) || !server->connected)
480 cmd_return_error(CMDERR_NOT_CONNECTED);
484 /* Now parse all arguments */
485 tmp = g_strconcat("KEY", " ", data, NULL);
486 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
490 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
493 if (!strcasecmp(argv[1], "msg"))
495 if (!strcasecmp(argv[1], "channel"))
499 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
502 if (argv[2][0] == '*') {
503 nickname = strdup("*");
505 /* Parse the typed nickname. */
506 if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
507 printformat_module("fe-common/silc", server, NULL,
508 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
512 /* Find client entry */
513 entrys = silc_client_get_clients_local(silc_client, conn, nickname,
514 argv[2], &entry_count);
516 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
517 inter->server = server;
518 inter->data = strdup(data);
519 inter->nick = strdup(nickname);
521 silc_client_get_clients(silc_client, conn, nickname, argv[2],
522 silc_client_command_key_get_clients, inter);
525 client_entry = entrys[0];
531 /* Get channel entry */
534 if (argv[2][0] == '*') {
535 if (!conn->current_channel) {
537 cmd_return_error(CMDERR_NOT_JOINED);
539 name = conn->current_channel->channel_name;
544 chanrec = silc_channel_find(server, name);
545 if (chanrec == NULL) {
547 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
549 channel_entry = chanrec->entry;
553 if (!strcasecmp(argv[3], "set")) {
557 if (type == 1 && client_entry) {
558 /* Set private message key */
560 silc_client_del_private_message_key(silc_client, conn, client_entry);
563 silc_client_add_private_message_key(silc_client, conn, client_entry,
567 TRUE : FALSE), FALSE);
569 silc_client_add_private_message_key(silc_client, conn, client_entry,
573 TRUE : FALSE), FALSE);
575 /* Send the key to the remote client so that it starts using it
577 silc_client_send_private_message_key(silc_client, conn,
579 } else if (type == 2) {
580 /* Set private channel key */
581 char *cipher = NULL, *hmac = NULL;
583 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
584 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
585 SILCTXT_CH_PRIVATE_KEY_NOMODE,
586 channel_entry->channel_name);
595 if (!silc_client_add_channel_private_key(silc_client, conn,
600 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
601 SILCTXT_CH_PRIVATE_KEY_ERROR,
602 channel_entry->channel_name);
606 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
607 SILCTXT_CH_PRIVATE_KEY_ADD,
608 channel_entry->channel_name);
616 if (!strcasecmp(argv[3], "unset")) {
619 if (type == 1 && client_entry) {
620 /* Unset private message key */
621 silc_client_del_private_message_key(silc_client, conn, client_entry);
622 } else if (type == 2) {
623 /* Unset channel key(s) */
624 SilcChannelPrivateKey *keys;
625 SilcUInt32 keys_count;
629 silc_client_del_channel_private_keys(silc_client, conn,
633 number = atoi(argv[4]);
634 keys = silc_client_list_channel_private_keys(silc_client, conn,
640 if (!number || number > keys_count) {
641 silc_client_free_channel_private_keys(keys, keys_count);
645 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
647 silc_client_free_channel_private_keys(keys, keys_count);
655 if (!strcasecmp(argv[3], "list")) {
659 SilcPrivateMessageKeys keys;
660 SilcUInt32 keys_count;
664 keys = silc_client_list_private_message_keys(silc_client, conn,
669 /* list the private message key(s) */
670 if (nickname[0] == '*') {
671 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
672 SILCTXT_PRIVATE_KEY_LIST);
673 for (k = 0; k < keys_count; k++) {
674 memset(buf, 0, sizeof(buf));
675 strncat(buf, " ", 2);
676 len = strlen(keys[k].client_entry->nickname);
677 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
679 for (i = 0; i < 30 - len; i++)
683 len = strlen(keys[k].cipher);
684 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
686 for (i = 0; i < 14 - len; i++)
691 strcat(buf, "<hidden>");
693 strcat(buf, "*generated*");
695 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
698 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
699 SILCTXT_PRIVATE_KEY_LIST_NICK,
700 client_entry->nickname);
701 for (k = 0; k < keys_count; k++) {
702 if (keys[k].client_entry != client_entry)
705 memset(buf, 0, sizeof(buf));
706 strncat(buf, " ", 2);
707 len = strlen(keys[k].client_entry->nickname);
708 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
710 for (i = 0; i < 30 - len; i++)
714 len = strlen(keys[k].cipher);
715 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
717 for (i = 0; i < 14 - len; i++)
722 strcat(buf, "<hidden>");
724 strcat(buf, "*generated*");
726 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
730 silc_client_free_private_message_keys(keys, keys_count);
732 } else if (type == 2) {
733 SilcChannelPrivateKey *keys;
734 SilcUInt32 keys_count;
738 keys = silc_client_list_channel_private_keys(silc_client, conn,
742 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
743 SILCTXT_CH_PRIVATE_KEY_LIST,
744 channel_entry->channel_name);
749 for (k = 0; k < keys_count; k++) {
750 memset(buf, 0, sizeof(buf));
751 strncat(buf, " ", 2);
753 len = strlen(keys[k]->cipher->cipher->name);
754 strncat(buf, keys[k]->cipher->cipher->name, len > 16 ? 16 : len);
756 for (i = 0; i < 16 - len; i++)
760 len = strlen(silc_hmac_get_name(keys[k]->hmac));
761 strncat(buf, silc_hmac_get_name(keys[k]->hmac), len > 16 ? 16 : len);
763 for (i = 0; i < 16 - len; i++)
767 strcat(buf, "<hidden>");
769 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
772 silc_client_free_channel_private_keys(keys, keys_count);
778 /* Send command is used to send key agreement */
779 if (!strcasecmp(argv[3], "agreement")) {
785 port = atoi(argv[5]);
787 internal = silc_calloc(1, sizeof(*internal));
788 internal->type = type;
789 internal->server = server;
792 if (settings_get_bool("use_auto_addr")) {
794 hostname = (char *)settings_get_str("auto_public_ip");
796 /* If the hostname isn't set, treat this case as if auto_public_ip
798 if ((hostname) && (*hostname == '\0')) {
801 bindhost = (char *)settings_get_str("auto_bind_ip");
803 /* if the bind_ip isn't set, but the public_ip IS, then assume then
804 public_ip is the same value as the bind_ip. */
805 if ((bindhost) && (*bindhost == '\0'))
807 port = settings_get_int("auto_bind_port");
809 } /* if use_auto_addr */
813 /* Start command is used to start key agreement (after receiving the
814 key_agreement client operation). */
815 if (!strcasecmp(argv[3], "negotiate")) {
821 port = atoi(argv[5]);
823 internal = silc_calloc(1, sizeof(*internal));
824 internal->type = type;
825 internal->server = server;
828 /* Change current channel private key */
829 if (!strcasecmp(argv[3], "change")) {
832 /* Unset channel key(s) */
833 SilcChannelPrivateKey *keys;
834 SilcUInt32 keys_count;
837 keys = silc_client_list_channel_private_keys(silc_client, conn,
845 if (chanrec->cur_key >= keys_count)
846 chanrec->cur_key = 0;
850 number = atoi(argv[4]);
851 if (!number || number > keys_count)
852 chanrec->cur_key = 0;
854 chanrec->cur_key = number - 1;
857 /* Set the current channel private key */
858 silc_client_current_channel_private_key(silc_client, conn,
860 keys[chanrec->cur_key]);
861 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
862 SILCTXT_CH_PRIVATE_KEY_CHANGE, chanrec->cur_key + 1,
863 channel_entry->channel_name);
865 silc_client_free_channel_private_keys(keys, keys_count);
871 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
872 "Usage: /KEY msg|channel <nickname|channel> "
873 "set|unset|agreement|negotiate [<arguments>]");
877 if (command == 4 && client_entry) {
878 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
879 SILCTXT_KEY_AGREEMENT, argv[2]);
880 internal->responder = TRUE;
881 silc_client_send_key_agreement(
882 silc_client, conn, client_entry, hostname,
884 settings_get_int("key_exchange_timeout_secs"),
885 keyagr_completion, internal);
891 if (command == 5 && client_entry && hostname) {
892 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
893 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
894 internal->responder = FALSE;
895 silc_client_perform_key_agreement(silc_client, conn, client_entry,
896 hostname, port, keyagr_completion,
905 /* Lists locally saved client and server public keys. */
907 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
913 void silc_channels_init(void)
915 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
916 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
917 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
919 command_bind_silc("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
920 command_bind_silc("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
921 command_bind_silc("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
922 command_bind_silc("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
923 command_bind_silc("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
924 command_bind_silc("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
925 command_bind_silc("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
927 silc_nicklist_init();
930 void silc_channels_deinit(void)
932 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
933 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
934 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
936 command_unbind("part", (SIGNAL_FUNC) command_part);
937 command_unbind("me", (SIGNAL_FUNC) command_me);
938 command_unbind("action", (SIGNAL_FUNC) command_action);
939 command_unbind("notice", (SIGNAL_FUNC) command_notice);
940 command_unbind("away", (SIGNAL_FUNC) command_away);
941 command_unbind("key", (SIGNAL_FUNC) command_key);
942 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
944 silc_nicklist_deinit();