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 server->usermode_away = set;
345 server->away_reason = g_strdup((char *)data);
346 signal_emit("away mode changed", 1, server);
348 silc_command_exec(server, "UMODE", set ? "+g" : "-g");
352 int type; /* 1 = msg, 2 = channel */
354 SILC_SERVER_REC *server;
357 /* Key agreement callback that is called after the key agreement protocol
358 has been performed. This is called also if error occured during the
359 key agreement protocol. The `key' is the allocated key material and
360 the caller is responsible of freeing it. The `key' is NULL if error
361 has occured. The application can freely use the `key' to whatever
362 purpose it needs. See lib/silcske/silcske.h for the definition of
363 the SilcSKEKeyMaterial structure. */
365 static void keyagr_completion(SilcClient client,
366 SilcClientConnection conn,
367 SilcClientEntry client_entry,
368 SilcKeyAgreementStatus status,
369 SilcSKEKeyMaterial *key,
372 KeyInternal i = (KeyInternal)context;
375 case SILC_KEY_AGREEMENT_OK:
376 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
377 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
380 /* Set the private key for this client */
381 silc_client_del_private_message_key(client, conn, client_entry);
382 silc_client_add_private_message_key_ske(client, conn, client_entry,
383 NULL, key, i->responder);
384 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
385 SILCTXT_KEY_AGREEMENT_PRIVMSG,
386 client_entry->nickname);
387 silc_ske_free_key_material(key);
392 case SILC_KEY_AGREEMENT_ERROR:
393 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
394 SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
397 case SILC_KEY_AGREEMENT_FAILURE:
398 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
399 SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
402 case SILC_KEY_AGREEMENT_TIMEOUT:
403 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
404 SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
407 case SILC_KEY_AGREEMENT_ABORTED:
408 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
409 SILCTXT_KEY_AGREEMENT_ABORTED, client_entry->nickname);
412 case SILC_KEY_AGREEMENT_ALREADY_STARTED:
413 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
414 SILCTXT_KEY_AGREEMENT_ALREADY_STARTED,
415 client_entry->nickname);
418 case SILC_KEY_AGREEMENT_SELF_DENIED:
419 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
420 SILCTXT_KEY_AGREEMENT_SELF_DENIED);
431 /* Local command KEY. This command is used to set and unset private
432 keys for channels, set and unset private keys for private messages
433 with remote clients and to send key agreement requests and
434 negotiate the key agreement protocol with remote client. The
435 key agreement is supported only to negotiate private message keys,
436 it currently cannot be used to negotiate private keys for channels,
437 as it is not convenient for that purpose. */
440 SILC_SERVER_REC *server;
446 /* Callback to be called after client information is resolved from the
449 static void silc_client_command_key_get_clients(SilcClient client,
450 SilcClientConnection conn,
451 SilcClientEntry *clients,
452 SilcUInt32 clients_count,
455 KeyGetClients internal = (KeyGetClients)context;
458 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s",
460 silc_free(internal->data);
461 silc_free(internal->nick);
466 signal_emit("command key", 3, internal->data, internal->server,
469 silc_free(internal->data);
470 silc_free(internal->nick);
474 static void command_key(const char *data, SILC_SERVER_REC *server,
477 SilcClientConnection conn;
478 SilcClientEntry *entrys, client_entry = NULL;
479 SilcUInt32 entry_count;
480 SILC_CHANNEL_REC *chanrec = NULL;
481 SilcChannelEntry channel_entry = NULL;
482 char *nickname = NULL, *tmp;
483 int command = 0, port = 0, type = 0;
484 char *hostname = NULL;
485 KeyInternal internal = NULL;
487 unsigned char **argv;
488 SilcUInt32 *argv_lens, *argv_types;
489 char *bindhost = NULL;
491 CMD_SILC_SERVER(server);
493 if (!server || !IS_SILC_SERVER(server) || !server->connected)
494 cmd_return_error(CMDERR_NOT_CONNECTED);
498 /* Now parse all arguments */
499 tmp = g_strconcat("KEY", " ", data, NULL);
500 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
504 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
507 if (!strcasecmp(argv[1], "msg"))
509 if (!strcasecmp(argv[1], "channel"))
513 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
516 if (argv[2][0] == '*') {
517 nickname = strdup("*");
519 /* Parse the typed nickname. */
520 if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
521 printformat_module("fe-common/silc", server, NULL,
522 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
526 /* Find client entry */
527 entrys = silc_client_get_clients_local(silc_client, conn, nickname,
528 argv[2], &entry_count);
530 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
531 inter->server = server;
532 inter->data = strdup(data);
533 inter->nick = strdup(nickname);
535 silc_client_get_clients(silc_client, conn, nickname, argv[2],
536 silc_client_command_key_get_clients, inter);
539 client_entry = entrys[0];
545 /* Get channel entry */
548 if (argv[2][0] == '*') {
549 if (!conn->current_channel) {
551 cmd_return_error(CMDERR_NOT_JOINED);
553 name = conn->current_channel->channel_name;
558 chanrec = silc_channel_find(server, name);
559 if (chanrec == NULL) {
561 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
563 channel_entry = chanrec->entry;
567 if (!strcasecmp(argv[3], "set")) {
571 if (type == 1 && client_entry) {
572 /* Set private message key */
574 silc_client_del_private_message_key(silc_client, conn, client_entry);
577 silc_client_add_private_message_key(silc_client, conn, client_entry,
581 TRUE : FALSE), FALSE);
583 silc_client_add_private_message_key(silc_client, conn, client_entry,
587 TRUE : FALSE), FALSE);
589 /* Send the key to the remote client so that it starts using it
591 silc_client_send_private_message_key(silc_client, conn,
593 } else if (type == 2) {
594 /* Set private channel key */
595 char *cipher = NULL, *hmac = NULL;
597 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
598 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
599 SILCTXT_CH_PRIVATE_KEY_NOMODE,
600 channel_entry->channel_name);
609 if (!silc_client_add_channel_private_key(silc_client, conn,
614 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
615 SILCTXT_CH_PRIVATE_KEY_ERROR,
616 channel_entry->channel_name);
620 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
621 SILCTXT_CH_PRIVATE_KEY_ADD,
622 channel_entry->channel_name);
630 if (!strcasecmp(argv[3], "unset")) {
633 if (type == 1 && client_entry) {
634 /* Unset private message key */
635 silc_client_del_private_message_key(silc_client, conn, client_entry);
636 } else if (type == 2) {
637 /* Unset channel key(s) */
638 SilcChannelPrivateKey *keys;
639 SilcUInt32 keys_count;
643 silc_client_del_channel_private_keys(silc_client, conn,
647 number = atoi(argv[4]);
648 keys = silc_client_list_channel_private_keys(silc_client, conn,
654 if (!number || number > keys_count) {
655 silc_client_free_channel_private_keys(keys, keys_count);
659 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
661 silc_client_free_channel_private_keys(keys, keys_count);
669 if (!strcasecmp(argv[3], "list")) {
673 SilcPrivateMessageKeys keys;
674 SilcUInt32 keys_count;
678 keys = silc_client_list_private_message_keys(silc_client, conn,
683 /* list the private message key(s) */
684 if (nickname[0] == '*') {
685 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
686 SILCTXT_PRIVATE_KEY_LIST);
687 for (k = 0; k < keys_count; k++) {
688 memset(buf, 0, sizeof(buf));
689 strncat(buf, " ", 2);
690 len = strlen(keys[k].client_entry->nickname);
691 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
693 for (i = 0; i < 30 - len; i++)
697 len = strlen(keys[k].cipher);
698 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
700 for (i = 0; i < 14 - len; i++)
705 strcat(buf, "<hidden>");
707 strcat(buf, "*generated*");
709 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
712 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
713 SILCTXT_PRIVATE_KEY_LIST_NICK,
714 client_entry->nickname);
715 for (k = 0; k < keys_count; k++) {
716 if (keys[k].client_entry != client_entry)
719 memset(buf, 0, sizeof(buf));
720 strncat(buf, " ", 2);
721 len = strlen(keys[k].client_entry->nickname);
722 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
724 for (i = 0; i < 30 - len; i++)
728 len = strlen(keys[k].cipher);
729 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
731 for (i = 0; i < 14 - len; i++)
736 strcat(buf, "<hidden>");
738 strcat(buf, "*generated*");
740 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
744 silc_client_free_private_message_keys(keys, keys_count);
746 } else if (type == 2) {
747 SilcChannelPrivateKey *keys;
748 SilcUInt32 keys_count;
752 keys = silc_client_list_channel_private_keys(silc_client, conn,
756 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
757 SILCTXT_CH_PRIVATE_KEY_LIST,
758 channel_entry->channel_name);
763 for (k = 0; k < keys_count; k++) {
764 memset(buf, 0, sizeof(buf));
765 strncat(buf, " ", 2);
767 len = strlen(keys[k]->cipher->cipher->name);
768 strncat(buf, keys[k]->cipher->cipher->name, len > 16 ? 16 : len);
770 for (i = 0; i < 16 - len; i++)
774 len = strlen(silc_hmac_get_name(keys[k]->hmac));
775 strncat(buf, silc_hmac_get_name(keys[k]->hmac), len > 16 ? 16 : len);
777 for (i = 0; i < 16 - len; i++)
781 strcat(buf, "<hidden>");
783 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
786 silc_client_free_channel_private_keys(keys, keys_count);
792 /* Send command is used to send key agreement */
793 if (!strcasecmp(argv[3], "agreement")) {
799 port = atoi(argv[5]);
801 internal = silc_calloc(1, sizeof(*internal));
802 internal->type = type;
803 internal->server = server;
806 if (settings_get_bool("use_auto_addr")) {
808 hostname = (char *)settings_get_str("auto_public_ip");
810 /* If the hostname isn't set, treat this case as if auto_public_ip
812 if ((hostname) && (*hostname == '\0')) {
815 bindhost = (char *)settings_get_str("auto_bind_ip");
817 /* if the bind_ip isn't set, but the public_ip IS, then assume then
818 public_ip is the same value as the bind_ip. */
819 if ((bindhost) && (*bindhost == '\0'))
821 port = settings_get_int("auto_bind_port");
823 } /* if use_auto_addr */
827 /* Start command is used to start key agreement (after receiving the
828 key_agreement client operation). */
829 if (!strcasecmp(argv[3], "negotiate")) {
835 port = atoi(argv[5]);
837 internal = silc_calloc(1, sizeof(*internal));
838 internal->type = type;
839 internal->server = server;
842 /* Change current channel private key */
843 if (!strcasecmp(argv[3], "change")) {
846 /* Unset channel key(s) */
847 SilcChannelPrivateKey *keys;
848 SilcUInt32 keys_count;
851 keys = silc_client_list_channel_private_keys(silc_client, conn,
859 if (chanrec->cur_key >= keys_count)
860 chanrec->cur_key = 0;
864 number = atoi(argv[4]);
865 if (!number || number > keys_count)
866 chanrec->cur_key = 0;
868 chanrec->cur_key = number - 1;
871 /* Set the current channel private key */
872 silc_client_current_channel_private_key(silc_client, conn,
874 keys[chanrec->cur_key]);
875 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
876 SILCTXT_CH_PRIVATE_KEY_CHANGE, chanrec->cur_key + 1,
877 channel_entry->channel_name);
879 silc_client_free_channel_private_keys(keys, keys_count);
885 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
886 "Usage: /KEY msg|channel <nickname|channel> "
887 "set|unset|agreement|negotiate [<arguments>]");
891 if (command == 4 && client_entry) {
892 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
893 SILCTXT_KEY_AGREEMENT, argv[2]);
894 internal->responder = TRUE;
895 silc_client_send_key_agreement(
896 silc_client, conn, client_entry, hostname,
898 settings_get_int("key_exchange_timeout_secs"),
899 keyagr_completion, internal);
905 if (command == 5 && client_entry && hostname) {
906 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
907 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
908 internal->responder = FALSE;
909 silc_client_perform_key_agreement(silc_client, conn, client_entry,
910 hostname, port, keyagr_completion,
919 /* Lists locally saved client and server public keys. */
921 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
927 void silc_channels_init(void)
929 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
930 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
931 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
933 command_bind_silc("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
934 command_bind_silc("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
935 command_bind_silc("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
936 command_bind_silc("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
937 command_bind_silc("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
938 command_bind_silc("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
939 command_bind_silc("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
941 silc_nicklist_init();
944 void silc_channels_deinit(void)
946 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
947 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
948 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
950 command_unbind("part", (SIGNAL_FUNC) command_part);
951 command_unbind("me", (SIGNAL_FUNC) command_me);
952 command_unbind("action", (SIGNAL_FUNC) command_action);
953 command_unbind("notice", (SIGNAL_FUNC) command_notice);
954 command_unbind("away", (SIGNAL_FUNC) command_away);
955 command_unbind("key", (SIGNAL_FUNC) command_key);
956 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
958 silc_nicklist_deinit();