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,
334 server->usermode_away = FALSE;
336 /* Set the away message */
337 silc_client_set_away_message(silc_client, server->conn, (char *)data);
340 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
341 SILCTXT_SET_AWAY, data);
342 server->usermode_away = TRUE;
345 signal_emit("away mode changed", 1, server);
347 silc_command_exec(server, "UMODE", set ? "+g" : "-g");
351 int type; /* 1 = msg, 2 = channel */
353 SILC_SERVER_REC *server;
356 /* Key agreement callback that is called after the key agreement protocol
357 has been performed. This is called also if error occured during the
358 key agreement protocol. The `key' is the allocated key material and
359 the caller is responsible of freeing it. The `key' is NULL if error
360 has occured. The application can freely use the `key' to whatever
361 purpose it needs. See lib/silcske/silcske.h for the definition of
362 the SilcSKEKeyMaterial structure. */
364 static void keyagr_completion(SilcClient client,
365 SilcClientConnection conn,
366 SilcClientEntry client_entry,
367 SilcKeyAgreementStatus status,
368 SilcSKEKeyMaterial *key,
371 KeyInternal i = (KeyInternal)context;
374 case SILC_KEY_AGREEMENT_OK:
375 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
376 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
379 /* Set the private key for this client */
380 silc_client_del_private_message_key(client, conn, client_entry);
381 silc_client_add_private_message_key_ske(client, conn, client_entry,
382 NULL, key, i->responder);
383 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
384 SILCTXT_KEY_AGREEMENT_PRIVMSG,
385 client_entry->nickname);
386 silc_ske_free_key_material(key);
391 case SILC_KEY_AGREEMENT_ERROR:
392 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
393 SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
396 case SILC_KEY_AGREEMENT_FAILURE:
397 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
398 SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
401 case SILC_KEY_AGREEMENT_TIMEOUT:
402 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
403 SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
406 case SILC_KEY_AGREEMENT_ABORTED:
407 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
408 SILCTXT_KEY_AGREEMENT_ABORTED, client_entry->nickname);
411 case SILC_KEY_AGREEMENT_ALREADY_STARTED:
412 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
413 SILCTXT_KEY_AGREEMENT_ALREADY_STARTED,
414 client_entry->nickname);
417 case SILC_KEY_AGREEMENT_SELF_DENIED:
418 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
419 SILCTXT_KEY_AGREEMENT_SELF_DENIED);
430 /* Local command KEY. This command is used to set and unset private
431 keys for channels, set and unset private keys for private messages
432 with remote clients and to send key agreement requests and
433 negotiate the key agreement protocol with remote client. The
434 key agreement is supported only to negotiate private message keys,
435 it currently cannot be used to negotiate private keys for channels,
436 as it is not convenient for that purpose. */
439 SILC_SERVER_REC *server;
445 /* Callback to be called after client information is resolved from the
448 static void silc_client_command_key_get_clients(SilcClient client,
449 SilcClientConnection conn,
450 SilcClientEntry *clients,
451 SilcUInt32 clients_count,
454 KeyGetClients internal = (KeyGetClients)context;
457 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s",
459 silc_free(internal->data);
460 silc_free(internal->nick);
465 signal_emit("command key", 3, internal->data, internal->server,
468 silc_free(internal->data);
469 silc_free(internal->nick);
473 static void command_key(const char *data, SILC_SERVER_REC *server,
476 SilcClientConnection conn;
477 SilcClientEntry *entrys, client_entry = NULL;
478 SilcUInt32 entry_count;
479 SILC_CHANNEL_REC *chanrec = NULL;
480 SilcChannelEntry channel_entry = NULL;
481 char *nickname = NULL, *tmp;
482 int command = 0, port = 0, type = 0;
483 char *hostname = NULL;
484 KeyInternal internal = NULL;
486 unsigned char **argv;
487 SilcUInt32 *argv_lens, *argv_types;
488 char *bindhost = NULL;
490 CMD_SILC_SERVER(server);
492 if (!server || !IS_SILC_SERVER(server) || !server->connected)
493 cmd_return_error(CMDERR_NOT_CONNECTED);
497 /* Now parse all arguments */
498 tmp = g_strconcat("KEY", " ", data, NULL);
499 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
503 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
506 if (!strcasecmp(argv[1], "msg"))
508 if (!strcasecmp(argv[1], "channel"))
512 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
515 if (argv[2][0] == '*') {
516 nickname = strdup("*");
518 /* Parse the typed nickname. */
519 if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
520 printformat_module("fe-common/silc", server, NULL,
521 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
525 /* Find client entry */
526 entrys = silc_client_get_clients_local(silc_client, conn, nickname,
527 argv[2], &entry_count);
529 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
530 inter->server = server;
531 inter->data = strdup(data);
532 inter->nick = strdup(nickname);
534 silc_client_get_clients(silc_client, conn, nickname, argv[2],
535 silc_client_command_key_get_clients, inter);
538 client_entry = entrys[0];
544 /* Get channel entry */
547 if (argv[2][0] == '*') {
548 if (!conn->current_channel) {
550 cmd_return_error(CMDERR_NOT_JOINED);
552 name = conn->current_channel->channel_name;
557 chanrec = silc_channel_find(server, name);
558 if (chanrec == NULL) {
560 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
562 channel_entry = chanrec->entry;
566 if (!strcasecmp(argv[3], "set")) {
570 if (type == 1 && client_entry) {
571 /* Set private message key */
573 silc_client_del_private_message_key(silc_client, conn, client_entry);
576 silc_client_add_private_message_key(silc_client, conn, client_entry,
580 TRUE : FALSE), FALSE);
582 silc_client_add_private_message_key(silc_client, conn, client_entry,
586 TRUE : FALSE), FALSE);
588 /* Send the key to the remote client so that it starts using it
590 silc_client_send_private_message_key(silc_client, conn,
592 } else if (type == 2) {
593 /* Set private channel key */
594 char *cipher = NULL, *hmac = NULL;
596 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
597 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
598 SILCTXT_CH_PRIVATE_KEY_NOMODE,
599 channel_entry->channel_name);
608 if (!silc_client_add_channel_private_key(silc_client, conn,
613 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
614 SILCTXT_CH_PRIVATE_KEY_ERROR,
615 channel_entry->channel_name);
619 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
620 SILCTXT_CH_PRIVATE_KEY_ADD,
621 channel_entry->channel_name);
629 if (!strcasecmp(argv[3], "unset")) {
632 if (type == 1 && client_entry) {
633 /* Unset private message key */
634 silc_client_del_private_message_key(silc_client, conn, client_entry);
635 } else if (type == 2) {
636 /* Unset channel key(s) */
637 SilcChannelPrivateKey *keys;
638 SilcUInt32 keys_count;
642 silc_client_del_channel_private_keys(silc_client, conn,
646 number = atoi(argv[4]);
647 keys = silc_client_list_channel_private_keys(silc_client, conn,
653 if (!number || number > keys_count) {
654 silc_client_free_channel_private_keys(keys, keys_count);
658 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
660 silc_client_free_channel_private_keys(keys, keys_count);
668 if (!strcasecmp(argv[3], "list")) {
672 SilcPrivateMessageKeys keys;
673 SilcUInt32 keys_count;
677 keys = silc_client_list_private_message_keys(silc_client, conn,
682 /* list the private message key(s) */
683 if (nickname[0] == '*') {
684 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
685 SILCTXT_PRIVATE_KEY_LIST);
686 for (k = 0; k < keys_count; k++) {
687 memset(buf, 0, sizeof(buf));
688 strncat(buf, " ", 2);
689 len = strlen(keys[k].client_entry->nickname);
690 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
692 for (i = 0; i < 30 - len; i++)
696 len = strlen(keys[k].cipher);
697 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
699 for (i = 0; i < 14 - len; i++)
704 strcat(buf, "<hidden>");
706 strcat(buf, "*generated*");
708 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
711 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
712 SILCTXT_PRIVATE_KEY_LIST_NICK,
713 client_entry->nickname);
714 for (k = 0; k < keys_count; k++) {
715 if (keys[k].client_entry != client_entry)
718 memset(buf, 0, sizeof(buf));
719 strncat(buf, " ", 2);
720 len = strlen(keys[k].client_entry->nickname);
721 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
723 for (i = 0; i < 30 - len; i++)
727 len = strlen(keys[k].cipher);
728 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
730 for (i = 0; i < 14 - len; i++)
735 strcat(buf, "<hidden>");
737 strcat(buf, "*generated*");
739 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
743 silc_client_free_private_message_keys(keys, keys_count);
745 } else if (type == 2) {
746 SilcChannelPrivateKey *keys;
747 SilcUInt32 keys_count;
751 keys = silc_client_list_channel_private_keys(silc_client, conn,
755 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
756 SILCTXT_CH_PRIVATE_KEY_LIST,
757 channel_entry->channel_name);
762 for (k = 0; k < keys_count; k++) {
763 memset(buf, 0, sizeof(buf));
764 strncat(buf, " ", 2);
766 len = strlen(keys[k]->cipher->cipher->name);
767 strncat(buf, keys[k]->cipher->cipher->name, len > 16 ? 16 : len);
769 for (i = 0; i < 16 - len; i++)
773 len = strlen(silc_hmac_get_name(keys[k]->hmac));
774 strncat(buf, silc_hmac_get_name(keys[k]->hmac), len > 16 ? 16 : len);
776 for (i = 0; i < 16 - len; i++)
780 strcat(buf, "<hidden>");
782 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
785 silc_client_free_channel_private_keys(keys, keys_count);
791 /* Send command is used to send key agreement */
792 if (!strcasecmp(argv[3], "agreement")) {
798 port = atoi(argv[5]);
800 internal = silc_calloc(1, sizeof(*internal));
801 internal->type = type;
802 internal->server = server;
805 if (settings_get_bool("use_auto_addr")) {
807 hostname = (char *)settings_get_str("auto_public_ip");
809 /* If the hostname isn't set, treat this case as if auto_public_ip
811 if ((hostname) && (*hostname == '\0')) {
814 bindhost = (char *)settings_get_str("auto_bind_ip");
816 /* if the bind_ip isn't set, but the public_ip IS, then assume then
817 public_ip is the same value as the bind_ip. */
818 if ((bindhost) && (*bindhost == '\0'))
820 port = settings_get_int("auto_bind_port");
822 } /* if use_auto_addr */
826 /* Start command is used to start key agreement (after receiving the
827 key_agreement client operation). */
828 if (!strcasecmp(argv[3], "negotiate")) {
834 port = atoi(argv[5]);
836 internal = silc_calloc(1, sizeof(*internal));
837 internal->type = type;
838 internal->server = server;
841 /* Change current channel private key */
842 if (!strcasecmp(argv[3], "change")) {
845 /* Unset channel key(s) */
846 SilcChannelPrivateKey *keys;
847 SilcUInt32 keys_count;
850 keys = silc_client_list_channel_private_keys(silc_client, conn,
858 if (chanrec->cur_key >= keys_count)
859 chanrec->cur_key = 0;
863 number = atoi(argv[4]);
864 if (!number || number > keys_count)
865 chanrec->cur_key = 0;
867 chanrec->cur_key = number - 1;
870 /* Set the current channel private key */
871 silc_client_current_channel_private_key(silc_client, conn,
873 keys[chanrec->cur_key]);
874 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
875 SILCTXT_CH_PRIVATE_KEY_CHANGE, chanrec->cur_key + 1,
876 channel_entry->channel_name);
878 silc_client_free_channel_private_keys(keys, keys_count);
884 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
885 "Usage: /KEY msg|channel <nickname|channel> "
886 "set|unset|agreement|negotiate [<arguments>]");
890 if (command == 4 && client_entry) {
891 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
892 SILCTXT_KEY_AGREEMENT, argv[2]);
893 internal->responder = TRUE;
894 silc_client_send_key_agreement(
895 silc_client, conn, client_entry, hostname,
897 settings_get_int("key_exchange_timeout_secs"),
898 keyagr_completion, internal);
904 if (command == 5 && client_entry && hostname) {
905 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
906 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
907 internal->responder = FALSE;
908 silc_client_perform_key_agreement(silc_client, conn, client_entry,
909 hostname, port, keyagr_completion,
918 /* Lists locally saved client and server public keys. */
920 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
926 void silc_channels_init(void)
928 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
929 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
930 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
932 command_bind_silc("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
933 command_bind_silc("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
934 command_bind_silc("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
935 command_bind_silc("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
936 command_bind_silc("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
937 command_bind_silc("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
938 command_bind_silc("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
940 silc_nicklist_init();
943 void silc_channels_deinit(void)
945 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
946 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
947 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
949 command_unbind("part", (SIGNAL_FUNC) command_part);
950 command_unbind("me", (SIGNAL_FUNC) command_me);
951 command_unbind("action", (SIGNAL_FUNC) command_action);
952 command_unbind("notice", (SIGNAL_FUNC) command_notice);
953 command_unbind("away", (SIGNAL_FUNC) command_away);
954 command_unbind("key", (SIGNAL_FUNC) command_key);
955 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
957 silc_nicklist_deinit();