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 static void sig_gui_quit(SILC_SERVER_REC *server, const char *msg)
114 silc_client_stop(silc_client);
117 /* Find Irssi channel entry by SILC channel entry */
119 SILC_CHANNEL_REC *silc_channel_find_entry(SILC_SERVER_REC *server,
120 SilcChannelEntry entry)
124 g_return_val_if_fail(IS_SILC_SERVER(server), NULL);
126 for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
127 SILC_CHANNEL_REC *rec = tmp->data;
129 if (rec->entry == entry)
136 /* PART (LEAVE) command. */
138 static void command_part(const char *data, SILC_SERVER_REC *server,
141 SILC_CHANNEL_REC *chanrec;
144 CMD_SILC_SERVER(server);
146 if (!IS_SILC_SERVER(server) || !server->connected)
147 cmd_return_error(CMDERR_NOT_CONNECTED);
149 if (!strcmp(data, "*") || *data == '\0') {
150 if (!IS_SILC_CHANNEL(item))
151 cmd_return_error(CMDERR_NOT_JOINED);
152 data = item->visible_name;
155 chanrec = silc_channel_find(server, data);
157 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
159 memset(userhost, 0, sizeof(userhost));
160 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
161 server->conn->local_entry->username,
162 server->conn->local_entry->hostname);
163 signal_emit("message part", 5, server, chanrec->name,
164 server->nick, userhost, "");
166 chanrec->left = TRUE;
167 silc_command_exec(server, "LEAVE", chanrec->name);
170 channel_destroy(CHANNEL(chanrec));
173 /* ME local command. */
175 static void command_me(const char *data, SILC_SERVER_REC *server,
178 SILC_CHANNEL_REC *chanrec;
179 char *tmpcmd = "ME", *tmp;
181 unsigned char *message = NULL;
182 unsigned char **argv;
183 SilcUInt32 *argv_lens, *argv_types;
186 CMD_SILC_SERVER(server);
188 if (!IS_SILC_SERVER(server) || !server->connected)
189 cmd_return_error(CMDERR_NOT_CONNECTED);
191 if (!IS_SILC_CHANNEL(item))
192 cmd_return_error(CMDERR_NOT_JOINED);
194 /* Now parse all arguments */
195 tmp = g_strconcat(tmpcmd, " ", data, NULL);
196 silc_parse_command_line(tmp, &argv, &argv_lens,
197 &argv_types, &argc, 2);
201 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
203 chanrec = silc_channel_find(server, item->visible_name);
205 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
207 if (!silc_term_utf8()) {
208 int len = silc_utf8_encoded_len(argv[1], argv_lens[1],
209 SILC_STRING_LANGUAGE);
210 message = silc_calloc(len + 1, sizeof(*message));
211 g_return_if_fail(message != NULL);
212 silc_utf8_encode(argv[1], argv_lens[1], SILC_STRING_LANGUAGE,
216 /* Send the action message */
217 silc_client_send_channel_message(silc_client, server->conn,
218 chanrec->entry, NULL,
219 SILC_MESSAGE_FLAG_ACTION |
220 SILC_MESSAGE_FLAG_UTF8,
221 message ? message : argv[1],
222 message ? strlen(message) : argv_lens[1],
225 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
226 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
227 server->conn->local_entry->nickname, argv[1]);
229 for (i = 0; i < argc; i++)
231 silc_free(argv_lens);
232 silc_free(argv_types);
236 /* ACTION local command. Same as ME but takes the channel as mandatory
239 static void command_action(const char *data, SILC_SERVER_REC *server,
242 SILC_CHANNEL_REC *chanrec;
243 char *tmpcmd = "ME", *tmp;
245 unsigned char *message = NULL;
246 unsigned char **argv;
247 SilcUInt32 *argv_lens, *argv_types;
250 CMD_SILC_SERVER(server);
251 if (!IS_SILC_SERVER(server) || !server->connected)
252 cmd_return_error(CMDERR_NOT_CONNECTED);
254 if (!IS_SILC_CHANNEL(item))
255 cmd_return_error(CMDERR_NOT_JOINED);
257 /* Now parse all arguments */
258 tmp = g_strconcat(tmpcmd, " ", data, NULL);
259 silc_parse_command_line(tmp, &argv, &argv_lens,
260 &argv_types, &argc, 3);
264 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
266 chanrec = silc_channel_find(server, argv[1]);
268 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
270 if (!silc_term_utf8()) {
271 int len = silc_utf8_encoded_len(argv[2], argv_lens[2],
272 SILC_STRING_LANGUAGE);
273 message = silc_calloc(len + 1, sizeof(*message));
274 g_return_if_fail(message != NULL);
275 silc_utf8_encode(argv[2], argv_lens[2], SILC_STRING_LANGUAGE,
279 /* Send the action message */
280 silc_client_send_channel_message(silc_client, server->conn,
281 chanrec->entry, NULL,
282 SILC_MESSAGE_FLAG_ACTION |
283 SILC_MESSAGE_FLAG_UTF8,
284 message ? message : argv[2],
285 message ? strlen(message) : argv_lens[2],
288 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
289 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
290 server->conn->local_entry->nickname, argv[2]);
292 for (i = 0; i < argc; i++)
294 silc_free(argv_lens);
295 silc_free(argv_types);
299 /* NOTICE local command. */
301 static void command_notice(const char *data, SILC_SERVER_REC *server,
304 SILC_CHANNEL_REC *chanrec;
305 char *tmpcmd = "ME", *tmp;
307 unsigned char *message = NULL;
308 unsigned char **argv;
309 SilcUInt32 *argv_lens, *argv_types;
312 CMD_SILC_SERVER(server);
313 if (!IS_SILC_SERVER(server) || !server->connected)
314 cmd_return_error(CMDERR_NOT_CONNECTED);
316 if (!IS_SILC_CHANNEL(item))
317 cmd_return_error(CMDERR_NOT_JOINED);
319 /* Now parse all arguments */
320 tmp = g_strconcat(tmpcmd, " ", data, NULL);
321 silc_parse_command_line(tmp, &argv, &argv_lens,
322 &argv_types, &argc, 2);
326 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
328 chanrec = silc_channel_find(server, item->visible_name);
330 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
332 if (!silc_term_utf8()) {
333 int len = silc_utf8_encoded_len(argv[1], argv_lens[1],
334 SILC_STRING_LANGUAGE);
335 message = silc_calloc(len + 1, sizeof(*message));
336 g_return_if_fail(message != NULL);
337 silc_utf8_encode(argv[1], argv_lens[1], SILC_STRING_LANGUAGE,
341 /* Send the action message */
342 silc_client_send_channel_message(silc_client, server->conn,
343 chanrec->entry, NULL,
344 SILC_MESSAGE_FLAG_NOTICE |
345 SILC_MESSAGE_FLAG_UTF8,
346 message ? message : argv[1],
347 message ? strlen(message) : argv_lens[1],
350 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
351 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_OWNNOTICE,
352 server->conn->local_entry->nickname, argv[1]);
354 for (i = 0; i < argc; i++)
356 silc_free(argv_lens);
357 silc_free(argv_types);
361 /* AWAY local command. Sends UMODE command that sets the SILC_UMODE_GONE
364 bool silc_set_away(const char *reason, SILC_SERVER_REC *server)
368 if (!IS_SILC_SERVER(server) || !server->connected)
371 if (*reason == '\0') {
372 /* Remove any possible away message */
373 silc_client_set_away_message(silc_client, server->conn, NULL);
376 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
379 /* Set the away message */
380 silc_client_set_away_message(silc_client, server->conn, (char *)reason);
383 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
384 SILCTXT_SET_AWAY, reason);
387 server->usermode_away = set;
388 g_free_and_null(server->away_reason);
390 server->away_reason = g_strdup((char *)reason);
392 signal_emit("away mode changed", 1, server);
397 static void command_away(const char *data, SILC_SERVER_REC *server,
400 CMD_SILC_SERVER(server);
402 if (!IS_SILC_SERVER(server) || !server->connected)
403 cmd_return_error(CMDERR_NOT_CONNECTED);
405 g_free_and_null(server->away_reason);
406 if ((data) && (*data != '\0'))
407 server->away_reason = g_strdup(data);
409 silc_command_exec(server, "UMODE",
410 (server->away_reason != NULL) ? "+g" : "-g");
414 int type; /* 1 = msg, 2 = channel */
416 SILC_SERVER_REC *server;
419 /* Key agreement callback that is called after the key agreement protocol
420 has been performed. This is called also if error occured during the
421 key agreement protocol. The `key' is the allocated key material and
422 the caller is responsible of freeing it. The `key' is NULL if error
423 has occured. The application can freely use the `key' to whatever
424 purpose it needs. See lib/silcske/silcske.h for the definition of
425 the SilcSKEKeyMaterial structure. */
427 static void keyagr_completion(SilcClient client,
428 SilcClientConnection conn,
429 SilcClientEntry client_entry,
430 SilcKeyAgreementStatus status,
431 SilcSKEKeyMaterial *key,
434 KeyInternal i = (KeyInternal)context;
437 case SILC_KEY_AGREEMENT_OK:
438 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
439 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
442 /* Set the private key for this client */
443 silc_client_del_private_message_key(client, conn, client_entry);
444 silc_client_add_private_message_key_ske(client, conn, client_entry,
445 NULL, NULL, key, i->responder);
446 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
447 SILCTXT_KEY_AGREEMENT_PRIVMSG,
448 client_entry->nickname);
449 silc_ske_free_key_material(key);
454 case SILC_KEY_AGREEMENT_ERROR:
455 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
456 SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
459 case SILC_KEY_AGREEMENT_FAILURE:
460 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
461 SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
464 case SILC_KEY_AGREEMENT_TIMEOUT:
465 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
466 SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
469 case SILC_KEY_AGREEMENT_ABORTED:
470 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
471 SILCTXT_KEY_AGREEMENT_ABORTED, client_entry->nickname);
474 case SILC_KEY_AGREEMENT_ALREADY_STARTED:
475 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
476 SILCTXT_KEY_AGREEMENT_ALREADY_STARTED,
477 client_entry->nickname);
480 case SILC_KEY_AGREEMENT_SELF_DENIED:
481 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
482 SILCTXT_KEY_AGREEMENT_SELF_DENIED);
493 /* Local command KEY. This command is used to set and unset private
494 keys for channels, set and unset private keys for private messages
495 with remote clients and to send key agreement requests and
496 negotiate the key agreement protocol with remote client. The
497 key agreement is supported only to negotiate private message keys,
498 it currently cannot be used to negotiate private keys for channels,
499 as it is not convenient for that purpose. */
502 SILC_SERVER_REC *server;
508 /* Callback to be called after client information is resolved from the
511 static void silc_client_command_key_get_clients(SilcClient client,
512 SilcClientConnection conn,
513 SilcClientEntry *clients,
514 SilcUInt32 clients_count,
517 KeyGetClients internal = (KeyGetClients)context;
520 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s",
522 silc_free(internal->data);
523 silc_free(internal->nick);
528 signal_emit("command key", 3, internal->data, internal->server,
531 silc_free(internal->data);
532 silc_free(internal->nick);
536 static void command_key(const char *data, SILC_SERVER_REC *server,
539 SilcClientConnection conn;
540 SilcClientEntry *entrys, client_entry = NULL;
541 SilcUInt32 entry_count;
542 SILC_CHANNEL_REC *chanrec = NULL;
543 SilcChannelEntry channel_entry = NULL;
544 char *nickname = NULL, *tmp;
545 int command = 0, port = 0, type = 0;
546 char *hostname = NULL;
547 KeyInternal internal = NULL;
549 unsigned char **argv;
550 SilcUInt32 *argv_lens, *argv_types;
551 char *bindhost = NULL;
553 CMD_SILC_SERVER(server);
555 if (!server || !IS_SILC_SERVER(server) || !server->connected)
556 cmd_return_error(CMDERR_NOT_CONNECTED);
560 /* Now parse all arguments */
561 tmp = g_strconcat("KEY", " ", data, NULL);
562 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
566 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
569 if (!strcasecmp(argv[1], "msg"))
571 if (!strcasecmp(argv[1], "channel"))
575 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
578 if (argv[2][0] == '*') {
579 nickname = strdup("*");
581 /* Parse the typed nickname. */
582 if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
583 printformat_module("fe-common/silc", server, NULL,
584 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
588 /* Find client entry */
589 entrys = silc_client_get_clients_local(silc_client, conn, nickname,
590 argv[2], &entry_count);
592 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
593 inter->server = server;
594 inter->data = strdup(data);
595 inter->nick = strdup(nickname);
597 silc_client_get_clients(silc_client, conn, nickname, argv[2],
598 silc_client_command_key_get_clients, inter);
601 client_entry = entrys[0];
607 /* Get channel entry */
610 if (argv[2][0] == '*') {
611 if (!conn->current_channel) {
613 cmd_return_error(CMDERR_NOT_JOINED);
615 name = conn->current_channel->channel_name;
620 chanrec = silc_channel_find(server, name);
621 if (chanrec == NULL) {
623 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
625 channel_entry = chanrec->entry;
629 if (!strcasecmp(argv[3], "set")) {
633 char *cipher = NULL, *hmac = NULL;
635 if (type == 1 && client_entry) {
636 /* Set private message key */
637 bool responder = FALSE;
639 silc_client_del_private_message_key(silc_client, conn, client_entry);
642 if (!strcasecmp(argv[5], "-responder"))
648 if (!strcasecmp(argv[6], "-responder"))
654 if (!strcasecmp(argv[7], "-responder"))
658 silc_client_add_private_message_key(silc_client, conn, client_entry,
660 argv[4], argv_lens[4],
662 TRUE : FALSE), responder);
664 /* Send the key to the remote client so that it starts using it
666 /* XXX for now we don't do this. This feature is pretty stupid
667 and should perhaps be removed altogether from SILC.
668 silc_client_send_private_message_key(silc_client, conn,
671 } else if (type == 2) {
672 /* Set private channel key */
673 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
674 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
675 SILCTXT_CH_PRIVATE_KEY_NOMODE,
676 channel_entry->channel_name);
685 if (!silc_client_add_channel_private_key(silc_client, conn,
690 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
691 SILCTXT_CH_PRIVATE_KEY_ERROR,
692 channel_entry->channel_name);
696 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
697 SILCTXT_CH_PRIVATE_KEY_ADD,
698 channel_entry->channel_name);
706 if (!strcasecmp(argv[3], "unset")) {
709 if (type == 1 && client_entry) {
710 /* Unset private message key */
711 silc_client_del_private_message_key(silc_client, conn, client_entry);
712 } else if (type == 2) {
713 /* Unset channel key(s) */
714 SilcChannelPrivateKey *keys;
715 SilcUInt32 keys_count;
719 silc_client_del_channel_private_keys(silc_client, conn,
723 number = atoi(argv[4]);
724 keys = silc_client_list_channel_private_keys(silc_client, conn,
730 if (!number || number > keys_count) {
731 silc_client_free_channel_private_keys(keys, keys_count);
735 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
737 silc_client_free_channel_private_keys(keys, keys_count);
745 if (!strcasecmp(argv[3], "list")) {
749 SilcPrivateMessageKeys keys;
750 SilcUInt32 keys_count;
754 keys = silc_client_list_private_message_keys(silc_client, conn,
759 /* list the private message key(s) */
760 if (nickname[0] == '*') {
761 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
762 SILCTXT_PRIVATE_KEY_LIST);
763 for (k = 0; k < keys_count; k++) {
764 memset(buf, 0, sizeof(buf));
765 strncat(buf, " ", 2);
766 len = strlen(keys[k].client_entry->nickname);
767 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
769 for (i = 0; i < 30 - len; i++)
773 len = strlen(keys[k].cipher);
774 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
776 for (i = 0; i < 14 - len; i++)
781 strcat(buf, "<hidden>");
783 strcat(buf, "*generated*");
785 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
788 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
789 SILCTXT_PRIVATE_KEY_LIST_NICK,
790 client_entry->nickname);
791 for (k = 0; k < keys_count; k++) {
792 if (keys[k].client_entry != client_entry)
795 memset(buf, 0, sizeof(buf));
796 strncat(buf, " ", 2);
797 len = strlen(keys[k].client_entry->nickname);
798 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
800 for (i = 0; i < 30 - len; i++)
804 len = strlen(keys[k].cipher);
805 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
807 for (i = 0; i < 14 - len; i++)
812 strcat(buf, "<hidden>");
814 strcat(buf, "*generated*");
816 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
820 silc_client_free_private_message_keys(keys, keys_count);
822 } else if (type == 2) {
823 SilcChannelPrivateKey *keys;
824 SilcUInt32 keys_count;
828 keys = silc_client_list_channel_private_keys(silc_client, conn,
832 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
833 SILCTXT_CH_PRIVATE_KEY_LIST,
834 channel_entry->channel_name);
839 for (k = 0; k < keys_count; k++) {
840 memset(buf, 0, sizeof(buf));
841 strncat(buf, " ", 2);
843 len = strlen(silc_cipher_get_name(keys[k]->cipher));
844 strncat(buf, silc_cipher_get_name(keys[k]->cipher),
845 len > 16 ? 16 : len);
847 for (i = 0; i < 16 - len; i++)
851 len = strlen(silc_hmac_get_name(keys[k]->hmac));
852 strncat(buf, silc_hmac_get_name(keys[k]->hmac), len > 16 ? 16 : len);
854 for (i = 0; i < 16 - len; i++)
858 strcat(buf, "<hidden>");
860 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
863 silc_client_free_channel_private_keys(keys, keys_count);
869 /* Send command is used to send key agreement */
870 if (!strcasecmp(argv[3], "agreement")) {
876 port = atoi(argv[5]);
878 internal = silc_calloc(1, sizeof(*internal));
879 internal->type = type;
880 internal->server = server;
883 if (settings_get_bool("use_auto_addr")) {
885 hostname = (char *)settings_get_str("auto_public_ip");
887 /* If the hostname isn't set, treat this case as if auto_public_ip
889 if ((hostname) && (*hostname == '\0')) {
892 bindhost = (char *)settings_get_str("auto_bind_ip");
894 /* if the bind_ip isn't set, but the public_ip IS, then assume then
895 public_ip is the same value as the bind_ip. */
896 if ((bindhost) && (*bindhost == '\0'))
898 port = settings_get_int("auto_bind_port");
900 } /* if use_auto_addr */
904 /* Start command is used to start key agreement (after receiving the
905 key_agreement client operation). */
906 if (!strcasecmp(argv[3], "negotiate")) {
912 port = atoi(argv[5]);
914 internal = silc_calloc(1, sizeof(*internal));
915 internal->type = type;
916 internal->server = server;
919 /* Change current channel private key */
920 if (!strcasecmp(argv[3], "change")) {
923 /* Unset channel key(s) */
924 SilcChannelPrivateKey *keys;
925 SilcUInt32 keys_count;
928 keys = silc_client_list_channel_private_keys(silc_client, conn,
936 if (chanrec->cur_key >= keys_count)
937 chanrec->cur_key = 0;
941 number = atoi(argv[4]);
942 if (!number || number > keys_count)
943 chanrec->cur_key = 0;
945 chanrec->cur_key = number - 1;
948 /* Set the current channel private key */
949 silc_client_current_channel_private_key(silc_client, conn,
951 keys[chanrec->cur_key]);
952 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
953 SILCTXT_CH_PRIVATE_KEY_CHANGE, chanrec->cur_key + 1,
954 channel_entry->channel_name);
956 silc_client_free_channel_private_keys(keys, keys_count);
962 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
963 "Usage: /KEY msg|channel <nickname|channel> "
964 "set|unset|agreement|negotiate [<arguments>]");
968 if (command == 4 && client_entry) {
969 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
970 SILCTXT_KEY_AGREEMENT, argv[2]);
971 internal->responder = TRUE;
972 silc_client_send_key_agreement(
973 silc_client, conn, client_entry, hostname,
975 settings_get_int("key_exchange_timeout_secs"),
976 keyagr_completion, internal);
982 if (command == 5 && client_entry && hostname) {
983 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
984 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
985 internal->responder = FALSE;
986 silc_client_perform_key_agreement(silc_client, conn, client_entry,
987 hostname, port, keyagr_completion,
996 /* Lists locally saved client and server public keys. */
998 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
1004 void silc_channels_init(void)
1006 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1007 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1008 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1009 signal_add("gui exit", (SIGNAL_FUNC) sig_gui_quit);
1011 command_bind_silc("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1012 command_bind_silc("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1013 command_bind_silc("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1014 command_bind_silc("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1015 command_bind_silc("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1016 command_bind_silc("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1017 command_bind_silc("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
1019 silc_nicklist_init();
1022 void silc_channels_deinit(void)
1024 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1025 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1026 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1027 signal_remove("gui exit", (SIGNAL_FUNC) sig_gui_quit);
1029 command_unbind("part", (SIGNAL_FUNC) command_part);
1030 command_unbind("me", (SIGNAL_FUNC) command_me);
1031 command_unbind("action", (SIGNAL_FUNC) command_action);
1032 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1033 command_unbind("away", (SIGNAL_FUNC) command_away);
1034 command_unbind("key", (SIGNAL_FUNC) command_key);
1035 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
1037 silc_nicklist_deinit();