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 /* XXX for now we don't do this. This feature is pretty stupid
650 and should perhaps be removed altogether from SILC.
651 silc_client_send_private_message_key(silc_client, conn,
654 } else if (type == 2) {
655 /* Set private channel key */
656 char *cipher = NULL, *hmac = NULL;
658 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
659 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
660 SILCTXT_CH_PRIVATE_KEY_NOMODE,
661 channel_entry->channel_name);
670 if (!silc_client_add_channel_private_key(silc_client, conn,
675 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
676 SILCTXT_CH_PRIVATE_KEY_ERROR,
677 channel_entry->channel_name);
681 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
682 SILCTXT_CH_PRIVATE_KEY_ADD,
683 channel_entry->channel_name);
691 if (!strcasecmp(argv[3], "unset")) {
694 if (type == 1 && client_entry) {
695 /* Unset private message key */
696 silc_client_del_private_message_key(silc_client, conn, client_entry);
697 } else if (type == 2) {
698 /* Unset channel key(s) */
699 SilcChannelPrivateKey *keys;
700 SilcUInt32 keys_count;
704 silc_client_del_channel_private_keys(silc_client, conn,
708 number = atoi(argv[4]);
709 keys = silc_client_list_channel_private_keys(silc_client, conn,
715 if (!number || number > keys_count) {
716 silc_client_free_channel_private_keys(keys, keys_count);
720 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
722 silc_client_free_channel_private_keys(keys, keys_count);
730 if (!strcasecmp(argv[3], "list")) {
734 SilcPrivateMessageKeys keys;
735 SilcUInt32 keys_count;
739 keys = silc_client_list_private_message_keys(silc_client, conn,
744 /* list the private message key(s) */
745 if (nickname[0] == '*') {
746 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
747 SILCTXT_PRIVATE_KEY_LIST);
748 for (k = 0; k < keys_count; k++) {
749 memset(buf, 0, sizeof(buf));
750 strncat(buf, " ", 2);
751 len = strlen(keys[k].client_entry->nickname);
752 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
754 for (i = 0; i < 30 - len; i++)
758 len = strlen(keys[k].cipher);
759 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
761 for (i = 0; i < 14 - len; i++)
766 strcat(buf, "<hidden>");
768 strcat(buf, "*generated*");
770 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
773 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
774 SILCTXT_PRIVATE_KEY_LIST_NICK,
775 client_entry->nickname);
776 for (k = 0; k < keys_count; k++) {
777 if (keys[k].client_entry != client_entry)
780 memset(buf, 0, sizeof(buf));
781 strncat(buf, " ", 2);
782 len = strlen(keys[k].client_entry->nickname);
783 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
785 for (i = 0; i < 30 - len; i++)
789 len = strlen(keys[k].cipher);
790 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
792 for (i = 0; i < 14 - len; i++)
797 strcat(buf, "<hidden>");
799 strcat(buf, "*generated*");
801 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
805 silc_client_free_private_message_keys(keys, keys_count);
807 } else if (type == 2) {
808 SilcChannelPrivateKey *keys;
809 SilcUInt32 keys_count;
813 keys = silc_client_list_channel_private_keys(silc_client, conn,
817 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
818 SILCTXT_CH_PRIVATE_KEY_LIST,
819 channel_entry->channel_name);
824 for (k = 0; k < keys_count; k++) {
825 memset(buf, 0, sizeof(buf));
826 strncat(buf, " ", 2);
828 len = strlen(keys[k]->cipher->cipher->name);
829 strncat(buf, keys[k]->cipher->cipher->name, len > 16 ? 16 : len);
831 for (i = 0; i < 16 - len; i++)
835 len = strlen(silc_hmac_get_name(keys[k]->hmac));
836 strncat(buf, silc_hmac_get_name(keys[k]->hmac), len > 16 ? 16 : len);
838 for (i = 0; i < 16 - len; i++)
842 strcat(buf, "<hidden>");
844 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
847 silc_client_free_channel_private_keys(keys, keys_count);
853 /* Send command is used to send key agreement */
854 if (!strcasecmp(argv[3], "agreement")) {
860 port = atoi(argv[5]);
862 internal = silc_calloc(1, sizeof(*internal));
863 internal->type = type;
864 internal->server = server;
867 if (settings_get_bool("use_auto_addr")) {
869 hostname = (char *)settings_get_str("auto_public_ip");
871 /* If the hostname isn't set, treat this case as if auto_public_ip
873 if ((hostname) && (*hostname == '\0')) {
876 bindhost = (char *)settings_get_str("auto_bind_ip");
878 /* if the bind_ip isn't set, but the public_ip IS, then assume then
879 public_ip is the same value as the bind_ip. */
880 if ((bindhost) && (*bindhost == '\0'))
882 port = settings_get_int("auto_bind_port");
884 } /* if use_auto_addr */
888 /* Start command is used to start key agreement (after receiving the
889 key_agreement client operation). */
890 if (!strcasecmp(argv[3], "negotiate")) {
896 port = atoi(argv[5]);
898 internal = silc_calloc(1, sizeof(*internal));
899 internal->type = type;
900 internal->server = server;
903 /* Change current channel private key */
904 if (!strcasecmp(argv[3], "change")) {
907 /* Unset channel key(s) */
908 SilcChannelPrivateKey *keys;
909 SilcUInt32 keys_count;
912 keys = silc_client_list_channel_private_keys(silc_client, conn,
920 if (chanrec->cur_key >= keys_count)
921 chanrec->cur_key = 0;
925 number = atoi(argv[4]);
926 if (!number || number > keys_count)
927 chanrec->cur_key = 0;
929 chanrec->cur_key = number - 1;
932 /* Set the current channel private key */
933 silc_client_current_channel_private_key(silc_client, conn,
935 keys[chanrec->cur_key]);
936 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
937 SILCTXT_CH_PRIVATE_KEY_CHANGE, chanrec->cur_key + 1,
938 channel_entry->channel_name);
940 silc_client_free_channel_private_keys(keys, keys_count);
946 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
947 "Usage: /KEY msg|channel <nickname|channel> "
948 "set|unset|agreement|negotiate [<arguments>]");
952 if (command == 4 && client_entry) {
953 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
954 SILCTXT_KEY_AGREEMENT, argv[2]);
955 internal->responder = TRUE;
956 silc_client_send_key_agreement(
957 silc_client, conn, client_entry, hostname,
959 settings_get_int("key_exchange_timeout_secs"),
960 keyagr_completion, internal);
966 if (command == 5 && client_entry && hostname) {
967 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
968 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
969 internal->responder = FALSE;
970 silc_client_perform_key_agreement(silc_client, conn, client_entry,
971 hostname, port, keyagr_completion,
980 /* Lists locally saved client and server public keys. */
982 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
988 void silc_channels_init(void)
990 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
991 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
992 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
993 signal_add("mime", (SIGNAL_FUNC) sig_mime);
995 command_bind_silc("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
996 command_bind_silc("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
997 command_bind_silc("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
998 command_bind_silc("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
999 command_bind_silc("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1000 command_bind_silc("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1001 command_bind_silc("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
1003 silc_nicklist_init();
1006 void silc_channels_deinit(void)
1008 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1009 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1010 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1011 signal_remove("mime", (SIGNAL_FUNC) sig_mime);
1013 command_unbind("part", (SIGNAL_FUNC) command_part);
1014 command_unbind("me", (SIGNAL_FUNC) command_me);
1015 command_unbind("action", (SIGNAL_FUNC) command_action);
1016 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1017 command_unbind("away", (SIGNAL_FUNC) command_away);
1018 command_unbind("key", (SIGNAL_FUNC) command_key);
1019 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
1021 silc_nicklist_deinit();