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,
50 const char *visible_name,
53 SILC_CHANNEL_REC *rec;
55 g_return_val_if_fail(server == NULL || IS_SILC_SERVER(server), NULL);
56 g_return_val_if_fail(name != NULL, NULL);
58 rec = g_new0(SILC_CHANNEL_REC, 1);
59 rec->chat_type = SILC_PROTOCOL;
60 channel_init((CHANNEL_REC *)rec, (SERVER_REC *)server, name, name,
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);
147 data = item->visible_name;
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->visible_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],
204 SILC_STRING_LANGUAGE);
205 message = silc_calloc(len + 1, sizeof(*message));
206 g_return_if_fail(message != NULL);
207 silc_utf8_encode(argv[1], argv_lens[1], SILC_STRING_LANGUAGE,
211 /* Send the action message */
212 silc_client_send_channel_message(silc_client, server->conn,
213 chanrec->entry, NULL,
214 SILC_MESSAGE_FLAG_ACTION |
215 SILC_MESSAGE_FLAG_UTF8,
216 message ? message : argv[1],
217 message ? strlen(message) : argv_lens[1],
220 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
221 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
222 server->conn->local_entry->nickname, argv[1]);
224 for (i = 0; i < argc; i++)
226 silc_free(argv_lens);
227 silc_free(argv_types);
231 /* ACTION local command. Same as ME but takes the channel as mandatory
234 static void command_action(const char *data, SILC_SERVER_REC *server,
237 SILC_CHANNEL_REC *chanrec;
238 char *tmpcmd = "ME", *tmp;
240 unsigned char *message = NULL;
241 unsigned char **argv;
242 SilcUInt32 *argv_lens, *argv_types;
245 CMD_SILC_SERVER(server);
246 if (!IS_SILC_SERVER(server) || !server->connected)
247 cmd_return_error(CMDERR_NOT_CONNECTED);
249 if (!IS_SILC_CHANNEL(item))
250 cmd_return_error(CMDERR_NOT_JOINED);
252 /* Now parse all arguments */
253 tmp = g_strconcat(tmpcmd, " ", data, NULL);
254 silc_parse_command_line(tmp, &argv, &argv_lens,
255 &argv_types, &argc, 3);
259 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
261 chanrec = silc_channel_find(server, argv[1]);
263 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
265 if (!silc_term_utf8()) {
266 int len = silc_utf8_encoded_len(argv[2], argv_lens[2],
267 SILC_STRING_LANGUAGE);
268 message = silc_calloc(len + 1, sizeof(*message));
269 g_return_if_fail(message != NULL);
270 silc_utf8_encode(argv[2], argv_lens[2], SILC_STRING_LANGUAGE,
274 /* Send the action message */
275 silc_client_send_channel_message(silc_client, server->conn,
276 chanrec->entry, NULL,
277 SILC_MESSAGE_FLAG_ACTION |
278 SILC_MESSAGE_FLAG_UTF8,
279 message ? message : argv[2],
280 message ? strlen(message) : argv_lens[2],
283 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
284 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
285 server->conn->local_entry->nickname, argv[2]);
287 for (i = 0; i < argc; i++)
289 silc_free(argv_lens);
290 silc_free(argv_types);
294 /* NOTICE local command. */
296 static void command_notice(const char *data, SILC_SERVER_REC *server,
299 SILC_CHANNEL_REC *chanrec;
300 char *tmpcmd = "ME", *tmp;
302 unsigned char *message = NULL;
303 unsigned char **argv;
304 SilcUInt32 *argv_lens, *argv_types;
307 CMD_SILC_SERVER(server);
308 if (!IS_SILC_SERVER(server) || !server->connected)
309 cmd_return_error(CMDERR_NOT_CONNECTED);
311 if (!IS_SILC_CHANNEL(item))
312 cmd_return_error(CMDERR_NOT_JOINED);
314 /* Now parse all arguments */
315 tmp = g_strconcat(tmpcmd, " ", data, NULL);
316 silc_parse_command_line(tmp, &argv, &argv_lens,
317 &argv_types, &argc, 2);
321 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
323 chanrec = silc_channel_find(server, item->visible_name);
325 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
327 if (!silc_term_utf8()) {
328 int len = silc_utf8_encoded_len(argv[1], argv_lens[1],
329 SILC_STRING_LANGUAGE);
330 message = silc_calloc(len + 1, sizeof(*message));
331 g_return_if_fail(message != NULL);
332 silc_utf8_encode(argv[1], argv_lens[1], SILC_STRING_LANGUAGE,
336 /* Send the action message */
337 silc_client_send_channel_message(silc_client, server->conn,
338 chanrec->entry, NULL,
339 SILC_MESSAGE_FLAG_NOTICE |
340 SILC_MESSAGE_FLAG_UTF8,
341 message ? message : argv[1],
342 message ? strlen(message) : argv_lens[1],
345 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
346 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_OWNNOTICE,
347 server->conn->local_entry->nickname, argv[1]);
349 for (i = 0; i < argc; i++)
351 silc_free(argv_lens);
352 silc_free(argv_types);
356 /* AWAY local command. Sends UMODE command that sets the SILC_UMODE_GONE
359 static void command_away(const char *data, SILC_SERVER_REC *server,
364 CMD_SILC_SERVER(server);
366 if (!IS_SILC_SERVER(server) || !server->connected)
367 cmd_return_error(CMDERR_NOT_CONNECTED);
370 /* Remove any possible away message */
371 silc_client_set_away_message(silc_client, server->conn, NULL);
374 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
377 /* Set the away message */
378 silc_client_set_away_message(silc_client, server->conn, (char *)data);
381 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
382 SILCTXT_SET_AWAY, data);
385 server->usermode_away = set;
386 g_free_and_null(server->away_reason);
388 server->away_reason = g_strdup((char *)data);
390 signal_emit("away mode changed", 1, server);
392 silc_command_exec(server, "UMODE", set ? "+g" : "-g");
396 int type; /* 1 = msg, 2 = channel */
398 SILC_SERVER_REC *server;
401 /* Key agreement callback that is called after the key agreement protocol
402 has been performed. This is called also if error occured during the
403 key agreement protocol. The `key' is the allocated key material and
404 the caller is responsible of freeing it. The `key' is NULL if error
405 has occured. The application can freely use the `key' to whatever
406 purpose it needs. See lib/silcske/silcske.h for the definition of
407 the SilcSKEKeyMaterial structure. */
409 static void keyagr_completion(SilcClient client,
410 SilcClientConnection conn,
411 SilcClientEntry client_entry,
412 SilcKeyAgreementStatus status,
413 SilcSKEKeyMaterial *key,
416 KeyInternal i = (KeyInternal)context;
419 case SILC_KEY_AGREEMENT_OK:
420 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
421 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
424 /* Set the private key for this client */
425 silc_client_del_private_message_key(client, conn, client_entry);
426 silc_client_add_private_message_key_ske(client, conn, client_entry,
427 NULL, NULL, key, i->responder);
428 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
429 SILCTXT_KEY_AGREEMENT_PRIVMSG,
430 client_entry->nickname);
431 silc_ske_free_key_material(key);
436 case SILC_KEY_AGREEMENT_ERROR:
437 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
438 SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
441 case SILC_KEY_AGREEMENT_FAILURE:
442 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
443 SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
446 case SILC_KEY_AGREEMENT_TIMEOUT:
447 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
448 SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
451 case SILC_KEY_AGREEMENT_ABORTED:
452 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
453 SILCTXT_KEY_AGREEMENT_ABORTED, client_entry->nickname);
456 case SILC_KEY_AGREEMENT_ALREADY_STARTED:
457 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
458 SILCTXT_KEY_AGREEMENT_ALREADY_STARTED,
459 client_entry->nickname);
462 case SILC_KEY_AGREEMENT_SELF_DENIED:
463 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
464 SILCTXT_KEY_AGREEMENT_SELF_DENIED);
475 /* Local command KEY. This command is used to set and unset private
476 keys for channels, set and unset private keys for private messages
477 with remote clients and to send key agreement requests and
478 negotiate the key agreement protocol with remote client. The
479 key agreement is supported only to negotiate private message keys,
480 it currently cannot be used to negotiate private keys for channels,
481 as it is not convenient for that purpose. */
484 SILC_SERVER_REC *server;
490 /* Callback to be called after client information is resolved from the
493 static void silc_client_command_key_get_clients(SilcClient client,
494 SilcClientConnection conn,
495 SilcClientEntry *clients,
496 SilcUInt32 clients_count,
499 KeyGetClients internal = (KeyGetClients)context;
502 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s",
504 silc_free(internal->data);
505 silc_free(internal->nick);
510 signal_emit("command key", 3, internal->data, internal->server,
513 silc_free(internal->data);
514 silc_free(internal->nick);
518 static void command_key(const char *data, SILC_SERVER_REC *server,
521 SilcClientConnection conn;
522 SilcClientEntry *entrys, client_entry = NULL;
523 SilcUInt32 entry_count;
524 SILC_CHANNEL_REC *chanrec = NULL;
525 SilcChannelEntry channel_entry = NULL;
526 char *nickname = NULL, *tmp;
527 int command = 0, port = 0, type = 0;
528 char *hostname = NULL;
529 KeyInternal internal = NULL;
531 unsigned char **argv;
532 SilcUInt32 *argv_lens, *argv_types;
533 char *bindhost = NULL;
535 CMD_SILC_SERVER(server);
537 if (!server || !IS_SILC_SERVER(server) || !server->connected)
538 cmd_return_error(CMDERR_NOT_CONNECTED);
542 /* Now parse all arguments */
543 tmp = g_strconcat("KEY", " ", data, NULL);
544 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
548 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
551 if (!strcasecmp(argv[1], "msg"))
553 if (!strcasecmp(argv[1], "channel"))
557 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
560 if (argv[2][0] == '*') {
561 nickname = strdup("*");
563 /* Parse the typed nickname. */
564 if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
565 printformat_module("fe-common/silc", server, NULL,
566 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
570 /* Find client entry */
571 entrys = silc_client_get_clients_local(silc_client, conn, nickname,
572 argv[2], &entry_count);
574 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
575 inter->server = server;
576 inter->data = strdup(data);
577 inter->nick = strdup(nickname);
579 silc_client_get_clients(silc_client, conn, nickname, argv[2],
580 silc_client_command_key_get_clients, inter);
583 client_entry = entrys[0];
589 /* Get channel entry */
592 if (argv[2][0] == '*') {
593 if (!conn->current_channel) {
595 cmd_return_error(CMDERR_NOT_JOINED);
597 name = conn->current_channel->channel_name;
602 chanrec = silc_channel_find(server, name);
603 if (chanrec == NULL) {
605 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
607 channel_entry = chanrec->entry;
611 if (!strcasecmp(argv[3], "set")) {
615 char *cipher = NULL, *hmac = NULL;
617 if (type == 1 && client_entry) {
618 /* Set private message key */
619 bool responder = FALSE;
621 silc_client_del_private_message_key(silc_client, conn, client_entry);
624 if (!strcasecmp(argv[5], "-responder"))
630 if (!strcasecmp(argv[6], "-responder"))
636 if (!strcasecmp(argv[7], "-responder"))
640 silc_client_add_private_message_key(silc_client, conn, client_entry,
642 argv[4], argv_lens[4],
644 TRUE : FALSE), responder);
646 /* Send the key to the remote client so that it starts using it
648 /* XXX for now we don't do this. This feature is pretty stupid
649 and should perhaps be removed altogether from SILC.
650 silc_client_send_private_message_key(silc_client, conn,
653 } else if (type == 2) {
654 /* Set private channel key */
655 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
656 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
657 SILCTXT_CH_PRIVATE_KEY_NOMODE,
658 channel_entry->channel_name);
667 if (!silc_client_add_channel_private_key(silc_client, conn,
672 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
673 SILCTXT_CH_PRIVATE_KEY_ERROR,
674 channel_entry->channel_name);
678 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
679 SILCTXT_CH_PRIVATE_KEY_ADD,
680 channel_entry->channel_name);
688 if (!strcasecmp(argv[3], "unset")) {
691 if (type == 1 && client_entry) {
692 /* Unset private message key */
693 silc_client_del_private_message_key(silc_client, conn, client_entry);
694 } else if (type == 2) {
695 /* Unset channel key(s) */
696 SilcChannelPrivateKey *keys;
697 SilcUInt32 keys_count;
701 silc_client_del_channel_private_keys(silc_client, conn,
705 number = atoi(argv[4]);
706 keys = silc_client_list_channel_private_keys(silc_client, conn,
712 if (!number || number > keys_count) {
713 silc_client_free_channel_private_keys(keys, keys_count);
717 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
719 silc_client_free_channel_private_keys(keys, keys_count);
727 if (!strcasecmp(argv[3], "list")) {
731 SilcPrivateMessageKeys keys;
732 SilcUInt32 keys_count;
736 keys = silc_client_list_private_message_keys(silc_client, conn,
741 /* list the private message key(s) */
742 if (nickname[0] == '*') {
743 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
744 SILCTXT_PRIVATE_KEY_LIST);
745 for (k = 0; k < keys_count; k++) {
746 memset(buf, 0, sizeof(buf));
747 strncat(buf, " ", 2);
748 len = strlen(keys[k].client_entry->nickname);
749 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
751 for (i = 0; i < 30 - len; i++)
755 len = strlen(keys[k].cipher);
756 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
758 for (i = 0; i < 14 - len; i++)
763 strcat(buf, "<hidden>");
765 strcat(buf, "*generated*");
767 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
770 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
771 SILCTXT_PRIVATE_KEY_LIST_NICK,
772 client_entry->nickname);
773 for (k = 0; k < keys_count; k++) {
774 if (keys[k].client_entry != client_entry)
777 memset(buf, 0, sizeof(buf));
778 strncat(buf, " ", 2);
779 len = strlen(keys[k].client_entry->nickname);
780 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
782 for (i = 0; i < 30 - len; i++)
786 len = strlen(keys[k].cipher);
787 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
789 for (i = 0; i < 14 - len; i++)
794 strcat(buf, "<hidden>");
796 strcat(buf, "*generated*");
798 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
802 silc_client_free_private_message_keys(keys, keys_count);
804 } else if (type == 2) {
805 SilcChannelPrivateKey *keys;
806 SilcUInt32 keys_count;
810 keys = silc_client_list_channel_private_keys(silc_client, conn,
814 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
815 SILCTXT_CH_PRIVATE_KEY_LIST,
816 channel_entry->channel_name);
821 for (k = 0; k < keys_count; k++) {
822 memset(buf, 0, sizeof(buf));
823 strncat(buf, " ", 2);
825 len = strlen(silc_cipher_get_name(keys[k]->cipher));
826 strncat(buf, silc_cipher_get_name(keys[k]->cipher),
827 len > 16 ? 16 : len);
829 for (i = 0; i < 16 - len; i++)
833 len = strlen(silc_hmac_get_name(keys[k]->hmac));
834 strncat(buf, silc_hmac_get_name(keys[k]->hmac), len > 16 ? 16 : len);
836 for (i = 0; i < 16 - len; i++)
840 strcat(buf, "<hidden>");
842 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
845 silc_client_free_channel_private_keys(keys, keys_count);
851 /* Send command is used to send key agreement */
852 if (!strcasecmp(argv[3], "agreement")) {
858 port = atoi(argv[5]);
860 internal = silc_calloc(1, sizeof(*internal));
861 internal->type = type;
862 internal->server = server;
865 if (settings_get_bool("use_auto_addr")) {
867 hostname = (char *)settings_get_str("auto_public_ip");
869 /* If the hostname isn't set, treat this case as if auto_public_ip
871 if ((hostname) && (*hostname == '\0')) {
874 bindhost = (char *)settings_get_str("auto_bind_ip");
876 /* if the bind_ip isn't set, but the public_ip IS, then assume then
877 public_ip is the same value as the bind_ip. */
878 if ((bindhost) && (*bindhost == '\0'))
880 port = settings_get_int("auto_bind_port");
882 } /* if use_auto_addr */
886 /* Start command is used to start key agreement (after receiving the
887 key_agreement client operation). */
888 if (!strcasecmp(argv[3], "negotiate")) {
894 port = atoi(argv[5]);
896 internal = silc_calloc(1, sizeof(*internal));
897 internal->type = type;
898 internal->server = server;
901 /* Change current channel private key */
902 if (!strcasecmp(argv[3], "change")) {
905 /* Unset channel key(s) */
906 SilcChannelPrivateKey *keys;
907 SilcUInt32 keys_count;
910 keys = silc_client_list_channel_private_keys(silc_client, conn,
918 if (chanrec->cur_key >= keys_count)
919 chanrec->cur_key = 0;
923 number = atoi(argv[4]);
924 if (!number || number > keys_count)
925 chanrec->cur_key = 0;
927 chanrec->cur_key = number - 1;
930 /* Set the current channel private key */
931 silc_client_current_channel_private_key(silc_client, conn,
933 keys[chanrec->cur_key]);
934 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
935 SILCTXT_CH_PRIVATE_KEY_CHANGE, chanrec->cur_key + 1,
936 channel_entry->channel_name);
938 silc_client_free_channel_private_keys(keys, keys_count);
944 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
945 "Usage: /KEY msg|channel <nickname|channel> "
946 "set|unset|agreement|negotiate [<arguments>]");
950 if (command == 4 && client_entry) {
951 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
952 SILCTXT_KEY_AGREEMENT, argv[2]);
953 internal->responder = TRUE;
954 silc_client_send_key_agreement(
955 silc_client, conn, client_entry, hostname,
957 settings_get_int("key_exchange_timeout_secs"),
958 keyagr_completion, internal);
964 if (command == 5 && client_entry && hostname) {
965 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
966 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
967 internal->responder = FALSE;
968 silc_client_perform_key_agreement(silc_client, conn, client_entry,
969 hostname, port, keyagr_completion,
978 /* Lists locally saved client and server public keys. */
980 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
986 void silc_channels_init(void)
988 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
989 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
990 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
992 command_bind_silc("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
993 command_bind_silc("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
994 command_bind_silc("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
995 command_bind_silc("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
996 command_bind_silc("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
997 command_bind_silc("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
998 command_bind_silc("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
1000 silc_nicklist_init();
1003 void silc_channels_deinit(void)
1005 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1006 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1007 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1009 command_unbind("part", (SIGNAL_FUNC) command_part);
1010 command_unbind("me", (SIGNAL_FUNC) command_me);
1011 command_unbind("action", (SIGNAL_FUNC) command_action);
1012 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1013 command_unbind("away", (SIGNAL_FUNC) command_away);
1014 command_unbind("key", (SIGNAL_FUNC) command_key);
1015 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
1017 silc_nicklist_deinit();