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 static void sig_gui_quit(SILC_SERVER_REC *server, const char *msg)
145 silc_client_stop(silc_client);
148 /* Find Irssi channel entry by SILC channel entry */
150 SILC_CHANNEL_REC *silc_channel_find_entry(SILC_SERVER_REC *server,
151 SilcChannelEntry entry)
155 g_return_val_if_fail(IS_SILC_SERVER(server), NULL);
157 for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
158 SILC_CHANNEL_REC *rec = tmp->data;
160 if (rec->entry == entry)
167 /* PART (LEAVE) command. */
169 static void command_part(const char *data, SILC_SERVER_REC *server,
172 SILC_CHANNEL_REC *chanrec;
175 CMD_SILC_SERVER(server);
177 if (!IS_SILC_SERVER(server) || !server->connected)
178 cmd_return_error(CMDERR_NOT_CONNECTED);
180 if (!strcmp(data, "*") || *data == '\0') {
181 if (!IS_SILC_CHANNEL(item))
182 cmd_return_error(CMDERR_NOT_JOINED);
183 data = item->visible_name;
186 chanrec = silc_channel_find(server, data);
188 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
190 memset(userhost, 0, sizeof(userhost));
191 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
192 server->conn->local_entry->username,
193 server->conn->local_entry->hostname);
194 signal_emit("message part", 5, server, chanrec->name,
195 server->nick, userhost, "");
197 chanrec->left = TRUE;
198 silc_command_exec(server, "LEAVE", chanrec->name);
199 /* enable queueing because we destroy the channel immedially */
200 silc_queue_enable(server->conn);
203 channel_destroy(CHANNEL(chanrec));
207 /* ACTION local command. */
209 static void command_action(const char *data, SILC_SERVER_REC *server,
214 char *message = NULL;
218 CMD_SILC_SERVER(server);
219 if (!IS_SILC_SERVER(server) || !server->connected)
220 cmd_return_error(CMDERR_NOT_CONNECTED);
222 if ((item != NULL) && (!IS_SILC_CHANNEL(item) && !IS_SILC_QUERY(item)))
223 cmd_return_error(CMDERR_NOT_JOINED);
225 /* Now parse all arguments */
226 if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS |
228 "action", &optlist, &target, &msg))
231 if (*target == '\0' || *msg == '\0')
232 cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
234 if (strcmp(target, "*") == 0) {
235 /* send to active channel/query */
237 cmd_param_error(CMDERR_NOT_JOINED);
239 target_type = IS_SILC_CHANNEL(item) ?
240 SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
241 target = (char *)window_item_get_target(item);
242 } else if (g_hash_table_lookup(optlist, "channel") != NULL)
243 target_type = SEND_TARGET_CHANNEL;
245 target_type = SEND_TARGET_NICK;
248 if (!silc_term_utf8()) {
249 int len = silc_utf8_encoded_len(msg, strlen(msg),
251 message = silc_calloc(len + 1, sizeof(*message));
252 g_return_if_fail(message != NULL);
253 silc_utf8_encode(msg, strlen(msg), SILC_STRING_LOCALE,
257 if (target != NULL) {
258 if (target_type == SEND_TARGET_CHANNEL) {
259 if (silc_send_channel(server, target, (message != NULL ? message : msg),
260 SILC_MESSAGE_FLAG_ACTION | SILC_MESSAGE_FLAG_UTF8 |
261 (g_hash_table_lookup(optlist, "sign") != NULL ?
262 SILC_MESSAGE_FLAG_SIGNED : 0))) {
263 if (g_hash_table_lookup(optlist, "sign"))
264 signal_emit("message silc signed_own_action", 3, server, msg, target);
266 signal_emit("message silc own_action", 3, server, msg, target);
269 if (silc_send_msg(server, target, (message != NULL ? message : msg),
270 (message != NULL ? strlen(message) : strlen(msg)),
271 SILC_MESSAGE_FLAG_ACTION | SILC_MESSAGE_FLAG_UTF8 |
272 (g_hash_table_lookup(optlist, "sign") != NULL ?
273 SILC_MESSAGE_FLAG_SIGNED : 0))) {
274 if (g_hash_table_lookup(optlist, "sign"))
275 signal_emit("message silc signed_own_private_action", 3,
276 server, msg, target);
278 signal_emit("message silc own_private_action", 3,
279 server, msg, target);
284 cmd_params_free(free_arg);
288 /* ME local command. */
290 static void command_me(const char *data, SILC_SERVER_REC *server,
295 CMD_SILC_SERVER(server);
296 if (!IS_SILC_SERVER(server) || !server->connected)
297 cmd_return_error(CMDERR_NOT_CONNECTED);
299 if (!IS_SILC_CHANNEL(item) && !IS_SILC_QUERY(item))
300 cmd_return_error(CMDERR_NOT_JOINED);
302 if (IS_SILC_CHANNEL(item))
303 tmpcmd = g_strdup_printf("-channel %s %s", item->visible_name, data);
305 tmpcmd = g_strdup_printf("%s %s", item->visible_name, data);
307 command_action(tmpcmd, server, item);
311 /* NOTICE local command. */
313 static void command_notice(const char *data, SILC_SERVER_REC *server,
318 char *message = NULL;
322 CMD_SILC_SERVER(server);
323 if (!IS_SILC_SERVER(server) || !server->connected)
324 cmd_return_error(CMDERR_NOT_CONNECTED);
326 if ((item != NULL) && (!IS_SILC_CHANNEL(item) && !IS_SILC_QUERY(item)))
327 cmd_return_error(CMDERR_NOT_JOINED);
329 /* Now parse all arguments */
330 if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS |
332 "notice", &optlist, &target, &msg))
335 if (*target == '\0' || *msg == '\0')
336 cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
338 if (strcmp(target, "*") == 0) {
339 /* send to active channel/query */
341 cmd_param_error(CMDERR_NOT_JOINED);
343 target_type = IS_SILC_CHANNEL(item) ?
344 SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
345 target = (char *)window_item_get_target(item);
346 } else if (g_hash_table_lookup(optlist, "channel") != NULL)
347 target_type = SEND_TARGET_CHANNEL;
349 target_type = SEND_TARGET_NICK;
352 if (!silc_term_utf8()) {
353 int len = silc_utf8_encoded_len(msg, strlen(msg),
355 message = silc_calloc(len + 1, sizeof(*message));
356 g_return_if_fail(message != NULL);
357 silc_utf8_encode(msg, strlen(msg), SILC_STRING_LOCALE,
361 if (target != NULL) {
362 if (target_type == SEND_TARGET_CHANNEL) {
363 if (silc_send_channel(server, target, (message != NULL ? message : msg),
364 SILC_MESSAGE_FLAG_NOTICE | SILC_MESSAGE_FLAG_UTF8 |
365 (g_hash_table_lookup(optlist, "sign") != NULL ?
366 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 if (silc_send_msg(server, target, (message != NULL ? message : msg),
374 (message != NULL ? strlen(message) : strlen(msg)),
375 SILC_MESSAGE_FLAG_NOTICE | SILC_MESSAGE_FLAG_UTF8 |
376 (g_hash_table_lookup(optlist, "sign") != NULL ?
377 SILC_MESSAGE_FLAG_SIGNED : 0))) {
378 if (g_hash_table_lookup(optlist, "sign"))
379 signal_emit("message silc signed_own_private_notice", 3,
380 server, msg, target);
382 signal_emit("message silc own_private_notice", 3,
383 server, msg, target);
388 cmd_params_free(free_arg);
392 /* AWAY local command. Sends UMODE command that sets the SILC_UMODE_GONE
395 bool silc_set_away(const char *reason, SILC_SERVER_REC *server)
399 if (!IS_SILC_SERVER(server) || !server->connected)
402 if (*reason == '\0') {
403 /* Remove any possible away message */
404 silc_client_set_away_message(silc_client, server->conn, NULL);
407 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
410 /* Set the away message */
411 silc_client_set_away_message(silc_client, server->conn, (char *)reason);
414 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
415 SILCTXT_SET_AWAY, reason);
418 server->usermode_away = set;
419 g_free_and_null(server->away_reason);
421 server->away_reason = g_strdup((char *)reason);
423 signal_emit("away mode changed", 1, server);
428 static void command_away(const char *data, SILC_SERVER_REC *server,
431 CMD_SILC_SERVER(server);
433 if (!IS_SILC_SERVER(server) || !server->connected)
434 cmd_return_error(CMDERR_NOT_CONNECTED);
436 g_free_and_null(server->away_reason);
437 if ((data) && (*data != '\0'))
438 server->away_reason = g_strdup(data);
440 silc_command_exec(server, "UMODE",
441 (server->away_reason != NULL) ? "+g" : "-g");
445 int type; /* 1 = msg, 2 = channel */
447 SILC_SERVER_REC *server;
450 /* Key agreement callback that is called after the key agreement protocol
451 has been performed. This is called also if error occured during the
452 key agreement protocol. The `key' is the allocated key material and
453 the caller is responsible of freeing it. The `key' is NULL if error
454 has occured. The application can freely use the `key' to whatever
455 purpose it needs. See lib/silcske/silcske.h for the definition of
456 the SilcSKEKeyMaterial structure. */
458 static void keyagr_completion(SilcClient client,
459 SilcClientConnection conn,
460 SilcClientEntry client_entry,
461 SilcKeyAgreementStatus status,
462 SilcSKEKeyMaterial *key,
465 KeyInternal i = (KeyInternal)context;
468 case SILC_KEY_AGREEMENT_OK:
469 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
470 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
473 /* Set the private key for this client */
474 silc_client_del_private_message_key(client, conn, client_entry);
475 silc_client_add_private_message_key_ske(client, conn, client_entry,
476 NULL, NULL, key, i->responder);
477 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
478 SILCTXT_KEY_AGREEMENT_PRIVMSG,
479 client_entry->nickname);
480 silc_ske_free_key_material(key);
485 case SILC_KEY_AGREEMENT_ERROR:
486 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
487 SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
490 case SILC_KEY_AGREEMENT_FAILURE:
491 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
492 SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
495 case SILC_KEY_AGREEMENT_TIMEOUT:
496 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
497 SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
500 case SILC_KEY_AGREEMENT_ABORTED:
501 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
502 SILCTXT_KEY_AGREEMENT_ABORTED, client_entry->nickname);
505 case SILC_KEY_AGREEMENT_ALREADY_STARTED:
506 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
507 SILCTXT_KEY_AGREEMENT_ALREADY_STARTED,
508 client_entry->nickname);
511 case SILC_KEY_AGREEMENT_SELF_DENIED:
512 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
513 SILCTXT_KEY_AGREEMENT_SELF_DENIED);
525 /* Local command KEY. This command is used to set and unset private
526 keys for channels, set and unset private keys for private messages
527 with remote clients and to send key agreement requests and
528 negotiate the key agreement protocol with remote client. The
529 key agreement is supported only to negotiate private message keys,
530 it currently cannot be used to negotiate private keys for channels,
531 as it is not convenient for that purpose. */
534 SILC_SERVER_REC *server;
540 /* Callback to be called after client information is resolved from the
543 static void silc_client_command_key_get_clients(SilcClient client,
544 SilcClientConnection conn,
545 SilcClientEntry *clients,
546 SilcUInt32 clients_count,
549 KeyGetClients internal = (KeyGetClients)context;
552 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s",
554 silc_free(internal->data);
555 silc_free(internal->nick);
560 signal_emit("command key", 3, internal->data, internal->server,
563 silc_free(internal->data);
564 silc_free(internal->nick);
568 static void command_key(const char *data, SILC_SERVER_REC *server,
571 SilcClientConnection conn;
572 SilcClientEntry *entrys, client_entry = NULL;
573 SilcUInt32 entry_count;
574 SILC_CHANNEL_REC *chanrec = NULL;
575 SilcChannelEntry channel_entry = NULL;
576 char *nickname = NULL, *tmp;
577 int command = 0, port = 0, type = 0;
578 char *hostname = NULL;
579 KeyInternal internal = NULL;
581 unsigned char **argv;
582 SilcUInt32 *argv_lens, *argv_types;
583 char *bindhost = NULL;
585 CMD_SILC_SERVER(server);
587 if (!server || !IS_SILC_SERVER(server) || !server->connected)
588 cmd_return_error(CMDERR_NOT_CONNECTED);
592 /* Now parse all arguments */
593 tmp = g_strconcat("KEY", " ", data, NULL);
594 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
598 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
601 if (!strcasecmp(argv[1], "msg"))
603 if (!strcasecmp(argv[1], "channel"))
607 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
610 if (argv[2][0] == '*') {
611 nickname = strdup("*");
613 /* Parse the typed nickname. */
614 if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
615 printformat_module("fe-common/silc", server, NULL,
616 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
620 /* Find client entry */
621 entrys = silc_client_get_clients_local(silc_client, conn, nickname,
622 argv[2], &entry_count);
624 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
625 inter->server = server;
626 inter->data = strdup(data);
627 inter->nick = strdup(nickname);
629 silc_client_get_clients(silc_client, conn, nickname, argv[2],
630 silc_client_command_key_get_clients, inter);
633 client_entry = entrys[0];
639 /* Get channel entry */
642 if (argv[2][0] == '*') {
643 if (!conn->current_channel) {
645 cmd_return_error(CMDERR_NOT_JOINED);
647 name = conn->current_channel->channel_name;
652 chanrec = silc_channel_find(server, name);
653 if (chanrec == NULL) {
655 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
657 channel_entry = chanrec->entry;
661 if (!strcasecmp(argv[3], "set")) {
665 char *cipher = NULL, *hmac = NULL;
667 if (type == 1 && client_entry) {
668 /* Set private message key */
669 bool responder = FALSE;
671 silc_client_del_private_message_key(silc_client, conn, client_entry);
674 if (!strcasecmp(argv[5], "-responder"))
680 if (!strcasecmp(argv[6], "-responder"))
686 if (!strcasecmp(argv[7], "-responder"))
690 silc_client_add_private_message_key(silc_client, conn, client_entry,
692 argv[4], argv_lens[4],
694 TRUE : FALSE), responder);
696 /* Send the key to the remote client so that it starts using it
698 /* XXX for now we don't do this. This feature is pretty stupid
699 and should perhaps be removed altogether from SILC.
700 silc_client_send_private_message_key(silc_client, conn,
703 } else if (type == 2) {
704 /* Set private channel key */
705 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
706 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
707 SILCTXT_CH_PRIVATE_KEY_NOMODE,
708 channel_entry->channel_name);
717 if (!silc_client_add_channel_private_key(silc_client, conn,
721 argv_lens[4], NULL)) {
722 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
723 SILCTXT_CH_PRIVATE_KEY_ERROR,
724 channel_entry->channel_name);
728 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
729 SILCTXT_CH_PRIVATE_KEY_ADD,
730 channel_entry->channel_name);
738 if (!strcasecmp(argv[3], "unset")) {
741 if (type == 1 && client_entry) {
742 /* Unset private message key */
743 silc_client_del_private_message_key(silc_client, conn, client_entry);
744 } else if (type == 2) {
745 /* Unset channel key(s) */
746 SilcChannelPrivateKey *keys;
747 SilcUInt32 keys_count;
751 silc_client_del_channel_private_keys(silc_client, conn,
755 number = atoi(argv[4]);
756 keys = silc_client_list_channel_private_keys(silc_client, conn,
762 if (!number || number > keys_count) {
763 silc_client_free_channel_private_keys(keys, keys_count);
767 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
769 silc_client_free_channel_private_keys(keys, keys_count);
777 if (!strcasecmp(argv[3], "list")) {
781 SilcPrivateMessageKeys keys;
782 SilcUInt32 keys_count;
786 keys = silc_client_list_private_message_keys(silc_client, conn,
791 /* list the private message key(s) */
792 if (nickname[0] == '*') {
793 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
794 SILCTXT_PRIVATE_KEY_LIST);
795 for (k = 0; k < keys_count; k++) {
796 memset(buf, 0, sizeof(buf));
797 strncat(buf, " ", 2);
798 len = strlen(keys[k].client_entry->nickname);
799 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
801 for (i = 0; i < 30 - len; i++)
805 len = strlen(keys[k].cipher);
806 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
808 for (i = 0; i < 14 - len; i++)
813 strcat(buf, "<hidden>");
815 strcat(buf, "*generated*");
817 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
820 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
821 SILCTXT_PRIVATE_KEY_LIST_NICK,
822 client_entry->nickname);
823 for (k = 0; k < keys_count; k++) {
824 if (keys[k].client_entry != client_entry)
827 memset(buf, 0, sizeof(buf));
828 strncat(buf, " ", 2);
829 len = strlen(keys[k].client_entry->nickname);
830 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
832 for (i = 0; i < 30 - len; i++)
836 len = strlen(keys[k].cipher);
837 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
839 for (i = 0; i < 14 - len; i++)
844 strcat(buf, "<hidden>");
846 strcat(buf, "*generated*");
848 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
852 silc_client_free_private_message_keys(keys, keys_count);
854 } else if (type == 2) {
855 SilcChannelPrivateKey *keys;
856 SilcUInt32 keys_count;
860 keys = silc_client_list_channel_private_keys(silc_client, conn,
864 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
865 SILCTXT_CH_PRIVATE_KEY_LIST,
866 channel_entry->channel_name);
871 for (k = 0; k < keys_count; k++) {
872 memset(buf, 0, sizeof(buf));
873 strncat(buf, " ", 2);
875 len = strlen(silc_cipher_get_name(keys[k]->cipher));
876 strncat(buf, silc_cipher_get_name(keys[k]->cipher),
877 len > 16 ? 16 : len);
879 for (i = 0; i < 16 - len; i++)
883 len = strlen(silc_hmac_get_name(keys[k]->hmac));
884 strncat(buf, silc_hmac_get_name(keys[k]->hmac), len > 16 ? 16 : len);
886 for (i = 0; i < 16 - len; i++)
890 strcat(buf, "<hidden>");
892 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
895 silc_client_free_channel_private_keys(keys, keys_count);
901 /* Send command is used to send key agreement */
902 if (!strcasecmp(argv[3], "agreement")) {
908 port = atoi(argv[5]);
910 internal = silc_calloc(1, sizeof(*internal));
911 internal->type = type;
912 internal->server = server;
915 if (settings_get_bool("use_auto_addr")) {
917 hostname = (char *)settings_get_str("auto_public_ip");
919 /* If the hostname isn't set, treat this case as if auto_public_ip
921 if ((hostname) && (*hostname == '\0')) {
924 bindhost = (char *)settings_get_str("auto_bind_ip");
926 /* if the bind_ip isn't set, but the public_ip IS, then assume then
927 public_ip is the same value as the bind_ip. */
928 if ((bindhost) && (*bindhost == '\0'))
930 port = settings_get_int("auto_bind_port");
932 } /* if use_auto_addr */
936 /* Start command is used to start key agreement (after receiving the
937 key_agreement client operation). */
938 if (!strcasecmp(argv[3], "negotiate")) {
944 port = atoi(argv[5]);
946 internal = silc_calloc(1, sizeof(*internal));
947 internal->type = type;
948 internal->server = server;
951 /* Change current channel private key */
952 if (!strcasecmp(argv[3], "change")) {
955 /* Unset channel key(s) */
956 SilcChannelPrivateKey *keys;
957 SilcUInt32 keys_count;
960 keys = silc_client_list_channel_private_keys(silc_client, conn,
968 if (chanrec->cur_key >= keys_count)
969 chanrec->cur_key = 0;
973 number = atoi(argv[4]);
974 if (!number || number > keys_count)
975 chanrec->cur_key = 0;
977 chanrec->cur_key = number - 1;
980 /* Set the current channel private key */
981 silc_client_current_channel_private_key(silc_client, conn,
983 keys[chanrec->cur_key]);
984 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
985 SILCTXT_CH_PRIVATE_KEY_CHANGE, chanrec->cur_key + 1,
986 channel_entry->channel_name);
988 silc_client_free_channel_private_keys(keys, keys_count);
994 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
995 "Usage: /KEY msg|channel <nickname|channel> "
996 "set|unset|agreement|negotiate [<arguments>]");
1000 if (command == 4 && client_entry) {
1001 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1002 SILCTXT_KEY_AGREEMENT, argv[2]);
1003 internal->responder = TRUE;
1004 silc_client_send_key_agreement(
1005 silc_client, conn, client_entry, hostname,
1007 settings_get_int("key_exchange_timeout_secs"),
1008 keyagr_completion, internal);
1010 silc_free(internal);
1014 if (command == 5 && client_entry && hostname) {
1015 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1016 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
1017 internal->responder = FALSE;
1018 silc_client_perform_key_agreement(silc_client, conn, client_entry,
1019 hostname, port, keyagr_completion,
1025 silc_free(nickname);
1028 void silc_list_key(const char *pub_filename, int verbose)
1030 SilcPublicKey public_key;
1031 SilcPublicKeyIdentifier ident;
1032 char *fingerprint, *babbleprint;
1036 SilcUInt32 key_len = 0;
1037 int is_server_key = (strstr(pub_filename, "serverkeys") != NULL);
1039 if (silc_pkcs_load_public_key((char *)pub_filename, &public_key,
1040 SILC_PKCS_FILE_PEM) == FALSE)
1041 if (silc_pkcs_load_public_key((char *)pub_filename, &public_key,
1042 SILC_PKCS_FILE_BIN) == FALSE) {
1043 printformat_module("fe-common/silc", NULL, NULL,
1044 MSGLEVEL_CRAP, SILCTXT_LISTKEY_LOADPUB,
1049 ident = silc_pkcs_decode_identifier(public_key->identifier);
1051 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1052 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1053 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1055 if (silc_pkcs_alloc(public_key->name, &pkcs)) {
1056 key_len = silc_pkcs_public_key_set(pkcs, public_key);
1057 silc_pkcs_free(pkcs);
1060 printformat_module("fe-common/silc", NULL, NULL,
1061 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_FILE,
1065 printformat_module("fe-common/silc", NULL, NULL,
1066 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_ALG,
1068 if (key_len && verbose)
1069 printformat_module("fe-common/silc", NULL, NULL,
1070 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_BITS,
1071 (unsigned int)key_len);
1072 if (ident->realname && (!is_server_key || verbose))
1073 printformat_module("fe-common/silc", NULL, NULL,
1074 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_RN,
1076 if (ident->username && verbose)
1077 printformat_module("fe-common/silc", NULL, NULL,
1078 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_UN,
1080 if (ident->host && (is_server_key || verbose))
1081 printformat_module("fe-common/silc", NULL, NULL,
1082 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_HN,
1084 if (ident->email && verbose)
1085 printformat_module("fe-common/silc", NULL, NULL,
1086 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_EMAIL,
1088 if (ident->org && verbose)
1089 printformat_module("fe-common/silc", NULL, NULL,
1090 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_ORG,
1092 if (ident->country && verbose)
1093 printformat_module("fe-common/silc", NULL, NULL,
1094 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_C,
1098 printformat_module("fe-common/silc", NULL, NULL,
1099 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_FINGER,
1101 printformat_module("fe-common/silc", NULL, NULL,
1102 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_BABL,
1106 silc_free(fingerprint);
1107 silc_free(babbleprint);
1109 silc_pkcs_public_key_free(public_key);
1110 silc_pkcs_free_identifier(ident);
1114 void silc_list_keys_in_dir(const char *dirname, const char *where)
1117 struct dirent *entry;
1119 dir = opendir(dirname);
1122 cmd_return_error(CMDERR_ERRNO);
1124 printformat_module("fe-common/silc", NULL, NULL,
1125 MSGLEVEL_CRAP, SILCTXT_LISTKEY_LIST,
1130 while ((entry = readdir(dir)) != NULL) {
1131 /* try to open everything that isn't a directory */
1135 snprintf(filename, sizeof(filename) - 1, "%s/%s", dirname, entry->d_name);
1136 if (!stat(filename, &buf) && S_ISREG(buf.st_mode))
1137 silc_list_key(filename, FALSE);
1143 void silc_list_file(const char *filename)
1149 snprintf(path, sizeof(path) - 1, "%s", filename);
1150 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1153 snprintf(path, sizeof(path) - 1, "%s/%s", get_irssi_dir(), filename);
1154 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1157 snprintf(path,sizeof(path) - 1, "%s/clientkeys/%s", get_irssi_dir(),
1159 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1162 snprintf(path,sizeof(path) - 1, "%s/serverkeys/%s", get_irssi_dir(),
1164 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1171 silc_list_key(path, TRUE);
1176 /* Lists locally saved client and server public keys. */
1177 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
1180 GHashTable *optlist;
1185 if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS |
1186 PARAM_FLAG_GETREST, "listkeys", &optlist,
1190 if (*filename != '\0') {
1192 silc_list_file(filename);
1195 int clients, servers;
1197 clients = (g_hash_table_lookup(optlist, "clients") != NULL);
1198 servers = (g_hash_table_lookup(optlist, "servers") != NULL);
1200 if (!(clients || servers))
1201 clients = servers = 1;
1204 snprintf(dirname, sizeof(dirname) - 1, "%s/serverkeys", get_irssi_dir());
1205 silc_list_keys_in_dir(dirname, "server");
1209 snprintf(dirname, sizeof(dirname) - 1, "%s/clientkeys", get_irssi_dir());
1210 silc_list_keys_in_dir(dirname, "client");
1213 cmd_params_free(free_arg);
1216 void silc_channels_init(void)
1218 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1219 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1220 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1221 signal_add("gui exit", (SIGNAL_FUNC) sig_gui_quit);
1222 signal_add("mime", (SIGNAL_FUNC) sig_mime);
1224 command_bind_silc("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1225 command_bind_silc("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1226 command_bind_silc("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1227 command_bind_silc("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1228 command_bind_silc("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1229 // command_bind_silc("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1230 // command_bind("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
1232 command_set_options("listkeys", "clients servers");
1233 command_set_options("action", "sign channel");
1234 command_set_options("notice", "sign channel");
1236 silc_nicklist_init();
1239 void silc_channels_deinit(void)
1241 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1242 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1243 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1244 signal_remove("gui exit", (SIGNAL_FUNC) sig_gui_quit);
1245 signal_remove("mime", (SIGNAL_FUNC) sig_mime);
1247 command_unbind("part", (SIGNAL_FUNC) command_part);
1248 command_unbind("me", (SIGNAL_FUNC) command_me);
1249 command_unbind("action", (SIGNAL_FUNC) command_action);
1250 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1251 command_unbind("away", (SIGNAL_FUNC) command_away);
1252 // command_unbind("key", (SIGNAL_FUNC) command_key);
1253 // command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
1255 silc_nicklist_deinit();