2 silc-channels.c : irssi
4 Copyright (C) 2000 - 2001, 2004, 2006 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 SilcChannelEntry 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);
756 if (!strcasecmp(argv[3], "list")) {
760 SilcPrivateMessageKeys keys;
761 SilcUInt32 keys_count;
765 keys = silc_client_list_private_message_keys(silc_client, conn,
770 /* list the private message key(s) */
771 if (nickname[0] == '*') {
772 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
773 SILCTXT_PRIVATE_KEY_LIST);
774 for (k = 0; k < keys_count; k++) {
775 memset(buf, 0, sizeof(buf));
776 strncat(buf, " ", 2);
777 len = strlen(keys[k].client_entry->nickname);
778 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
780 for (i = 0; i < 30 - len; i++)
784 len = strlen(keys[k].cipher);
785 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
787 for (i = 0; i < 14 - len; i++)
792 strcat(buf, "<hidden>");
794 strcat(buf, "*generated*");
796 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
799 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
800 SILCTXT_PRIVATE_KEY_LIST_NICK,
801 client_entry->nickname);
802 for (k = 0; k < keys_count; k++) {
803 if (keys[k].client_entry != client_entry)
806 memset(buf, 0, sizeof(buf));
807 strncat(buf, " ", 2);
808 len = strlen(keys[k].client_entry->nickname);
809 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
811 for (i = 0; i < 30 - len; i++)
815 len = strlen(keys[k].cipher);
816 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
818 for (i = 0; i < 14 - len; i++)
823 strcat(buf, "<hidden>");
825 strcat(buf, "*generated*");
827 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
831 silc_client_free_private_message_keys(keys, keys_count);
833 } else if (type == 2) {
837 ckeys = silc_client_list_channel_private_keys(silc_client, conn,
840 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
841 SILCTXT_CH_PRIVATE_KEY_LIST,
842 channel_entry->channel_name);
847 for (k = 0; k < keys_count; k++) {
848 memset(buf, 0, sizeof(buf));
849 strncat(buf, " ", 2);
851 len = strlen(silc_cipher_get_name(keys[k]->cipher));
852 strncat(buf, silc_cipher_get_name(keys[k]->cipher),
853 len > 16 ? 16 : len);
855 for (i = 0; i < 16 - len; i++)
859 len = strlen(silc_hmac_get_name(keys[k]->hmac));
860 strncat(buf, silc_hmac_get_name(keys[k]->hmac), len > 16 ? 16 : len);
862 for (i = 0; i < 16 - len; i++)
866 strcat(buf, "<hidden>");
868 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
871 silc_client_free_channel_private_keys(keys, keys_count);
878 /* Send command is used to send key agreement */
879 if (!strcasecmp(argv[3], "agreement")) {
885 if (!strcasecmp(argv[5], "UDP"))
888 port = atoi(argv[5]);
893 internal = silc_calloc(1, sizeof(*internal));
894 internal->type = type;
895 internal->server = server;
898 if (settings_get_bool("use_auto_addr")) {
899 hostname = (char *)settings_get_str("auto_public_ip");
901 /* If the hostname isn't set, treat this case as if auto_public_ip
903 if ((hostname) && (*hostname == '\0')) {
906 bindhost = (char *)settings_get_str("auto_bind_ip");
908 /* if the bind_ip isn't set, but the public_ip IS, then assume then
909 public_ip is the same value as the bind_ip. */
910 if ((bindhost) && (*bindhost == '\0'))
912 port = settings_get_int("auto_bind_port");
914 } /* if use_auto_addr */
918 /* Start command is used to start key agreement (after receiving the
919 key_agreement client operation). */
920 if (!strcasecmp(argv[3], "negotiate")) {
926 if (!strcasecmp(argv[5], "UDP"))
929 port = atoi(argv[5]);
934 internal = silc_calloc(1, sizeof(*internal));
935 internal->type = type;
936 internal->server = server;
939 /* Change current channel private key */
940 if (!strcasecmp(argv[3], "change")) {
943 /* Unset channel key(s) */
946 ckeys = silc_client_list_channel_private_keys(silc_client, conn,
953 if (chanrec->cur_key >= silc_dlist_count(ckeys))
954 chanrec->cur_key = 0;
958 number = atoi(argv[4]);
959 if (!number || number > silc_dlist_count(ckeys))
960 chanrec->cur_key = 0;
962 chanrec->cur_key = number - 1;
965 for (i = 0; i < chanrec->cur_key; i++)
966 ch = silc_dlist_get(ckeys);
970 /* Set the current channel private key */
971 silc_client_current_channel_private_key(silc_client, conn,
973 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
974 SILCTXT_CH_PRIVATE_KEY_CHANGE, i + 1,
975 channel_entry->channel_name);
977 silc_dlist_uninit(ckeys);
983 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
984 "Usage: /KEY msg|channel <nickname|channel> "
985 "set|unset|agreement|negotiate [<arguments>]");
989 if (command == 4 && client_entry) {
990 SilcClientConnectionParams params;
992 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
993 SILCTXT_KEY_AGREEMENT, argv[2]);
994 internal->responder = TRUE;
996 memset(¶ms, 0, sizeof(params));
997 params.local_ip = hostname;
998 params.bind_ip = bindhost;
999 params.local_port = port;
1001 params.timeout_secs = settings_get_int("key_exchange_timeout_secs");
1003 silc_client_send_key_agreement(
1004 silc_client, conn, client_entry, ¶ms,
1005 irssi_pubkey, irssi_privkey,
1006 keyagr_completion, internal);
1008 silc_free(internal);
1012 if (command == 5 && client_entry && hostname) {
1013 SilcClientConnectionParams params;
1015 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1016 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
1017 internal->responder = FALSE;
1019 memset(¶ms, 0, sizeof(params));
1021 if (settings_get_bool("use_auto_addr")) {
1022 params.local_ip = (char *)settings_get_str("auto_public_ip");
1023 if ((params.local_ip) && (*params.local_ip == '\0')) {
1024 params.local_ip = silc_net_localip();
1026 params.bind_ip = (char *)settings_get_str("auto_bind_ip");
1027 if ((params.bind_ip) && (*params.bind_ip == '\0'))
1028 params.bind_ip = NULL;
1029 params.local_port = settings_get_int("auto_bind_port");
1032 if (!params.local_ip)
1033 params.local_ip = silc_net_localip();
1036 params.timeout_secs = settings_get_int("key_exchange_timeout_secs");
1038 silc_client_perform_key_agreement(silc_client, conn, client_entry, ¶ms,
1039 irssi_pubkey, irssi_privkey,
1040 hostname, port, keyagr_completion,
1050 void silc_list_key(const char *pub_filename, int verbose)
1052 SilcPublicKey public_key;
1053 SilcPublicKeyIdentifier ident;
1054 char *fingerprint, *babbleprint;
1058 SilcUInt32 key_len = 0;
1059 int is_server_key = (strstr(pub_filename, "serverkeys") != NULL);
1061 if (silc_pkcs_load_public_key((char *)pub_filename, &public_key,
1062 SILC_PKCS_FILE_PEM) == FALSE)
1063 if (silc_pkcs_load_public_key((char *)pub_filename, &public_key,
1064 SILC_PKCS_FILE_BIN) == FALSE) {
1065 printformat_module("fe-common/silc", NULL, NULL,
1066 MSGLEVEL_CRAP, SILCTXT_LISTKEY_LOADPUB,
1071 ident = silc_pkcs_decode_identifier(public_key->identifier);
1073 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1074 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1075 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1077 if (silc_pkcs_alloc(public_key->name, &pkcs)) {
1078 key_len = silc_pkcs_public_key_set(pkcs, public_key);
1079 silc_pkcs_free(pkcs);
1082 printformat_module("fe-common/silc", NULL, NULL,
1083 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_FILE,
1087 printformat_module("fe-common/silc", NULL, NULL,
1088 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_ALG,
1090 if (key_len && verbose)
1091 printformat_module("fe-common/silc", NULL, NULL,
1092 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_BITS,
1093 (unsigned int)key_len);
1094 if (ident->realname && (!is_server_key || verbose))
1095 printformat_module("fe-common/silc", NULL, NULL,
1096 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_RN,
1098 if (ident->username && verbose)
1099 printformat_module("fe-common/silc", NULL, NULL,
1100 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_UN,
1102 if (ident->host && (is_server_key || verbose))
1103 printformat_module("fe-common/silc", NULL, NULL,
1104 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_HN,
1106 if (ident->email && verbose)
1107 printformat_module("fe-common/silc", NULL, NULL,
1108 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_EMAIL,
1110 if (ident->org && verbose)
1111 printformat_module("fe-common/silc", NULL, NULL,
1112 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_ORG,
1114 if (ident->country && verbose)
1115 printformat_module("fe-common/silc", NULL, NULL,
1116 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_C,
1120 printformat_module("fe-common/silc", NULL, NULL,
1121 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_FINGER,
1123 printformat_module("fe-common/silc", NULL, NULL,
1124 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_BABL,
1128 silc_free(fingerprint);
1129 silc_free(babbleprint);
1131 silc_pkcs_public_key_free(public_key);
1132 silc_pkcs_free_identifier(ident);
1136 void silc_list_keys_in_dir(const char *dirname, const char *where)
1139 struct dirent *entry;
1141 dir = opendir(dirname);
1144 cmd_return_error(CMDERR_ERRNO);
1146 printformat_module("fe-common/silc", NULL, NULL,
1147 MSGLEVEL_CRAP, SILCTXT_LISTKEY_LIST,
1152 while ((entry = readdir(dir)) != NULL) {
1153 /* try to open everything that isn't a directory */
1157 snprintf(filename, sizeof(filename) - 1, "%s/%s", dirname, entry->d_name);
1158 if (!stat(filename, &buf) && S_ISREG(buf.st_mode))
1159 silc_list_key(filename, FALSE);
1165 void silc_list_file(const char *filename)
1171 snprintf(path, sizeof(path) - 1, "%s", filename);
1172 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1175 snprintf(path, sizeof(path) - 1, "%s/%s", get_irssi_dir(), filename);
1176 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1179 snprintf(path,sizeof(path) - 1, "%s/clientkeys/%s", get_irssi_dir(),
1181 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1184 snprintf(path,sizeof(path) - 1, "%s/serverkeys/%s", get_irssi_dir(),
1186 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1193 silc_list_key(path, TRUE);
1198 /* Lists locally saved client and server public keys. */
1199 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
1202 GHashTable *optlist;
1207 if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS |
1208 PARAM_FLAG_GETREST, "listkeys", &optlist,
1212 if (*filename != '\0') {
1214 silc_list_file(filename);
1217 int clients, servers;
1219 clients = (g_hash_table_lookup(optlist, "clients") != NULL);
1220 servers = (g_hash_table_lookup(optlist, "servers") != NULL);
1222 if (!(clients || servers))
1223 clients = servers = 1;
1226 snprintf(dirname, sizeof(dirname) - 1, "%s/serverkeys", get_irssi_dir());
1227 silc_list_keys_in_dir(dirname, "server");
1231 snprintf(dirname, sizeof(dirname) - 1, "%s/clientkeys", get_irssi_dir());
1232 silc_list_keys_in_dir(dirname, "client");
1235 cmd_params_free(free_arg);
1238 void silc_channels_init(void)
1240 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1241 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1242 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1243 signal_add("mime", (SIGNAL_FUNC) sig_mime);
1245 command_bind_silc("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1246 command_bind_silc("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1247 command_bind_silc("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1248 command_bind_silc("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1249 command_bind_silc("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1250 command_bind_silc("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1251 // command_bind("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
1253 //command_set_options("listkeys", "clients servers");
1254 command_set_options("action", "sign channel");
1255 command_set_options("notice", "sign channel");
1257 silc_nicklist_init();
1260 void silc_channels_deinit(void)
1262 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1263 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1264 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1265 signal_remove("mime", (SIGNAL_FUNC) sig_mime);
1267 command_unbind("part", (SIGNAL_FUNC) command_part);
1268 command_unbind("me", (SIGNAL_FUNC) command_me);
1269 command_unbind("action", (SIGNAL_FUNC) command_action);
1270 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1271 command_unbind("away", (SIGNAL_FUNC) command_away);
1272 command_unbind("key", (SIGNAL_FUNC) command_key);
1273 // command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
1275 silc_nicklist_deinit();