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 bool silc_set_away(const char *reason, SILC_SERVER_REC *server)
363 if (!IS_SILC_SERVER(server) || !server->connected)
366 if (*reason == '\0') {
367 /* Remove any possible away message */
368 silc_client_set_away_message(silc_client, server->conn, NULL);
371 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
374 /* Set the away message */
375 silc_client_set_away_message(silc_client, server->conn, (char *)reason);
378 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
379 SILCTXT_SET_AWAY, reason);
382 server->usermode_away = set;
383 g_free_and_null(server->away_reason);
385 server->away_reason = g_strdup((char *)reason);
387 signal_emit("away mode changed", 1, server);
392 static void command_away(const char *data, SILC_SERVER_REC *server,
395 CMD_SILC_SERVER(server);
397 if (!IS_SILC_SERVER(server) || !server->connected)
398 cmd_return_error(CMDERR_NOT_CONNECTED);
400 g_free_and_null(server->away_reason);
401 if ((data) && (*data != '\0'))
402 server->away_reason = g_strdup(data);
404 silc_command_exec(server, "UMODE",
405 (server->away_reason != NULL) ? "+g" : "-g");
409 int type; /* 1 = msg, 2 = channel */
411 SILC_SERVER_REC *server;
414 /* Key agreement callback that is called after the key agreement protocol
415 has been performed. This is called also if error occured during the
416 key agreement protocol. The `key' is the allocated key material and
417 the caller is responsible of freeing it. The `key' is NULL if error
418 has occured. The application can freely use the `key' to whatever
419 purpose it needs. See lib/silcske/silcske.h for the definition of
420 the SilcSKEKeyMaterial structure. */
422 static void keyagr_completion(SilcClient client,
423 SilcClientConnection conn,
424 SilcClientEntry client_entry,
425 SilcKeyAgreementStatus status,
426 SilcSKEKeyMaterial *key,
429 KeyInternal i = (KeyInternal)context;
432 case SILC_KEY_AGREEMENT_OK:
433 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
434 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
437 /* Set the private key for this client */
438 silc_client_del_private_message_key(client, conn, client_entry);
439 silc_client_add_private_message_key_ske(client, conn, client_entry,
440 NULL, NULL, key, i->responder);
441 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
442 SILCTXT_KEY_AGREEMENT_PRIVMSG,
443 client_entry->nickname);
444 silc_ske_free_key_material(key);
449 case SILC_KEY_AGREEMENT_ERROR:
450 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
451 SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
454 case SILC_KEY_AGREEMENT_FAILURE:
455 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
456 SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
459 case SILC_KEY_AGREEMENT_TIMEOUT:
460 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
461 SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
464 case SILC_KEY_AGREEMENT_ABORTED:
465 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
466 SILCTXT_KEY_AGREEMENT_ABORTED, client_entry->nickname);
469 case SILC_KEY_AGREEMENT_ALREADY_STARTED:
470 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
471 SILCTXT_KEY_AGREEMENT_ALREADY_STARTED,
472 client_entry->nickname);
475 case SILC_KEY_AGREEMENT_SELF_DENIED:
476 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
477 SILCTXT_KEY_AGREEMENT_SELF_DENIED);
488 /* Local command KEY. This command is used to set and unset private
489 keys for channels, set and unset private keys for private messages
490 with remote clients and to send key agreement requests and
491 negotiate the key agreement protocol with remote client. The
492 key agreement is supported only to negotiate private message keys,
493 it currently cannot be used to negotiate private keys for channels,
494 as it is not convenient for that purpose. */
497 SILC_SERVER_REC *server;
503 /* Callback to be called after client information is resolved from the
506 static void silc_client_command_key_get_clients(SilcClient client,
507 SilcClientConnection conn,
508 SilcClientEntry *clients,
509 SilcUInt32 clients_count,
512 KeyGetClients internal = (KeyGetClients)context;
515 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s",
517 silc_free(internal->data);
518 silc_free(internal->nick);
523 signal_emit("command key", 3, internal->data, internal->server,
526 silc_free(internal->data);
527 silc_free(internal->nick);
531 static void command_key(const char *data, SILC_SERVER_REC *server,
534 SilcClientConnection conn;
535 SilcClientEntry *entrys, client_entry = NULL;
536 SilcUInt32 entry_count;
537 SILC_CHANNEL_REC *chanrec = NULL;
538 SilcChannelEntry channel_entry = NULL;
539 char *nickname = NULL, *tmp;
540 int command = 0, port = 0, type = 0;
541 char *hostname = NULL;
542 KeyInternal internal = NULL;
544 unsigned char **argv;
545 SilcUInt32 *argv_lens, *argv_types;
546 char *bindhost = NULL;
548 CMD_SILC_SERVER(server);
550 if (!server || !IS_SILC_SERVER(server) || !server->connected)
551 cmd_return_error(CMDERR_NOT_CONNECTED);
555 /* Now parse all arguments */
556 tmp = g_strconcat("KEY", " ", data, NULL);
557 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
561 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
564 if (!strcasecmp(argv[1], "msg"))
566 if (!strcasecmp(argv[1], "channel"))
570 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
573 if (argv[2][0] == '*') {
574 nickname = strdup("*");
576 /* Parse the typed nickname. */
577 if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
578 printformat_module("fe-common/silc", server, NULL,
579 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
583 /* Find client entry */
584 entrys = silc_client_get_clients_local(silc_client, conn, nickname,
585 argv[2], &entry_count);
587 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
588 inter->server = server;
589 inter->data = strdup(data);
590 inter->nick = strdup(nickname);
592 silc_client_get_clients(silc_client, conn, nickname, argv[2],
593 silc_client_command_key_get_clients, inter);
596 client_entry = entrys[0];
602 /* Get channel entry */
605 if (argv[2][0] == '*') {
606 if (!conn->current_channel) {
608 cmd_return_error(CMDERR_NOT_JOINED);
610 name = conn->current_channel->channel_name;
615 chanrec = silc_channel_find(server, name);
616 if (chanrec == NULL) {
618 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
620 channel_entry = chanrec->entry;
624 if (!strcasecmp(argv[3], "set")) {
628 char *cipher = NULL, *hmac = NULL;
630 if (type == 1 && client_entry) {
631 /* Set private message key */
632 bool responder = FALSE;
634 silc_client_del_private_message_key(silc_client, conn, client_entry);
637 if (!strcasecmp(argv[5], "-responder"))
643 if (!strcasecmp(argv[6], "-responder"))
649 if (!strcasecmp(argv[7], "-responder"))
653 silc_client_add_private_message_key(silc_client, conn, client_entry,
655 argv[4], argv_lens[4],
657 TRUE : FALSE), responder);
659 /* Send the key to the remote client so that it starts using it
661 /* XXX for now we don't do this. This feature is pretty stupid
662 and should perhaps be removed altogether from SILC.
663 silc_client_send_private_message_key(silc_client, conn,
666 } else if (type == 2) {
667 /* Set private channel key */
668 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
669 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
670 SILCTXT_CH_PRIVATE_KEY_NOMODE,
671 channel_entry->channel_name);
680 if (!silc_client_add_channel_private_key(silc_client, conn,
685 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
686 SILCTXT_CH_PRIVATE_KEY_ERROR,
687 channel_entry->channel_name);
691 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
692 SILCTXT_CH_PRIVATE_KEY_ADD,
693 channel_entry->channel_name);
701 if (!strcasecmp(argv[3], "unset")) {
704 if (type == 1 && client_entry) {
705 /* Unset private message key */
706 silc_client_del_private_message_key(silc_client, conn, client_entry);
707 } else if (type == 2) {
708 /* Unset channel key(s) */
709 SilcChannelPrivateKey *keys;
710 SilcUInt32 keys_count;
714 silc_client_del_channel_private_keys(silc_client, conn,
718 number = atoi(argv[4]);
719 keys = silc_client_list_channel_private_keys(silc_client, conn,
725 if (!number || number > keys_count) {
726 silc_client_free_channel_private_keys(keys, keys_count);
730 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
732 silc_client_free_channel_private_keys(keys, keys_count);
740 if (!strcasecmp(argv[3], "list")) {
744 SilcPrivateMessageKeys keys;
745 SilcUInt32 keys_count;
749 keys = silc_client_list_private_message_keys(silc_client, conn,
754 /* list the private message key(s) */
755 if (nickname[0] == '*') {
756 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
757 SILCTXT_PRIVATE_KEY_LIST);
758 for (k = 0; k < keys_count; k++) {
759 memset(buf, 0, sizeof(buf));
760 strncat(buf, " ", 2);
761 len = strlen(keys[k].client_entry->nickname);
762 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
764 for (i = 0; i < 30 - len; i++)
768 len = strlen(keys[k].cipher);
769 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
771 for (i = 0; i < 14 - len; i++)
776 strcat(buf, "<hidden>");
778 strcat(buf, "*generated*");
780 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
783 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
784 SILCTXT_PRIVATE_KEY_LIST_NICK,
785 client_entry->nickname);
786 for (k = 0; k < keys_count; k++) {
787 if (keys[k].client_entry != client_entry)
790 memset(buf, 0, sizeof(buf));
791 strncat(buf, " ", 2);
792 len = strlen(keys[k].client_entry->nickname);
793 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
795 for (i = 0; i < 30 - len; i++)
799 len = strlen(keys[k].cipher);
800 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
802 for (i = 0; i < 14 - len; i++)
807 strcat(buf, "<hidden>");
809 strcat(buf, "*generated*");
811 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
815 silc_client_free_private_message_keys(keys, keys_count);
817 } else if (type == 2) {
818 SilcChannelPrivateKey *keys;
819 SilcUInt32 keys_count;
823 keys = silc_client_list_channel_private_keys(silc_client, conn,
827 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
828 SILCTXT_CH_PRIVATE_KEY_LIST,
829 channel_entry->channel_name);
834 for (k = 0; k < keys_count; k++) {
835 memset(buf, 0, sizeof(buf));
836 strncat(buf, " ", 2);
838 len = strlen(silc_cipher_get_name(keys[k]->cipher));
839 strncat(buf, silc_cipher_get_name(keys[k]->cipher),
840 len > 16 ? 16 : len);
842 for (i = 0; i < 16 - len; i++)
846 len = strlen(silc_hmac_get_name(keys[k]->hmac));
847 strncat(buf, silc_hmac_get_name(keys[k]->hmac), len > 16 ? 16 : len);
849 for (i = 0; i < 16 - len; i++)
853 strcat(buf, "<hidden>");
855 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
858 silc_client_free_channel_private_keys(keys, keys_count);
864 /* Send command is used to send key agreement */
865 if (!strcasecmp(argv[3], "agreement")) {
871 port = atoi(argv[5]);
873 internal = silc_calloc(1, sizeof(*internal));
874 internal->type = type;
875 internal->server = server;
878 if (settings_get_bool("use_auto_addr")) {
880 hostname = (char *)settings_get_str("auto_public_ip");
882 /* If the hostname isn't set, treat this case as if auto_public_ip
884 if ((hostname) && (*hostname == '\0')) {
887 bindhost = (char *)settings_get_str("auto_bind_ip");
889 /* if the bind_ip isn't set, but the public_ip IS, then assume then
890 public_ip is the same value as the bind_ip. */
891 if ((bindhost) && (*bindhost == '\0'))
893 port = settings_get_int("auto_bind_port");
895 } /* if use_auto_addr */
899 /* Start command is used to start key agreement (after receiving the
900 key_agreement client operation). */
901 if (!strcasecmp(argv[3], "negotiate")) {
907 port = atoi(argv[5]);
909 internal = silc_calloc(1, sizeof(*internal));
910 internal->type = type;
911 internal->server = server;
914 /* Change current channel private key */
915 if (!strcasecmp(argv[3], "change")) {
918 /* Unset channel key(s) */
919 SilcChannelPrivateKey *keys;
920 SilcUInt32 keys_count;
923 keys = silc_client_list_channel_private_keys(silc_client, conn,
931 if (chanrec->cur_key >= keys_count)
932 chanrec->cur_key = 0;
936 number = atoi(argv[4]);
937 if (!number || number > keys_count)
938 chanrec->cur_key = 0;
940 chanrec->cur_key = number - 1;
943 /* Set the current channel private key */
944 silc_client_current_channel_private_key(silc_client, conn,
946 keys[chanrec->cur_key]);
947 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
948 SILCTXT_CH_PRIVATE_KEY_CHANGE, chanrec->cur_key + 1,
949 channel_entry->channel_name);
951 silc_client_free_channel_private_keys(keys, keys_count);
957 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
958 "Usage: /KEY msg|channel <nickname|channel> "
959 "set|unset|agreement|negotiate [<arguments>]");
963 if (command == 4 && client_entry) {
964 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
965 SILCTXT_KEY_AGREEMENT, argv[2]);
966 internal->responder = TRUE;
967 silc_client_send_key_agreement(
968 silc_client, conn, client_entry, hostname,
970 settings_get_int("key_exchange_timeout_secs"),
971 keyagr_completion, internal);
977 if (command == 5 && client_entry && hostname) {
978 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
979 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
980 internal->responder = FALSE;
981 silc_client_perform_key_agreement(silc_client, conn, client_entry,
982 hostname, port, keyagr_completion,
991 /* Lists locally saved client and server public keys. */
993 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
999 void silc_channels_init(void)
1001 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1002 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1003 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1005 command_bind_silc("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1006 command_bind_silc("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1007 command_bind_silc("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1008 command_bind_silc("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1009 command_bind_silc("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1010 command_bind_silc("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1011 command_bind_silc("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
1013 silc_nicklist_init();
1016 void silc_channels_deinit(void)
1018 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1019 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1020 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1022 command_unbind("part", (SIGNAL_FUNC) command_part);
1023 command_unbind("me", (SIGNAL_FUNC) command_me);
1024 command_unbind("action", (SIGNAL_FUNC) command_action);
1025 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1026 command_unbind("away", (SIGNAL_FUNC) command_away);
1027 command_unbind("key", (SIGNAL_FUNC) command_key);
1028 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
1030 silc_nicklist_deinit();