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"
36 #include "channels-setup.h"
38 #include "silc-servers.h"
39 #include "silc-channels.h"
40 #include "silc-queries.h"
41 #include "silc-nicklist.h"
42 #include "window-item-def.h"
44 #include "fe-common/core/printtext.h"
45 #include "fe-common/silc/module-formats.h"
47 #include "silc-commands.h"
49 void sig_mime(SILC_SERVER_REC *server, SILC_CHANNEL_REC *channel,
50 BLOB_REC *blob, const char *enc, const char *type,
53 if (!(IS_SILC_SERVER(server)))
56 printformat_module("fe-common/silc", server,
57 channel == NULL ? NULL : channel->name,
58 MSGLEVEL_CRAP, SILCTXT_MESSAGE_DATA,
59 nick == NULL ? "[<unknown>]" : nick, type);
62 SILC_CHANNEL_REC *silc_channel_create(SILC_SERVER_REC *server,
63 const char *name, int automatic)
65 SILC_CHANNEL_REC *rec;
67 g_return_val_if_fail(server == NULL || IS_SILC_SERVER(server), NULL);
68 g_return_val_if_fail(name != NULL, NULL);
70 rec = g_new0(SILC_CHANNEL_REC, 1);
71 rec->chat_type = SILC_PROTOCOL;
72 rec->name = g_strdup(name);
75 channel_init((CHANNEL_REC *) rec, automatic);
79 static void sig_channel_destroyed(SILC_CHANNEL_REC *channel)
81 if (!IS_SILC_CHANNEL(channel))
83 if (channel->server && channel->server->disconnected)
86 if (channel->server != NULL && !channel->left && !channel->kicked) {
87 /* destroying channel record without actually
88 having left the channel yet */
89 silc_command_exec(channel->server, "LEAVE", channel->name);
93 static void silc_channels_join(SILC_SERVER_REC *server,
94 const char *channels, int automatic)
97 SILC_CHANNEL_REC *chanrec;
99 list = g_strsplit(channels, ",", -1);
100 for (tmp = list; *tmp != NULL; tmp++) {
101 chanrec = silc_channel_find(server, *tmp);
105 silc_command_exec(server, "JOIN", *tmp);
111 static void sig_connected(SILC_SERVER_REC *server)
113 if (IS_SILC_SERVER(server))
114 server->channels_join = (void *) silc_channels_join;
117 /* "server quit" signal from the core to indicate that QUIT command
120 static void sig_server_quit(SILC_SERVER_REC *server, const char *msg)
122 if (IS_SILC_SERVER(server) && server->conn && server->conn->sock)
123 silc_command_exec(server, "QUIT", msg);
126 /* Find Irssi channel entry by SILC channel entry */
128 SILC_CHANNEL_REC *silc_channel_find_entry(SILC_SERVER_REC *server,
129 SilcChannelEntry entry)
133 g_return_val_if_fail(IS_SILC_SERVER(server), NULL);
135 for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
136 SILC_CHANNEL_REC *rec = tmp->data;
138 if (rec->entry == entry)
145 /* PART (LEAVE) command. */
147 static void command_part(const char *data, SILC_SERVER_REC *server,
150 SILC_CHANNEL_REC *chanrec;
153 CMD_SILC_SERVER(server);
155 if (!IS_SILC_SERVER(server) || !server->connected)
156 cmd_return_error(CMDERR_NOT_CONNECTED);
158 if (!strcmp(data, "*") || *data == '\0') {
159 if (!IS_SILC_CHANNEL(item))
160 cmd_return_error(CMDERR_NOT_JOINED);
164 chanrec = silc_channel_find(server, data);
166 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
168 memset(userhost, 0, sizeof(userhost));
169 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
170 server->conn->local_entry->username,
171 server->conn->local_entry->hostname);
172 signal_emit("message part", 5, server, chanrec->name,
173 server->nick, userhost, "");
175 chanrec->left = TRUE;
176 silc_command_exec(server, "LEAVE", chanrec->name);
179 channel_destroy(CHANNEL(chanrec));
182 /* ME local command. */
184 static void command_me(const char *data, SILC_SERVER_REC *server,
187 SILC_CHANNEL_REC *chanrec;
188 char *tmpcmd = "ME", *tmp;
190 unsigned char *message = NULL;
191 unsigned char **argv;
192 SilcUInt32 *argv_lens, *argv_types;
195 CMD_SILC_SERVER(server);
197 if (!IS_SILC_SERVER(server) || !server->connected)
198 cmd_return_error(CMDERR_NOT_CONNECTED);
200 if (!IS_SILC_CHANNEL(item))
201 cmd_return_error(CMDERR_NOT_JOINED);
203 /* Now parse all arguments */
204 tmp = g_strconcat(tmpcmd, " ", data, NULL);
205 silc_parse_command_line(tmp, &argv, &argv_lens,
206 &argv_types, &argc, 2);
210 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
212 chanrec = silc_channel_find(server, item->name);
214 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
216 if (!silc_term_utf8()) {
217 int len = silc_utf8_encoded_len(argv[1], argv_lens[1],
218 SILC_STRING_LANGUAGE);
219 message = silc_calloc(len + 1, sizeof(*message));
220 g_return_if_fail(message != NULL);
221 silc_utf8_encode(argv[1], argv_lens[1], SILC_STRING_LANGUAGE,
225 /* Send the action message */
226 silc_client_send_channel_message(silc_client, server->conn,
227 chanrec->entry, NULL,
228 SILC_MESSAGE_FLAG_ACTION |
229 SILC_MESSAGE_FLAG_UTF8,
230 message ? message : argv[1],
231 message ? strlen(message) : argv_lens[1],
234 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
235 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
236 server->conn->local_entry->nickname, argv[1]);
238 for (i = 0; i < argc; i++)
240 silc_free(argv_lens);
241 silc_free(argv_types);
245 /* ACTION local command. Same as ME but takes the channel as mandatory
248 static void command_action(const char *data, SILC_SERVER_REC *server,
251 SILC_CHANNEL_REC *chanrec;
252 char *tmpcmd = "ME", *tmp;
254 unsigned char *message = NULL;
255 unsigned char **argv;
256 SilcUInt32 *argv_lens, *argv_types;
259 CMD_SILC_SERVER(server);
260 if (!IS_SILC_SERVER(server) || !server->connected)
261 cmd_return_error(CMDERR_NOT_CONNECTED);
263 if (!IS_SILC_CHANNEL(item))
264 cmd_return_error(CMDERR_NOT_JOINED);
266 /* Now parse all arguments */
267 tmp = g_strconcat(tmpcmd, " ", data, NULL);
268 silc_parse_command_line(tmp, &argv, &argv_lens,
269 &argv_types, &argc, 3);
273 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
275 chanrec = silc_channel_find(server, argv[1]);
277 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
279 if (!silc_term_utf8()) {
280 int len = silc_utf8_encoded_len(argv[2], argv_lens[2],
281 SILC_STRING_LANGUAGE);
282 message = silc_calloc(len + 1, sizeof(*message));
283 g_return_if_fail(message != NULL);
284 silc_utf8_encode(argv[2], argv_lens[2], SILC_STRING_LANGUAGE,
288 /* Send the action message */
289 silc_client_send_channel_message(silc_client, server->conn,
290 chanrec->entry, NULL,
291 SILC_MESSAGE_FLAG_ACTION |
292 SILC_MESSAGE_FLAG_UTF8,
293 message ? message : argv[2],
294 message ? strlen(message) : argv_lens[2],
297 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
298 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
299 server->conn->local_entry->nickname, argv[2]);
301 for (i = 0; i < argc; i++)
303 silc_free(argv_lens);
304 silc_free(argv_types);
308 /* NOTICE local command. */
310 static void command_notice(const char *data, SILC_SERVER_REC *server,
313 SILC_CHANNEL_REC *chanrec;
314 char *tmpcmd = "ME", *tmp;
316 unsigned char *message = NULL;
317 unsigned char **argv;
318 SilcUInt32 *argv_lens, *argv_types;
321 CMD_SILC_SERVER(server);
322 if (!IS_SILC_SERVER(server) || !server->connected)
323 cmd_return_error(CMDERR_NOT_CONNECTED);
325 if (!IS_SILC_CHANNEL(item))
326 cmd_return_error(CMDERR_NOT_JOINED);
328 /* Now parse all arguments */
329 tmp = g_strconcat(tmpcmd, " ", data, NULL);
330 silc_parse_command_line(tmp, &argv, &argv_lens,
331 &argv_types, &argc, 2);
335 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
337 chanrec = silc_channel_find(server, item->name);
339 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
341 if (!silc_term_utf8()) {
342 int len = silc_utf8_encoded_len(argv[1], argv_lens[1],
343 SILC_STRING_LANGUAGE);
344 message = silc_calloc(len + 1, sizeof(*message));
345 g_return_if_fail(message != NULL);
346 silc_utf8_encode(argv[1], argv_lens[1], SILC_STRING_LANGUAGE,
350 /* Send the action message */
351 silc_client_send_channel_message(silc_client, server->conn,
352 chanrec->entry, NULL,
353 SILC_MESSAGE_FLAG_NOTICE |
354 SILC_MESSAGE_FLAG_UTF8,
355 message ? message : argv[1],
356 message ? strlen(message) : argv_lens[1],
359 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
360 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_OWNNOTICE,
361 server->conn->local_entry->nickname, argv[1]);
363 for (i = 0; i < argc; i++)
365 silc_free(argv_lens);
366 silc_free(argv_types);
370 /* AWAY local command. Sends UMODE command that sets the SILC_UMODE_GONE
373 static void command_away(const char *data, SILC_SERVER_REC *server,
378 CMD_SILC_SERVER(server);
380 if (!IS_SILC_SERVER(server) || !server->connected)
381 cmd_return_error(CMDERR_NOT_CONNECTED);
384 /* Remove any possible away message */
385 silc_client_set_away_message(silc_client, server->conn, NULL);
388 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
391 /* Set the away message */
392 silc_client_set_away_message(silc_client, server->conn, (char *)data);
395 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
396 SILCTXT_SET_AWAY, data);
399 server->usermode_away = set;
400 g_free_and_null(server->away_reason);
402 server->away_reason = g_strdup((char *)data);
404 signal_emit("away mode changed", 1, server);
406 silc_command_exec(server, "UMODE", set ? "+g" : "-g");
410 int type; /* 1 = msg, 2 = channel */
412 SILC_SERVER_REC *server;
415 /* Key agreement callback that is called after the key agreement protocol
416 has been performed. This is called also if error occured during the
417 key agreement protocol. The `key' is the allocated key material and
418 the caller is responsible of freeing it. The `key' is NULL if error
419 has occured. The application can freely use the `key' to whatever
420 purpose it needs. See lib/silcske/silcske.h for the definition of
421 the SilcSKEKeyMaterial structure. */
423 static void keyagr_completion(SilcClient client,
424 SilcClientConnection conn,
425 SilcClientEntry client_entry,
426 SilcKeyAgreementStatus status,
427 SilcSKEKeyMaterial *key,
430 KeyInternal i = (KeyInternal)context;
433 case SILC_KEY_AGREEMENT_OK:
434 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
435 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
438 /* Set the private key for this client */
439 silc_client_del_private_message_key(client, conn, client_entry);
440 silc_client_add_private_message_key_ske(client, conn, client_entry,
441 NULL, key, i->responder);
442 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
443 SILCTXT_KEY_AGREEMENT_PRIVMSG,
444 client_entry->nickname);
445 silc_ske_free_key_material(key);
450 case SILC_KEY_AGREEMENT_ERROR:
451 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
452 SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
455 case SILC_KEY_AGREEMENT_FAILURE:
456 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
457 SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
460 case SILC_KEY_AGREEMENT_TIMEOUT:
461 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
462 SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
465 case SILC_KEY_AGREEMENT_ABORTED:
466 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
467 SILCTXT_KEY_AGREEMENT_ABORTED, client_entry->nickname);
470 case SILC_KEY_AGREEMENT_ALREADY_STARTED:
471 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
472 SILCTXT_KEY_AGREEMENT_ALREADY_STARTED,
473 client_entry->nickname);
476 case SILC_KEY_AGREEMENT_SELF_DENIED:
477 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
478 SILCTXT_KEY_AGREEMENT_SELF_DENIED);
489 /* Local command KEY. This command is used to set and unset private
490 keys for channels, set and unset private keys for private messages
491 with remote clients and to send key agreement requests and
492 negotiate the key agreement protocol with remote client. The
493 key agreement is supported only to negotiate private message keys,
494 it currently cannot be used to negotiate private keys for channels,
495 as it is not convenient for that purpose. */
498 SILC_SERVER_REC *server;
504 /* Callback to be called after client information is resolved from the
507 static void silc_client_command_key_get_clients(SilcClient client,
508 SilcClientConnection conn,
509 SilcClientEntry *clients,
510 SilcUInt32 clients_count,
513 KeyGetClients internal = (KeyGetClients)context;
516 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s",
518 silc_free(internal->data);
519 silc_free(internal->nick);
524 signal_emit("command key", 3, internal->data, internal->server,
527 silc_free(internal->data);
528 silc_free(internal->nick);
532 static void command_key(const char *data, SILC_SERVER_REC *server,
535 SilcClientConnection conn;
536 SilcClientEntry *entrys, client_entry = NULL;
537 SilcUInt32 entry_count;
538 SILC_CHANNEL_REC *chanrec = NULL;
539 SilcChannelEntry channel_entry = NULL;
540 char *nickname = NULL, *tmp;
541 int command = 0, port = 0, type = 0;
542 char *hostname = NULL;
543 KeyInternal internal = NULL;
545 unsigned char **argv;
546 SilcUInt32 *argv_lens, *argv_types;
547 char *bindhost = NULL;
549 CMD_SILC_SERVER(server);
551 if (!server || !IS_SILC_SERVER(server) || !server->connected)
552 cmd_return_error(CMDERR_NOT_CONNECTED);
556 /* Now parse all arguments */
557 tmp = g_strconcat("KEY", " ", data, NULL);
558 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
562 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
565 if (!strcasecmp(argv[1], "msg"))
567 if (!strcasecmp(argv[1], "channel"))
571 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
574 if (argv[2][0] == '*') {
575 nickname = strdup("*");
577 /* Parse the typed nickname. */
578 if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
579 printformat_module("fe-common/silc", server, NULL,
580 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
584 /* Find client entry */
585 entrys = silc_client_get_clients_local(silc_client, conn, nickname,
586 argv[2], &entry_count);
588 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
589 inter->server = server;
590 inter->data = strdup(data);
591 inter->nick = strdup(nickname);
593 silc_client_get_clients(silc_client, conn, nickname, argv[2],
594 silc_client_command_key_get_clients, inter);
597 client_entry = entrys[0];
603 /* Get channel entry */
606 if (argv[2][0] == '*') {
607 if (!conn->current_channel) {
609 cmd_return_error(CMDERR_NOT_JOINED);
611 name = conn->current_channel->channel_name;
616 chanrec = silc_channel_find(server, name);
617 if (chanrec == NULL) {
619 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
621 channel_entry = chanrec->entry;
625 if (!strcasecmp(argv[3], "set")) {
629 if (type == 1 && client_entry) {
630 /* Set private message key */
632 silc_client_del_private_message_key(silc_client, conn, client_entry);
635 silc_client_add_private_message_key(silc_client, conn, client_entry,
639 TRUE : FALSE), FALSE);
641 silc_client_add_private_message_key(silc_client, conn, client_entry,
645 TRUE : FALSE), FALSE);
647 /* Send the key to the remote client so that it starts using it
649 silc_client_send_private_message_key(silc_client, conn,
651 } else if (type == 2) {
652 /* Set private channel key */
653 char *cipher = NULL, *hmac = NULL;
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(keys[k]->cipher->cipher->name);
826 strncat(buf, keys[k]->cipher->cipher->name, len > 16 ? 16 : len);
828 for (i = 0; i < 16 - len; i++)
832 len = strlen(silc_hmac_get_name(keys[k]->hmac));
833 strncat(buf, silc_hmac_get_name(keys[k]->hmac), len > 16 ? 16 : len);
835 for (i = 0; i < 16 - len; i++)
839 strcat(buf, "<hidden>");
841 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
844 silc_client_free_channel_private_keys(keys, keys_count);
850 /* Send command is used to send key agreement */
851 if (!strcasecmp(argv[3], "agreement")) {
857 port = atoi(argv[5]);
859 internal = silc_calloc(1, sizeof(*internal));
860 internal->type = type;
861 internal->server = server;
864 if (settings_get_bool("use_auto_addr")) {
866 hostname = (char *)settings_get_str("auto_public_ip");
868 /* If the hostname isn't set, treat this case as if auto_public_ip
870 if ((hostname) && (*hostname == '\0')) {
873 bindhost = (char *)settings_get_str("auto_bind_ip");
875 /* if the bind_ip isn't set, but the public_ip IS, then assume then
876 public_ip is the same value as the bind_ip. */
877 if ((bindhost) && (*bindhost == '\0'))
879 port = settings_get_int("auto_bind_port");
881 } /* if use_auto_addr */
885 /* Start command is used to start key agreement (after receiving the
886 key_agreement client operation). */
887 if (!strcasecmp(argv[3], "negotiate")) {
893 port = atoi(argv[5]);
895 internal = silc_calloc(1, sizeof(*internal));
896 internal->type = type;
897 internal->server = server;
900 /* Change current channel private key */
901 if (!strcasecmp(argv[3], "change")) {
904 /* Unset channel key(s) */
905 SilcChannelPrivateKey *keys;
906 SilcUInt32 keys_count;
909 keys = silc_client_list_channel_private_keys(silc_client, conn,
917 if (chanrec->cur_key >= keys_count)
918 chanrec->cur_key = 0;
922 number = atoi(argv[4]);
923 if (!number || number > keys_count)
924 chanrec->cur_key = 0;
926 chanrec->cur_key = number - 1;
929 /* Set the current channel private key */
930 silc_client_current_channel_private_key(silc_client, conn,
932 keys[chanrec->cur_key]);
933 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
934 SILCTXT_CH_PRIVATE_KEY_CHANGE, chanrec->cur_key + 1,
935 channel_entry->channel_name);
937 silc_client_free_channel_private_keys(keys, keys_count);
943 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
944 "Usage: /KEY msg|channel <nickname|channel> "
945 "set|unset|agreement|negotiate [<arguments>]");
949 if (command == 4 && client_entry) {
950 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
951 SILCTXT_KEY_AGREEMENT, argv[2]);
952 internal->responder = TRUE;
953 silc_client_send_key_agreement(
954 silc_client, conn, client_entry, hostname,
956 settings_get_int("key_exchange_timeout_secs"),
957 keyagr_completion, internal);
963 if (command == 5 && client_entry && hostname) {
964 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
965 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
966 internal->responder = FALSE;
967 silc_client_perform_key_agreement(silc_client, conn, client_entry,
968 hostname, port, keyagr_completion,
977 /* Lists locally saved client and server public keys. */
979 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
985 void silc_channels_init(void)
987 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
988 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
989 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
990 signal_add("mime", (SIGNAL_FUNC) sig_mime);
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);
1008 signal_remove("mime", (SIGNAL_FUNC) sig_mime);
1010 command_unbind("part", (SIGNAL_FUNC) command_part);
1011 command_unbind("me", (SIGNAL_FUNC) command_me);
1012 command_unbind("action", (SIGNAL_FUNC) command_action);
1013 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1014 command_unbind("away", (SIGNAL_FUNC) command_away);
1015 command_unbind("key", (SIGNAL_FUNC) command_key);
1016 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
1018 silc_nicklist_deinit();