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 *message = NULL;
177 unsigned char **argv;
178 SilcUInt32 *argv_lens, *argv_types;
181 CMD_SILC_SERVER(server);
183 if (!IS_SILC_SERVER(server) || !server->connected)
184 cmd_return_error(CMDERR_NOT_CONNECTED);
186 if (!IS_SILC_CHANNEL(item))
187 cmd_return_error(CMDERR_NOT_JOINED);
189 /* Now parse all arguments */
190 tmp = g_strconcat(tmpcmd, " ", data, NULL);
191 silc_parse_command_line(tmp, &argv, &argv_lens,
192 &argv_types, &argc, 2);
196 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
198 chanrec = silc_channel_find(server, item->name);
200 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
202 if (!silc_term_utf8()) {
203 int len = silc_utf8_encoded_len(argv[1], argv_lens[1], SILC_STRING_ASCII);
204 message = silc_calloc(len + 1, sizeof(*message));
205 g_return_if_fail(message != NULL);
206 silc_utf8_encode(argv[1], argv_lens[1], SILC_STRING_ASCII, message, len);
209 /* Send the action message */
210 silc_client_send_channel_message(silc_client, server->conn,
211 chanrec->entry, NULL,
212 SILC_MESSAGE_FLAG_ACTION |
213 SILC_MESSAGE_FLAG_UTF8,
214 message ? message : argv[1],
215 message ? strlen(message) : argv_lens[1],
218 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
219 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
220 server->conn->local_entry->nickname, argv[1]);
222 for (i = 0; i < argc; i++)
224 silc_free(argv_lens);
225 silc_free(argv_types);
229 /* ACTION local command. Same as ME but takes the channel as mandatory
232 static void command_action(const char *data, SILC_SERVER_REC *server,
235 SILC_CHANNEL_REC *chanrec;
236 char *tmpcmd = "ME", *tmp;
238 unsigned char *message = NULL;
239 unsigned char **argv;
240 SilcUInt32 *argv_lens, *argv_types;
243 CMD_SILC_SERVER(server);
244 if (!IS_SILC_SERVER(server) || !server->connected)
245 cmd_return_error(CMDERR_NOT_CONNECTED);
247 if (!IS_SILC_CHANNEL(item))
248 cmd_return_error(CMDERR_NOT_JOINED);
250 /* Now parse all arguments */
251 tmp = g_strconcat(tmpcmd, " ", data, NULL);
252 silc_parse_command_line(tmp, &argv, &argv_lens,
253 &argv_types, &argc, 3);
257 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
259 chanrec = silc_channel_find(server, argv[1]);
261 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
263 if (!silc_term_utf8()) {
264 int len = silc_utf8_encoded_len(argv[2], argv_lens[2], SILC_STRING_ASCII);
265 message = silc_calloc(len + 1, sizeof(*message));
266 g_return_if_fail(message != NULL);
267 silc_utf8_encode(argv[2], argv_lens[2], SILC_STRING_ASCII, message, len);
270 /* Send the action message */
271 silc_client_send_channel_message(silc_client, server->conn,
272 chanrec->entry, NULL,
273 SILC_MESSAGE_FLAG_ACTION |
274 SILC_MESSAGE_FLAG_UTF8,
275 message ? message : argv[2],
276 message ? strlen(message) : argv_lens[2],
279 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
280 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
281 server->conn->local_entry->nickname, argv[2]);
283 for (i = 0; i < argc; i++)
285 silc_free(argv_lens);
286 silc_free(argv_types);
290 /* NOTICE local command. */
292 static void command_notice(const char *data, SILC_SERVER_REC *server,
295 SILC_CHANNEL_REC *chanrec;
296 char *tmpcmd = "ME", *tmp;
298 unsigned char *message = NULL;
299 unsigned char **argv;
300 SilcUInt32 *argv_lens, *argv_types;
303 CMD_SILC_SERVER(server);
304 if (!IS_SILC_SERVER(server) || !server->connected)
305 cmd_return_error(CMDERR_NOT_CONNECTED);
307 if (!IS_SILC_CHANNEL(item))
308 cmd_return_error(CMDERR_NOT_JOINED);
310 /* Now parse all arguments */
311 tmp = g_strconcat(tmpcmd, " ", data, NULL);
312 silc_parse_command_line(tmp, &argv, &argv_lens,
313 &argv_types, &argc, 2);
317 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
319 chanrec = silc_channel_find(server, item->name);
321 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
323 if (!silc_term_utf8()) {
324 int len = silc_utf8_encoded_len(argv[1], argv_lens[1], SILC_STRING_ASCII);
325 message = silc_calloc(len + 1, sizeof(*message));
326 g_return_if_fail(message != NULL);
327 silc_utf8_encode(argv[1], argv_lens[1], SILC_STRING_ASCII, message, len);
330 /* Send the action message */
331 silc_client_send_channel_message(silc_client, server->conn,
332 chanrec->entry, NULL,
333 SILC_MESSAGE_FLAG_NOTICE |
334 SILC_MESSAGE_FLAG_UTF8,
335 message ? message : argv[1],
336 message ? strlen(message) : argv_lens[1],
339 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
340 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_OWNNOTICE,
341 server->conn->local_entry->nickname, argv[1]);
343 for (i = 0; i < argc; i++)
345 silc_free(argv_lens);
346 silc_free(argv_types);
350 /* AWAY local command. Sends UMODE command that sets the SILC_UMODE_GONE
353 static void command_away(const char *data, SILC_SERVER_REC *server,
358 CMD_SILC_SERVER(server);
360 if (!IS_SILC_SERVER(server) || !server->connected)
361 cmd_return_error(CMDERR_NOT_CONNECTED);
364 /* Remove any possible away message */
365 silc_client_set_away_message(silc_client, server->conn, NULL);
368 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
371 /* Set the away message */
372 silc_client_set_away_message(silc_client, server->conn, (char *)data);
375 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
376 SILCTXT_SET_AWAY, data);
379 server->usermode_away = set;
381 server->away_reason = g_strdup((char *)data);
382 signal_emit("away mode changed", 1, server);
384 silc_command_exec(server, "UMODE", set ? "+g" : "-g");
388 int type; /* 1 = msg, 2 = channel */
390 SILC_SERVER_REC *server;
393 /* Key agreement callback that is called after the key agreement protocol
394 has been performed. This is called also if error occured during the
395 key agreement protocol. The `key' is the allocated key material and
396 the caller is responsible of freeing it. The `key' is NULL if error
397 has occured. The application can freely use the `key' to whatever
398 purpose it needs. See lib/silcske/silcske.h for the definition of
399 the SilcSKEKeyMaterial structure. */
401 static void keyagr_completion(SilcClient client,
402 SilcClientConnection conn,
403 SilcClientEntry client_entry,
404 SilcKeyAgreementStatus status,
405 SilcSKEKeyMaterial *key,
408 KeyInternal i = (KeyInternal)context;
411 case SILC_KEY_AGREEMENT_OK:
412 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
413 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
416 /* Set the private key for this client */
417 silc_client_del_private_message_key(client, conn, client_entry);
418 silc_client_add_private_message_key_ske(client, conn, client_entry,
419 NULL, key, i->responder);
420 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
421 SILCTXT_KEY_AGREEMENT_PRIVMSG,
422 client_entry->nickname);
423 silc_ske_free_key_material(key);
428 case SILC_KEY_AGREEMENT_ERROR:
429 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
430 SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
433 case SILC_KEY_AGREEMENT_FAILURE:
434 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
435 SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
438 case SILC_KEY_AGREEMENT_TIMEOUT:
439 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
440 SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
443 case SILC_KEY_AGREEMENT_ABORTED:
444 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
445 SILCTXT_KEY_AGREEMENT_ABORTED, client_entry->nickname);
448 case SILC_KEY_AGREEMENT_ALREADY_STARTED:
449 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
450 SILCTXT_KEY_AGREEMENT_ALREADY_STARTED,
451 client_entry->nickname);
454 case SILC_KEY_AGREEMENT_SELF_DENIED:
455 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
456 SILCTXT_KEY_AGREEMENT_SELF_DENIED);
467 /* Local command KEY. This command is used to set and unset private
468 keys for channels, set and unset private keys for private messages
469 with remote clients and to send key agreement requests and
470 negotiate the key agreement protocol with remote client. The
471 key agreement is supported only to negotiate private message keys,
472 it currently cannot be used to negotiate private keys for channels,
473 as it is not convenient for that purpose. */
476 SILC_SERVER_REC *server;
482 /* Callback to be called after client information is resolved from the
485 static void silc_client_command_key_get_clients(SilcClient client,
486 SilcClientConnection conn,
487 SilcClientEntry *clients,
488 SilcUInt32 clients_count,
491 KeyGetClients internal = (KeyGetClients)context;
494 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s",
496 silc_free(internal->data);
497 silc_free(internal->nick);
502 signal_emit("command key", 3, internal->data, internal->server,
505 silc_free(internal->data);
506 silc_free(internal->nick);
510 static void command_key(const char *data, SILC_SERVER_REC *server,
513 SilcClientConnection conn;
514 SilcClientEntry *entrys, client_entry = NULL;
515 SilcUInt32 entry_count;
516 SILC_CHANNEL_REC *chanrec = NULL;
517 SilcChannelEntry channel_entry = NULL;
518 char *nickname = NULL, *tmp;
519 int command = 0, port = 0, type = 0;
520 char *hostname = NULL;
521 KeyInternal internal = NULL;
523 unsigned char **argv;
524 SilcUInt32 *argv_lens, *argv_types;
525 char *bindhost = NULL;
527 CMD_SILC_SERVER(server);
529 if (!server || !IS_SILC_SERVER(server) || !server->connected)
530 cmd_return_error(CMDERR_NOT_CONNECTED);
534 /* Now parse all arguments */
535 tmp = g_strconcat("KEY", " ", data, NULL);
536 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
540 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
543 if (!strcasecmp(argv[1], "msg"))
545 if (!strcasecmp(argv[1], "channel"))
549 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
552 if (argv[2][0] == '*') {
553 nickname = strdup("*");
555 /* Parse the typed nickname. */
556 if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
557 printformat_module("fe-common/silc", server, NULL,
558 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
562 /* Find client entry */
563 entrys = silc_client_get_clients_local(silc_client, conn, nickname,
564 argv[2], &entry_count);
566 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
567 inter->server = server;
568 inter->data = strdup(data);
569 inter->nick = strdup(nickname);
571 silc_client_get_clients(silc_client, conn, nickname, argv[2],
572 silc_client_command_key_get_clients, inter);
575 client_entry = entrys[0];
581 /* Get channel entry */
584 if (argv[2][0] == '*') {
585 if (!conn->current_channel) {
587 cmd_return_error(CMDERR_NOT_JOINED);
589 name = conn->current_channel->channel_name;
594 chanrec = silc_channel_find(server, name);
595 if (chanrec == NULL) {
597 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
599 channel_entry = chanrec->entry;
603 if (!strcasecmp(argv[3], "set")) {
607 if (type == 1 && client_entry) {
608 /* Set private message key */
610 silc_client_del_private_message_key(silc_client, conn, client_entry);
613 silc_client_add_private_message_key(silc_client, conn, client_entry,
617 TRUE : FALSE), FALSE);
619 silc_client_add_private_message_key(silc_client, conn, client_entry,
623 TRUE : FALSE), FALSE);
625 /* Send the key to the remote client so that it starts using it
627 silc_client_send_private_message_key(silc_client, conn,
629 } else if (type == 2) {
630 /* Set private channel key */
631 char *cipher = NULL, *hmac = NULL;
633 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
634 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
635 SILCTXT_CH_PRIVATE_KEY_NOMODE,
636 channel_entry->channel_name);
645 if (!silc_client_add_channel_private_key(silc_client, conn,
650 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
651 SILCTXT_CH_PRIVATE_KEY_ERROR,
652 channel_entry->channel_name);
656 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
657 SILCTXT_CH_PRIVATE_KEY_ADD,
658 channel_entry->channel_name);
666 if (!strcasecmp(argv[3], "unset")) {
669 if (type == 1 && client_entry) {
670 /* Unset private message key */
671 silc_client_del_private_message_key(silc_client, conn, client_entry);
672 } else if (type == 2) {
673 /* Unset channel key(s) */
674 SilcChannelPrivateKey *keys;
675 SilcUInt32 keys_count;
679 silc_client_del_channel_private_keys(silc_client, conn,
683 number = atoi(argv[4]);
684 keys = silc_client_list_channel_private_keys(silc_client, conn,
690 if (!number || number > keys_count) {
691 silc_client_free_channel_private_keys(keys, keys_count);
695 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
697 silc_client_free_channel_private_keys(keys, keys_count);
705 if (!strcasecmp(argv[3], "list")) {
709 SilcPrivateMessageKeys keys;
710 SilcUInt32 keys_count;
714 keys = silc_client_list_private_message_keys(silc_client, conn,
719 /* list the private message key(s) */
720 if (nickname[0] == '*') {
721 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
722 SILCTXT_PRIVATE_KEY_LIST);
723 for (k = 0; k < keys_count; k++) {
724 memset(buf, 0, sizeof(buf));
725 strncat(buf, " ", 2);
726 len = strlen(keys[k].client_entry->nickname);
727 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
729 for (i = 0; i < 30 - len; i++)
733 len = strlen(keys[k].cipher);
734 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
736 for (i = 0; i < 14 - len; i++)
741 strcat(buf, "<hidden>");
743 strcat(buf, "*generated*");
745 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
748 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
749 SILCTXT_PRIVATE_KEY_LIST_NICK,
750 client_entry->nickname);
751 for (k = 0; k < keys_count; k++) {
752 if (keys[k].client_entry != client_entry)
755 memset(buf, 0, sizeof(buf));
756 strncat(buf, " ", 2);
757 len = strlen(keys[k].client_entry->nickname);
758 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
760 for (i = 0; i < 30 - len; i++)
764 len = strlen(keys[k].cipher);
765 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
767 for (i = 0; i < 14 - len; i++)
772 strcat(buf, "<hidden>");
774 strcat(buf, "*generated*");
776 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
780 silc_client_free_private_message_keys(keys, keys_count);
782 } else if (type == 2) {
783 SilcChannelPrivateKey *keys;
784 SilcUInt32 keys_count;
788 keys = silc_client_list_channel_private_keys(silc_client, conn,
792 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
793 SILCTXT_CH_PRIVATE_KEY_LIST,
794 channel_entry->channel_name);
799 for (k = 0; k < keys_count; k++) {
800 memset(buf, 0, sizeof(buf));
801 strncat(buf, " ", 2);
803 len = strlen(keys[k]->cipher->cipher->name);
804 strncat(buf, keys[k]->cipher->cipher->name, len > 16 ? 16 : len);
806 for (i = 0; i < 16 - len; i++)
810 len = strlen(silc_hmac_get_name(keys[k]->hmac));
811 strncat(buf, silc_hmac_get_name(keys[k]->hmac), len > 16 ? 16 : len);
813 for (i = 0; i < 16 - len; i++)
817 strcat(buf, "<hidden>");
819 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
822 silc_client_free_channel_private_keys(keys, keys_count);
828 /* Send command is used to send key agreement */
829 if (!strcasecmp(argv[3], "agreement")) {
835 port = atoi(argv[5]);
837 internal = silc_calloc(1, sizeof(*internal));
838 internal->type = type;
839 internal->server = server;
842 if (settings_get_bool("use_auto_addr")) {
844 hostname = (char *)settings_get_str("auto_public_ip");
846 /* If the hostname isn't set, treat this case as if auto_public_ip
848 if ((hostname) && (*hostname == '\0')) {
851 bindhost = (char *)settings_get_str("auto_bind_ip");
853 /* if the bind_ip isn't set, but the public_ip IS, then assume then
854 public_ip is the same value as the bind_ip. */
855 if ((bindhost) && (*bindhost == '\0'))
857 port = settings_get_int("auto_bind_port");
859 } /* if use_auto_addr */
863 /* Start command is used to start key agreement (after receiving the
864 key_agreement client operation). */
865 if (!strcasecmp(argv[3], "negotiate")) {
871 port = atoi(argv[5]);
873 internal = silc_calloc(1, sizeof(*internal));
874 internal->type = type;
875 internal->server = server;
878 /* Change current channel private key */
879 if (!strcasecmp(argv[3], "change")) {
882 /* Unset channel key(s) */
883 SilcChannelPrivateKey *keys;
884 SilcUInt32 keys_count;
887 keys = silc_client_list_channel_private_keys(silc_client, conn,
895 if (chanrec->cur_key >= keys_count)
896 chanrec->cur_key = 0;
900 number = atoi(argv[4]);
901 if (!number || number > keys_count)
902 chanrec->cur_key = 0;
904 chanrec->cur_key = number - 1;
907 /* Set the current channel private key */
908 silc_client_current_channel_private_key(silc_client, conn,
910 keys[chanrec->cur_key]);
911 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
912 SILCTXT_CH_PRIVATE_KEY_CHANGE, chanrec->cur_key + 1,
913 channel_entry->channel_name);
915 silc_client_free_channel_private_keys(keys, keys_count);
921 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
922 "Usage: /KEY msg|channel <nickname|channel> "
923 "set|unset|agreement|negotiate [<arguments>]");
927 if (command == 4 && client_entry) {
928 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
929 SILCTXT_KEY_AGREEMENT, argv[2]);
930 internal->responder = TRUE;
931 silc_client_send_key_agreement(
932 silc_client, conn, client_entry, hostname,
934 settings_get_int("key_exchange_timeout_secs"),
935 keyagr_completion, internal);
941 if (command == 5 && client_entry && hostname) {
942 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
943 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
944 internal->responder = FALSE;
945 silc_client_perform_key_agreement(silc_client, conn, client_entry,
946 hostname, port, keyagr_completion,
955 /* Lists locally saved client and server public keys. */
957 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
963 void silc_channels_init(void)
965 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
966 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
967 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
969 command_bind_silc("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
970 command_bind_silc("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
971 command_bind_silc("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
972 command_bind_silc("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
973 command_bind_silc("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
974 command_bind_silc("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
975 command_bind_silc("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
977 silc_nicklist_init();
980 void silc_channels_deinit(void)
982 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
983 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
984 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
986 command_unbind("part", (SIGNAL_FUNC) command_part);
987 command_unbind("me", (SIGNAL_FUNC) command_me);
988 command_unbind("action", (SIGNAL_FUNC) command_action);
989 command_unbind("notice", (SIGNAL_FUNC) command_notice);
990 command_unbind("away", (SIGNAL_FUNC) command_away);
991 command_unbind("key", (SIGNAL_FUNC) command_key);
992 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
994 silc_nicklist_deinit();