2 silc-channels.c : irssi
4 Copyright (C) 2000 - 2001, 2004, 2006, 2007 Timo Sirainen
5 Pekka Riikonen <priikone@silcnet.org>
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 "silc-cmdqueue.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 const char *blob, const char *nick, int verified)
52 unsigned char *message;
53 SilcUInt32 message_len;
56 if (!(IS_SILC_SERVER(server)))
59 message = silc_unescape_data(blob, &message_len);
61 mime = silc_mime_decode(NULL, message, message_len);
67 printformat_module("fe-common/silc", server,
68 channel == NULL ? NULL : channel->name,
69 MSGLEVEL_CRAP, SILCTXT_MESSAGE_DATA,
70 nick == NULL ? "[<unknown>]" : nick,
71 silc_mime_get_field(mime, "Content-Type"));
77 SILC_CHANNEL_REC *silc_channel_create(SILC_SERVER_REC *server,
79 const char *visible_name,
82 SILC_CHANNEL_REC *rec;
84 g_return_val_if_fail(server == NULL || IS_SILC_SERVER(server), NULL);
85 g_return_val_if_fail(name != NULL, NULL);
87 rec = g_new0(SILC_CHANNEL_REC, 1);
88 rec->chat_type = SILC_PROTOCOL;
89 channel_init((CHANNEL_REC *)rec, (SERVER_REC *)server, name, name,
94 static void sig_channel_destroyed(SILC_CHANNEL_REC *channel)
96 if (!IS_SILC_CHANNEL(channel))
98 if (channel->server && channel->server->disconnected)
101 if (channel->server != NULL && !channel->left && !channel->kicked) {
102 /* destroying channel record without actually
103 having left the channel yet */
104 silc_command_exec(channel->server, "LEAVE", channel->name);
105 /* enable queueing because we destroy the channel immedially */
106 silc_queue_enable(channel->server->conn);
110 static void silc_channels_join(SILC_SERVER_REC *server,
111 const char *channels, int automatic)
114 SILC_CHANNEL_REC *chanrec;
116 list = g_strsplit(channels, ",", -1);
117 for (tmp = list; *tmp != NULL; tmp++) {
118 chanrec = silc_channel_find(server, *tmp);
122 silc_command_exec(server, "JOIN", *tmp);
128 static void sig_connected(SILC_SERVER_REC *server)
130 if (IS_SILC_SERVER(server))
131 server->channels_join = (void *) silc_channels_join;
134 /* "server quit" signal from the core to indicate that QUIT command
137 static void sig_server_quit(SILC_SERVER_REC *server, const char *msg)
139 if (IS_SILC_SERVER(server) && server->conn)
140 silc_command_exec(server, "QUIT", msg);
143 /* Find Irssi channel entry by SILC channel entry */
145 SILC_CHANNEL_REC *silc_channel_find_entry(SILC_SERVER_REC *server,
146 SilcChannelEntry entry)
150 g_return_val_if_fail(IS_SILC_SERVER(server), NULL);
152 for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
153 SILC_CHANNEL_REC *rec = tmp->data;
155 if (rec->entry == entry)
162 /* PART (LEAVE) command. */
164 static void command_part(const char *data, SILC_SERVER_REC *server,
167 SILC_CHANNEL_REC *chanrec;
170 CMD_SILC_SERVER(server);
172 if (!IS_SILC_SERVER(server) || !server->connected)
173 cmd_return_error(CMDERR_NOT_CONNECTED);
175 if (!strcmp(data, "*") || *data == '\0') {
176 if (!IS_SILC_CHANNEL(item))
177 cmd_return_error(CMDERR_NOT_JOINED);
178 data = item->visible_name;
181 chanrec = silc_channel_find(server, data);
183 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
185 memset(userhost, 0, sizeof(userhost));
186 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
187 server->conn->local_entry->username,
188 server->conn->local_entry->hostname);
189 signal_emit("message part", 5, server, chanrec->name,
190 server->nick, userhost, "");
192 chanrec->left = TRUE;
193 silc_command_exec(server, "LEAVE", chanrec->name);
194 /* enable queueing because we destroy the channel immedially */
195 silc_queue_enable(server->conn);
198 channel_destroy(CHANNEL(chanrec));
202 /* ACTION local command. */
204 static void command_action(const char *data, SILC_SERVER_REC *server,
209 char *message = NULL;
212 SilcBool sign = FALSE;
214 CMD_SILC_SERVER(server);
215 if (!IS_SILC_SERVER(server) || !server->connected)
216 cmd_return_error(CMDERR_NOT_CONNECTED);
218 if ((item != NULL) && (!IS_SILC_CHANNEL(item) && !IS_SILC_QUERY(item)))
219 cmd_return_error(CMDERR_NOT_JOINED);
221 /* Now parse all arguments */
222 if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS |
224 "action", &optlist, &target, &msg))
227 if (*target == '\0' || *msg == '\0')
228 cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
230 if (strcmp(target, "*") == 0) {
231 /* send to active channel/query */
233 cmd_param_error(CMDERR_NOT_JOINED);
235 target_type = IS_SILC_CHANNEL(item) ?
236 SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
237 target = (char *)window_item_get_target(item);
238 } else if (g_hash_table_lookup(optlist, "channel") != NULL)
239 target_type = SEND_TARGET_CHANNEL;
241 target_type = SEND_TARGET_NICK;
244 if (!silc_term_utf8()) {
245 int len = silc_utf8_encoded_len(msg, strlen(msg),
247 message = silc_calloc(len + 1, sizeof(*message));
248 g_return_if_fail(message != NULL);
249 silc_utf8_encode(msg, strlen(msg), SILC_STRING_LOCALE,
253 if (target != NULL) {
254 if (target_type == SEND_TARGET_CHANNEL) {
255 sign = (g_hash_table_lookup(optlist, "sign") ? TRUE :
256 settings_get_bool("sign_channel_messages") ? TRUE : FALSE);
257 if (silc_send_channel(server, target, (message != NULL ? message : msg),
258 SILC_MESSAGE_FLAG_ACTION | SILC_MESSAGE_FLAG_UTF8 |
259 (sign ? SILC_MESSAGE_FLAG_SIGNED : 0))) {
260 if (g_hash_table_lookup(optlist, "sign"))
261 signal_emit("message silc signed_own_action", 3, server, msg, target);
263 signal_emit("message silc own_action", 3, server, msg, target);
266 sign = (g_hash_table_lookup(optlist, "sign") ? TRUE :
267 settings_get_bool("sign_private_messages") ? TRUE : FALSE);
268 if (silc_send_msg(server, target, (message != NULL ? message : msg),
269 (message != NULL ? strlen(message) : strlen(msg)),
270 SILC_MESSAGE_FLAG_ACTION | SILC_MESSAGE_FLAG_UTF8 |
271 (sign ? SILC_MESSAGE_FLAG_SIGNED : 0))) {
272 if (g_hash_table_lookup(optlist, "sign"))
273 signal_emit("message silc signed_own_private_action", 3,
274 server, msg, target);
276 signal_emit("message silc own_private_action", 3,
277 server, msg, target);
282 cmd_params_free(free_arg);
286 /* ME local command. */
288 static void command_me(const char *data, SILC_SERVER_REC *server,
293 CMD_SILC_SERVER(server);
294 if (!IS_SILC_SERVER(server) || !server->connected)
295 cmd_return_error(CMDERR_NOT_CONNECTED);
297 if (!IS_SILC_CHANNEL(item) && !IS_SILC_QUERY(item))
298 cmd_return_error(CMDERR_NOT_JOINED);
300 if (IS_SILC_CHANNEL(item))
301 tmpcmd = g_strdup_printf("-channel %s %s", item->visible_name, data);
303 tmpcmd = g_strdup_printf("%s %s", item->visible_name, data);
305 command_action(tmpcmd, server, item);
309 /* NOTICE local command. */
311 static void command_notice(const char *data, SILC_SERVER_REC *server,
316 char *message = NULL;
321 CMD_SILC_SERVER(server);
322 if (!IS_SILC_SERVER(server) || !server->connected)
323 cmd_return_error(CMDERR_NOT_CONNECTED);
325 if ((item != NULL) && (!IS_SILC_CHANNEL(item) && !IS_SILC_QUERY(item)))
326 cmd_return_error(CMDERR_NOT_JOINED);
328 /* Now parse all arguments */
329 if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS |
331 "notice", &optlist, &target, &msg))
334 if (*target == '\0' || *msg == '\0')
335 cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
337 if (strcmp(target, "*") == 0) {
338 /* send to active channel/query */
340 cmd_param_error(CMDERR_NOT_JOINED);
342 target_type = IS_SILC_CHANNEL(item) ?
343 SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
344 target = (char *)window_item_get_target(item);
345 } else if (g_hash_table_lookup(optlist, "channel") != NULL)
346 target_type = SEND_TARGET_CHANNEL;
348 target_type = SEND_TARGET_NICK;
351 if (!silc_term_utf8()) {
352 int len = silc_utf8_encoded_len(msg, strlen(msg),
354 message = silc_calloc(len + 1, sizeof(*message));
355 g_return_if_fail(message != NULL);
356 silc_utf8_encode(msg, strlen(msg), SILC_STRING_LOCALE,
360 if (target != NULL) {
361 if (target_type == SEND_TARGET_CHANNEL) {
362 sign = (g_hash_table_lookup(optlist, "sign") ? TRUE :
363 settings_get_bool("sign_channel_messages") ? TRUE : FALSE);
364 if (silc_send_channel(server, target, (message != NULL ? message : msg),
365 SILC_MESSAGE_FLAG_NOTICE | SILC_MESSAGE_FLAG_UTF8 |
366 (sign ? SILC_MESSAGE_FLAG_SIGNED : 0))) {
367 if (g_hash_table_lookup(optlist, "sign"))
368 signal_emit("message silc signed_own_notice", 3, server, msg, target);
370 signal_emit("message silc own_notice", 3, server, msg, target);
373 sign = (g_hash_table_lookup(optlist, "sign") ? TRUE :
374 settings_get_bool("sign_private_messages") ? TRUE : FALSE);
375 if (silc_send_msg(server, target, (message != NULL ? message : msg),
376 (message != NULL ? strlen(message) : strlen(msg)),
377 SILC_MESSAGE_FLAG_NOTICE | SILC_MESSAGE_FLAG_UTF8 |
378 (sign ? SILC_MESSAGE_FLAG_SIGNED : 0))) {
379 if (g_hash_table_lookup(optlist, "sign"))
380 signal_emit("message silc signed_own_private_notice", 3,
381 server, msg, target);
383 signal_emit("message silc own_private_notice", 3,
384 server, msg, target);
389 cmd_params_free(free_arg);
393 /* AWAY local command. Sends UMODE command that sets the SILC_UMODE_GONE
396 bool silc_set_away(const char *reason, SILC_SERVER_REC *server)
400 if (!IS_SILC_SERVER(server) || !server->connected)
403 if (*reason == '\0') {
404 /* Remove any possible away message */
405 silc_client_set_away_message(silc_client, server->conn, NULL);
408 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
411 /* Set the away message */
412 silc_client_set_away_message(silc_client, server->conn, (char *)reason);
415 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
416 SILCTXT_SET_AWAY, reason);
419 server->usermode_away = set;
420 g_free_and_null(server->away_reason);
422 server->away_reason = g_strdup((char *)reason);
424 signal_emit("away mode changed", 1, server);
429 static void command_away(const char *data, SILC_SERVER_REC *server,
432 CMD_SILC_SERVER(server);
434 if (!IS_SILC_SERVER(server) || !server->connected)
435 cmd_return_error(CMDERR_NOT_CONNECTED);
437 g_free_and_null(server->away_reason);
438 if ((data) && (*data != '\0'))
439 server->away_reason = g_strdup(data);
441 silc_command_exec(server, "UMODE",
442 (server->away_reason != NULL) ? "+g" : "-g");
446 SILC_SERVER_REC *server;
447 int type; /* 1 = msg, 2 = channel */
451 /* Key agreement callback that is called after the key agreement protocol
452 has been performed. This is called also if error occured during the
453 key agreement protocol. The `key' is the allocated key material and
454 the caller is responsible of freeing it. The `key' is NULL if error
455 has occured. The application can freely use the `key' to whatever
456 purpose it needs. See lib/silcske/silcske.h for the definition of
457 the SilcSKEKeyMaterial structure. */
459 static void keyagr_completion(SilcClient client,
460 SilcClientConnection conn,
461 SilcClientEntry client_entry,
462 SilcKeyAgreementStatus status,
463 SilcSKEKeyMaterial key,
466 KeyInternal i = (KeyInternal)context;
469 case SILC_KEY_AGREEMENT_OK:
470 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
471 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
474 /* Set the private key for this client */
475 silc_client_del_private_message_key(client, conn, client_entry);
476 silc_client_add_private_message_key_ske(client, conn, client_entry,
478 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
479 SILCTXT_KEY_AGREEMENT_PRIVMSG,
480 client_entry->nickname);
481 silc_ske_free_key_material(key);
486 case SILC_KEY_AGREEMENT_ERROR:
487 case SILC_KEY_AGREEMENT_NO_MEMORY:
488 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
489 SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
492 case SILC_KEY_AGREEMENT_FAILURE:
493 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
494 SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
497 case SILC_KEY_AGREEMENT_TIMEOUT:
498 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
499 SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
502 case SILC_KEY_AGREEMENT_ABORTED:
503 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
504 SILCTXT_KEY_AGREEMENT_ABORTED, client_entry->nickname);
507 case SILC_KEY_AGREEMENT_ALREADY_STARTED:
508 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
509 SILCTXT_KEY_AGREEMENT_ALREADY_STARTED,
510 client_entry->nickname);
513 case SILC_KEY_AGREEMENT_SELF_DENIED:
514 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
515 SILCTXT_KEY_AGREEMENT_SELF_DENIED);
526 /* Local command KEY. This command is used to set and unset private
527 keys for channels, set and unset private keys for private messages
528 with remote clients and to send key agreement requests and
529 negotiate the key agreement protocol with remote client. The
530 key agreement is supported only to negotiate private message keys,
531 it currently cannot be used to negotiate private keys for channels,
532 as it is not convenient for that purpose. */
535 SILC_SERVER_REC *server;
541 /* Callback to be called after client information is resolved from the
544 static void silc_client_command_key_get_clients(SilcClient client,
545 SilcClientConnection conn,
550 KeyGetClients internal = (KeyGetClients)context;
553 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s",
555 silc_free(internal->data);
556 silc_free(internal->nick);
561 signal_emit("command key", 3, internal->data, internal->server,
564 silc_free(internal->data);
565 silc_free(internal->nick);
569 static void command_key(const char *data, SILC_SERVER_REC *server,
572 SilcClientConnection conn;
573 SilcClientEntry client_entry = NULL;
575 SILC_CHANNEL_REC *chanrec = NULL;
576 SilcChannelEntry channel_entry = NULL;
577 char nickname[128 + 1], *tmp;
578 int command = 0, port = 0, type = 0;
579 char *hostname = NULL;
580 KeyInternal internal = NULL;
582 unsigned char **argv;
583 SilcUInt32 *argv_lens, *argv_types;
584 char *bindhost = NULL;
585 SilcChannelPrivateKey ch = NULL;
587 SilcBool udp = FALSE;
590 CMD_SILC_SERVER(server);
592 if (!server || !IS_SILC_SERVER(server) || !server->connected)
593 cmd_return_error(CMDERR_NOT_CONNECTED);
597 /* Now parse all arguments */
598 tmp = g_strconcat("KEY", " ", data, NULL);
599 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
603 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
606 if (!strcasecmp(argv[1], "msg"))
608 if (!strcasecmp(argv[1], "channel"))
612 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
615 if (argv[2][0] == '*') {
616 strcpy(nickname, "*");
618 /* Parse the typed nickname. */
619 if (!silc_parse_userfqdn(argv[2], nickname, sizeof(nickname), NULL, 0)) {
620 printformat_module("fe-common/silc", server, NULL,
621 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
625 /* Find client entry */
626 clients = silc_client_get_clients_local(silc_client, conn, nickname,
629 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
630 inter->server = server;
631 inter->data = strdup(data);
632 inter->nick = strdup(nickname);
634 silc_client_get_clients(silc_client, conn, nickname, argv[2],
635 silc_client_command_key_get_clients, inter);
639 client_entry = silc_dlist_get(clients);
640 silc_client_list_free(silc_client, conn, clients);
645 /* Get channel entry */
648 if (argv[2][0] == '*') {
649 if (!conn->current_channel) {
651 cmd_return_error(CMDERR_NOT_JOINED);
653 name = conn->current_channel->channel_name;
658 chanrec = silc_channel_find(server, name);
659 if (chanrec == NULL) {
661 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
663 channel_entry = chanrec->entry;
667 if (!strcasecmp(argv[3], "set")) {
671 char *cipher = NULL, *hmac = NULL;
678 if (type == 1 && client_entry) {
679 /* Set private message key */
680 silc_client_del_private_message_key(silc_client, conn, client_entry);
681 silc_client_add_private_message_key(silc_client, conn, client_entry,
683 argv[4], argv_lens[4]);
684 } else if (type == 2) {
685 /* Set private channel key */
686 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
687 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
688 SILCTXT_CH_PRIVATE_KEY_NOMODE,
689 channel_entry->channel_name);
693 if (!silc_client_add_channel_private_key(silc_client, conn,
697 argv_lens[4], NULL)) {
698 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
699 SILCTXT_CH_PRIVATE_KEY_ERROR,
700 channel_entry->channel_name);
704 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
705 SILCTXT_CH_PRIVATE_KEY_ADD,
706 channel_entry->channel_name);
714 if (!strcasecmp(argv[3], "unset")) {
717 if (type == 1 && client_entry) {
718 /* Unset private message key */
719 silc_client_del_private_message_key(silc_client, conn, client_entry);
720 } else if (type == 2) {
721 /* Unset channel key(s) */
725 silc_client_del_channel_private_keys(silc_client, conn,
729 number = atoi(argv[4]);
730 ckeys = silc_client_list_channel_private_keys(silc_client, conn,
735 if (!number || number > silc_dlist_count(ckeys)) {
736 silc_dlist_uninit(ckeys);
740 for (i = 0; i < number; i++)
741 ch = silc_dlist_get(ckeys);
745 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
747 silc_dlist_uninit(ckeys);
755 if (!strcasecmp(argv[3], "list")) {
759 SilcPrivateMessageKeys keys;
760 SilcUInt32 keys_count;
764 keys = silc_client_list_private_message_keys(silc_client, conn,
769 /* list the private message key(s) */
770 if (nickname[0] == '*') {
771 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
772 SILCTXT_PRIVATE_KEY_LIST);
773 for (k = 0; k < keys_count; k++) {
774 memset(buf, 0, sizeof(buf));
775 strncat(buf, " ", 2);
776 len = strlen(keys[k].client_entry->nickname);
777 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
779 for (i = 0; i < 30 - len; i++)
783 len = strlen(keys[k].cipher);
784 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
786 for (i = 0; i < 14 - len; i++)
791 strcat(buf, "<hidden>");
793 strcat(buf, "*generated*");
795 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
798 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
799 SILCTXT_PRIVATE_KEY_LIST_NICK,
800 client_entry->nickname);
801 for (k = 0; k < keys_count; k++) {
802 if (keys[k].client_entry != client_entry)
805 memset(buf, 0, sizeof(buf));
806 strncat(buf, " ", 2);
807 len = strlen(keys[k].client_entry->nickname);
808 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
810 for (i = 0; i < 30 - len; i++)
814 len = strlen(keys[k].cipher);
815 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
817 for (i = 0; i < 14 - len; i++)
822 strcat(buf, "<hidden>");
824 strcat(buf, "*generated*");
826 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
830 silc_client_free_private_message_keys(keys, keys_count);
832 } else if (type == 2) {
836 ckeys = silc_client_list_channel_private_keys(silc_client, conn,
839 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
840 SILCTXT_CH_PRIVATE_KEY_LIST,
841 channel_entry->channel_name);
846 while ((ch = silc_dlist_get(ckeys))) {
847 memset(buf, 0, sizeof(buf));
848 strncat(buf, " ", 2);
850 len = strlen(silc_cipher_get_name(ch->cipher));
851 strncat(buf, silc_cipher_get_name(ch->cipher),
852 len > 16 ? 16 : len);
854 for (i = 0; i < 16 - len; i++)
858 len = strlen(silc_hmac_get_name(ch->hmac));
859 strncat(buf, silc_hmac_get_name(ch->hmac), len > 16 ? 16 : len);
861 for (i = 0; i < 16 - len; i++)
865 strcat(buf, "<hidden>");
867 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
870 silc_dlist_uninit(ckeys);
876 /* Send command is used to send key agreement */
877 if (!strcasecmp(argv[3], "agreement")) {
883 if (!strcasecmp(argv[5], "UDP"))
886 port = atoi(argv[5]);
891 internal = silc_calloc(1, sizeof(*internal));
892 internal->type = type;
893 internal->server = server;
896 if (settings_get_bool("use_auto_addr")) {
897 hostname = (char *)settings_get_str("auto_public_ip");
899 /* If the hostname isn't set, treat this case as if auto_public_ip
901 if ((hostname) && (*hostname == '\0')) {
904 bindhost = (char *)settings_get_str("auto_bind_ip");
906 /* if the bind_ip isn't set, but the public_ip IS, then assume then
907 public_ip is the same value as the bind_ip. */
908 if ((bindhost) && (*bindhost == '\0'))
910 port = settings_get_int("auto_bind_port");
912 } /* if use_auto_addr */
916 /* Start command is used to start key agreement (after receiving the
917 key_agreement client operation). */
918 if (!strcasecmp(argv[3], "negotiate")) {
924 if (!strcasecmp(argv[5], "UDP"))
927 port = atoi(argv[5]);
932 internal = silc_calloc(1, sizeof(*internal));
933 internal->type = type;
934 internal->server = server;
937 /* Change current channel private key */
938 if (!strcasecmp(argv[3], "change")) {
941 /* Unset channel key(s) */
944 ckeys = silc_client_list_channel_private_keys(silc_client, conn,
951 if (chanrec->cur_key >= silc_dlist_count(ckeys))
952 chanrec->cur_key = 0;
956 number = atoi(argv[4]);
957 if (!number || number > silc_dlist_count(ckeys))
958 chanrec->cur_key = 0;
960 chanrec->cur_key = number - 1;
963 for (i = 0; i < chanrec->cur_key; i++)
964 ch = silc_dlist_get(ckeys);
968 /* Set the current channel private key */
969 silc_client_current_channel_private_key(silc_client, conn,
971 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
972 SILCTXT_CH_PRIVATE_KEY_CHANGE, i + 1,
973 channel_entry->channel_name);
975 silc_dlist_uninit(ckeys);
981 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
982 "Usage: /KEY msg|channel <nickname|channel> "
983 "set|unset|agreement|negotiate [<arguments>]");
987 if (command == 4 && client_entry) {
988 SilcClientConnectionParams params;
990 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
991 SILCTXT_KEY_AGREEMENT, argv[2]);
992 internal->responder = TRUE;
994 memset(¶ms, 0, sizeof(params));
995 params.local_ip = hostname;
996 params.bind_ip = bindhost;
997 params.local_port = port;
999 params.timeout_secs = settings_get_int("key_exchange_timeout_secs");
1001 silc_client_send_key_agreement(
1002 silc_client, conn, client_entry, ¶ms,
1003 irssi_pubkey, irssi_privkey,
1004 keyagr_completion, internal);
1006 silc_free(internal);
1010 if (command == 5 && client_entry && hostname) {
1011 SilcClientConnectionParams params;
1013 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1014 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
1015 internal->responder = FALSE;
1017 memset(¶ms, 0, sizeof(params));
1019 if (settings_get_bool("use_auto_addr")) {
1020 params.local_ip = (char *)settings_get_str("auto_public_ip");
1021 if ((params.local_ip) && (*params.local_ip == '\0')) {
1022 params.local_ip = silc_net_localip();
1024 params.bind_ip = (char *)settings_get_str("auto_bind_ip");
1025 if ((params.bind_ip) && (*params.bind_ip == '\0'))
1026 params.bind_ip = NULL;
1027 params.local_port = settings_get_int("auto_bind_port");
1030 if (!params.local_ip)
1031 params.local_ip = silc_net_localip();
1034 params.timeout_secs = settings_get_int("key_exchange_timeout_secs");
1036 silc_client_perform_key_agreement(silc_client, conn, client_entry, ¶ms,
1037 irssi_pubkey, irssi_privkey,
1038 hostname, port, keyagr_completion,
1047 void silc_list_key(const char *pub_filename, int verbose)
1049 SilcPublicKey public_key;
1050 SilcPublicKeyIdentifier ident;
1051 SilcSILCPublicKey silc_pubkey;
1052 char *fingerprint, *babbleprint;
1055 SilcUInt32 key_len = 0;
1056 int is_server_key = (strstr(pub_filename, "serverkeys") != NULL);
1058 if (!silc_pkcs_load_public_key((char *)pub_filename, &public_key)) {
1059 printformat_module("fe-common/silc", NULL, NULL,
1060 MSGLEVEL_CRAP, SILCTXT_LISTKEY_LOADPUB,
1065 /* Print only SILC public keys */
1066 if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
1067 printformat_module("fe-common/silc", NULL, NULL,
1068 MSGLEVEL_CRAP, SILCTXT_LISTKEY_LOADPUB,
1073 silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
1074 ident = &silc_pubkey->identifier;
1076 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1077 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1078 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1079 key_len = silc_pkcs_public_key_get_len(public_key);
1081 printformat_module("fe-common/silc", NULL, NULL,
1082 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_FILE,
1086 printformat_module("fe-common/silc", NULL, NULL,
1087 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_ALG,
1088 silc_pkcs_get_name(public_key));
1089 if (key_len && verbose)
1090 printformat_module("fe-common/silc", NULL, NULL,
1091 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_BITS,
1092 (unsigned int)key_len);
1093 if (ident->version && verbose)
1094 printformat_module("fe-common/silc", NULL, NULL,
1095 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_VER,
1097 if (ident->realname && (!is_server_key || verbose))
1098 printformat_module("fe-common/silc", NULL, NULL,
1099 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_RN,
1101 if (ident->username && verbose)
1102 printformat_module("fe-common/silc", NULL, NULL,
1103 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_UN,
1105 if (ident->host && (is_server_key || verbose))
1106 printformat_module("fe-common/silc", NULL, NULL,
1107 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_HN,
1109 if (ident->email && verbose)
1110 printformat_module("fe-common/silc", NULL, NULL,
1111 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_EMAIL,
1113 if (ident->org && verbose)
1114 printformat_module("fe-common/silc", NULL, NULL,
1115 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_ORG,
1117 if (ident->country && verbose)
1118 printformat_module("fe-common/silc", NULL, NULL,
1119 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_C,
1123 printformat_module("fe-common/silc", NULL, NULL,
1124 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_FINGER,
1126 printformat_module("fe-common/silc", NULL, NULL,
1127 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_BABL,
1131 silc_free(fingerprint);
1132 silc_free(babbleprint);
1134 silc_pkcs_public_key_free(public_key);
1137 void silc_list_keys_in_dir(const char *dirname, const char *where)
1140 struct dirent *entry;
1142 dir = opendir(dirname);
1145 cmd_return_error(CMDERR_ERRNO);
1147 printformat_module("fe-common/silc", NULL, NULL,
1148 MSGLEVEL_CRAP, SILCTXT_LISTKEY_LIST,
1153 while ((entry = readdir(dir)) != NULL) {
1154 /* try to open everything that isn't a directory */
1158 snprintf(filename, sizeof(filename) - 1, "%s/%s", dirname, entry->d_name);
1159 if (!stat(filename, &buf) && S_ISREG(buf.st_mode))
1160 silc_list_key(filename, FALSE);
1166 void silc_list_file(const char *filename)
1172 snprintf(path, sizeof(path) - 1, "%s", filename);
1173 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1176 snprintf(path, sizeof(path) - 1, "%s/%s", get_irssi_dir(), filename);
1177 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1180 snprintf(path,sizeof(path) - 1, "%s/clientkeys/%s", get_irssi_dir(),
1182 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1185 snprintf(path,sizeof(path) - 1, "%s/serverkeys/%s", get_irssi_dir(),
1187 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1194 silc_list_key(path, TRUE);
1197 /* Lists locally saved client and server public keys. */
1198 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
1201 GHashTable *optlist;
1206 if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS |
1207 PARAM_FLAG_GETREST, "listkeys", &optlist,
1211 if (*filename != '\0') {
1213 silc_list_file(filename);
1216 int clients, servers;
1218 clients = (g_hash_table_lookup(optlist, "clients") != NULL);
1219 servers = (g_hash_table_lookup(optlist, "servers") != NULL);
1221 if (!(clients || servers))
1222 clients = servers = 1;
1225 snprintf(dirname, sizeof(dirname) - 1, "%s/serverkeys", get_irssi_dir());
1226 silc_list_keys_in_dir(dirname, "server");
1230 snprintf(dirname, sizeof(dirname) - 1, "%s/clientkeys", get_irssi_dir());
1231 silc_list_keys_in_dir(dirname, "client");
1234 cmd_params_free(free_arg);
1237 void silc_channels_init(void)
1239 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1240 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1241 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1242 signal_add("mime", (SIGNAL_FUNC) sig_mime);
1244 command_bind_silc("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1245 command_bind_silc("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1246 command_bind_silc("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1247 command_bind_silc("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1248 command_bind_silc("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1249 command_bind_silc("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1250 command_bind("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
1252 command_set_options("listkeys", "clients servers");
1253 command_set_options("action", "sign channel");
1254 command_set_options("notice", "sign channel");
1256 silc_nicklist_init();
1259 void silc_channels_deinit(void)
1261 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1262 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1263 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1264 signal_remove("mime", (SIGNAL_FUNC) sig_mime);
1266 command_unbind("part", (SIGNAL_FUNC) command_part);
1267 command_unbind("me", (SIGNAL_FUNC) command_me);
1268 command_unbind("action", (SIGNAL_FUNC) command_action);
1269 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1270 command_unbind("away", (SIGNAL_FUNC) command_away);
1271 command_unbind("key", (SIGNAL_FUNC) command_key);
1272 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
1274 silc_nicklist_deinit();