2 silc-channels.c : irssi
4 Copyright (C) 2000 - 2001, 2004 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 "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 char type[128], enc[128];
53 unsigned char *data, *message;
54 SilcUInt32 data_len, message_len;
56 if (!(IS_SILC_SERVER(server)))
59 message = silc_unescape_data(blob, &message_len);
61 memset(type, 0, sizeof(type));
62 memset(enc, 0, sizeof(enc));
64 if (!silc_mime_parse(message, message_len, NULL, 0, type, sizeof(type) - 1,
65 enc, sizeof(enc) - 1, &data, &data_len)) {
70 printformat_module("fe-common/silc", server,
71 channel == NULL ? NULL : channel->name,
72 MSGLEVEL_CRAP, SILCTXT_MESSAGE_DATA,
73 nick == NULL ? "[<unknown>]" : nick, type);
79 SILC_CHANNEL_REC *silc_channel_create(SILC_SERVER_REC *server,
81 const char *visible_name,
84 SILC_CHANNEL_REC *rec;
86 g_return_val_if_fail(server == NULL || IS_SILC_SERVER(server), NULL);
87 g_return_val_if_fail(name != NULL, NULL);
89 rec = g_new0(SILC_CHANNEL_REC, 1);
90 rec->chat_type = SILC_PROTOCOL;
91 channel_init((CHANNEL_REC *)rec, (SERVER_REC *)server, name, name,
96 static void sig_channel_destroyed(SILC_CHANNEL_REC *channel)
98 if (!IS_SILC_CHANNEL(channel))
100 if (channel->server && channel->server->disconnected)
103 if (channel->server != NULL && !channel->left && !channel->kicked) {
104 /* destroying channel record without actually
105 having left the channel yet */
106 silc_command_exec(channel->server, "LEAVE", channel->name);
107 /* enable queueing because we destroy the channel immedially */
108 silc_queue_enable(channel->server->conn);
112 static void silc_channels_join(SILC_SERVER_REC *server,
113 const char *channels, int automatic)
116 SILC_CHANNEL_REC *chanrec;
118 list = g_strsplit(channels, ",", -1);
119 for (tmp = list; *tmp != NULL; tmp++) {
120 chanrec = silc_channel_find(server, *tmp);
124 silc_command_exec(server, "JOIN", *tmp);
130 static void sig_connected(SILC_SERVER_REC *server)
132 if (IS_SILC_SERVER(server))
133 server->channels_join = (void *) silc_channels_join;
136 /* "server quit" signal from the core to indicate that QUIT command
139 static void sig_server_quit(SILC_SERVER_REC *server, const char *msg)
141 if (IS_SILC_SERVER(server) && server->conn && server->conn->sock)
142 silc_command_exec(server, "QUIT", msg);
145 static void sig_gui_quit(SILC_SERVER_REC *server, const char *msg)
147 silc_client_stop(silc_client);
150 /* Find Irssi channel entry by SILC channel entry */
152 SILC_CHANNEL_REC *silc_channel_find_entry(SILC_SERVER_REC *server,
153 SilcChannelEntry entry)
157 g_return_val_if_fail(IS_SILC_SERVER(server), NULL);
159 for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
160 SILC_CHANNEL_REC *rec = tmp->data;
162 if (rec->entry == entry)
169 /* PART (LEAVE) command. */
171 static void command_part(const char *data, SILC_SERVER_REC *server,
174 SILC_CHANNEL_REC *chanrec;
177 CMD_SILC_SERVER(server);
179 if (!IS_SILC_SERVER(server) || !server->connected)
180 cmd_return_error(CMDERR_NOT_CONNECTED);
182 if (!strcmp(data, "*") || *data == '\0') {
183 if (!IS_SILC_CHANNEL(item))
184 cmd_return_error(CMDERR_NOT_JOINED);
185 data = item->visible_name;
188 chanrec = silc_channel_find(server, data);
190 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
192 memset(userhost, 0, sizeof(userhost));
193 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
194 server->conn->local_entry->username,
195 server->conn->local_entry->hostname);
196 signal_emit("message part", 5, server, chanrec->name,
197 server->nick, userhost, "");
199 chanrec->left = TRUE;
200 silc_command_exec(server, "LEAVE", chanrec->name);
201 /* enable queueing because we destroy the channel immedially */
202 silc_queue_enable(server->conn);
205 channel_destroy(CHANNEL(chanrec));
209 /* ACTION local command. */
211 static void command_action(const char *data, SILC_SERVER_REC *server,
216 char *message = NULL;
220 CMD_SILC_SERVER(server);
221 if (!IS_SILC_SERVER(server) || !server->connected)
222 cmd_return_error(CMDERR_NOT_CONNECTED);
224 if ((item != NULL) && (!IS_SILC_CHANNEL(item) && !IS_SILC_QUERY(item)))
225 cmd_return_error(CMDERR_NOT_JOINED);
227 /* Now parse all arguments */
228 if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS |
230 "action", &optlist, &target, &msg))
233 if (*target == '\0' || *msg == '\0')
234 cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
236 if (strcmp(target, "*") == 0) {
237 /* send to active channel/query */
239 cmd_param_error(CMDERR_NOT_JOINED);
241 target_type = IS_SILC_CHANNEL(item) ?
242 SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
243 target = (char *)window_item_get_target(item);
244 } else if (g_hash_table_lookup(optlist, "channel") != NULL)
245 target_type = SEND_TARGET_CHANNEL;
247 target_type = SEND_TARGET_NICK;
250 if (!silc_term_utf8()) {
251 int len = silc_utf8_encoded_len(msg, strlen(msg),
253 message = silc_calloc(len + 1, sizeof(*message));
254 g_return_if_fail(message != NULL);
255 silc_utf8_encode(msg, strlen(msg), SILC_STRING_LOCALE,
259 if (target != NULL) {
260 if (target_type == SEND_TARGET_CHANNEL) {
261 if (silc_send_channel(server, target, (message != NULL ? message : msg),
262 SILC_MESSAGE_FLAG_ACTION | SILC_MESSAGE_FLAG_UTF8 |
263 (g_hash_table_lookup(optlist, "sign") != NULL ?
264 SILC_MESSAGE_FLAG_SIGNED : 0))) {
265 if (g_hash_table_lookup(optlist, "sign"))
266 signal_emit("message silc signed_own_action", 3, server, msg, target);
268 signal_emit("message silc own_action", 3, server, msg, target);
271 if (silc_send_msg(server, target, (message != NULL ? message : msg),
272 (message != NULL ? strlen(message) : strlen(msg)),
273 SILC_MESSAGE_FLAG_ACTION | SILC_MESSAGE_FLAG_UTF8 |
274 (g_hash_table_lookup(optlist, "sign") != NULL ?
275 SILC_MESSAGE_FLAG_SIGNED : 0))) {
276 if (g_hash_table_lookup(optlist, "sign"))
277 signal_emit("message silc signed_own_private_action", 3,
278 server, msg, target);
280 signal_emit("message silc own_private_action", 3,
281 server, msg, target);
286 cmd_params_free(free_arg);
290 /* ME local command. */
292 static void command_me(const char *data, SILC_SERVER_REC *server,
297 CMD_SILC_SERVER(server);
298 if (!IS_SILC_SERVER(server) || !server->connected)
299 cmd_return_error(CMDERR_NOT_CONNECTED);
301 if (!IS_SILC_CHANNEL(item) && !IS_SILC_QUERY(item))
302 cmd_return_error(CMDERR_NOT_JOINED);
304 if (IS_SILC_CHANNEL(item))
305 tmpcmd = g_strdup_printf("-channel %s %s", item->visible_name, data);
307 tmpcmd = g_strdup_printf("%s %s", item->visible_name, data);
309 command_action(tmpcmd, server, item);
313 /* NOTICE local command. */
315 static void command_notice(const char *data, SILC_SERVER_REC *server,
320 char *message = NULL;
324 CMD_SILC_SERVER(server);
325 if (!IS_SILC_SERVER(server) || !server->connected)
326 cmd_return_error(CMDERR_NOT_CONNECTED);
328 if ((item != NULL) && (!IS_SILC_CHANNEL(item) && !IS_SILC_QUERY(item)))
329 cmd_return_error(CMDERR_NOT_JOINED);
331 /* Now parse all arguments */
332 if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS |
334 "notice", &optlist, &target, &msg))
337 if (*target == '\0' || *msg == '\0')
338 cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
340 if (strcmp(target, "*") == 0) {
341 /* send to active channel/query */
343 cmd_param_error(CMDERR_NOT_JOINED);
345 target_type = IS_SILC_CHANNEL(item) ?
346 SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
347 target = (char *)window_item_get_target(item);
348 } else if (g_hash_table_lookup(optlist, "channel") != NULL)
349 target_type = SEND_TARGET_CHANNEL;
351 target_type = SEND_TARGET_NICK;
354 if (!silc_term_utf8()) {
355 int len = silc_utf8_encoded_len(msg, strlen(msg),
357 message = silc_calloc(len + 1, sizeof(*message));
358 g_return_if_fail(message != NULL);
359 silc_utf8_encode(msg, strlen(msg), SILC_STRING_LOCALE,
363 if (target != NULL) {
364 if (target_type == SEND_TARGET_CHANNEL) {
365 if (silc_send_channel(server, target, (message != NULL ? message : msg),
366 SILC_MESSAGE_FLAG_NOTICE | SILC_MESSAGE_FLAG_UTF8 |
367 (g_hash_table_lookup(optlist, "sign") != NULL ?
368 SILC_MESSAGE_FLAG_SIGNED : 0))) {
369 if (g_hash_table_lookup(optlist, "sign"))
370 signal_emit("message silc signed_own_notice", 3, server, msg, target);
372 signal_emit("message silc own_notice", 3, server, msg, target);
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 (g_hash_table_lookup(optlist, "sign") != NULL ?
379 SILC_MESSAGE_FLAG_SIGNED : 0))) {
380 if (g_hash_table_lookup(optlist, "sign"))
381 signal_emit("message silc signed_own_private_notice", 3,
382 server, msg, target);
384 signal_emit("message silc own_private_notice", 3,
385 server, msg, target);
390 cmd_params_free(free_arg);
394 /* AWAY local command. Sends UMODE command that sets the SILC_UMODE_GONE
397 bool silc_set_away(const char *reason, SILC_SERVER_REC *server)
401 if (!IS_SILC_SERVER(server) || !server->connected)
404 if (*reason == '\0') {
405 /* Remove any possible away message */
406 silc_client_set_away_message(silc_client, server->conn, NULL);
409 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
412 /* Set the away message */
413 silc_client_set_away_message(silc_client, server->conn, (char *)reason);
416 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
417 SILCTXT_SET_AWAY, reason);
420 server->usermode_away = set;
421 g_free_and_null(server->away_reason);
423 server->away_reason = g_strdup((char *)reason);
425 signal_emit("away mode changed", 1, server);
430 static void command_away(const char *data, SILC_SERVER_REC *server,
433 CMD_SILC_SERVER(server);
435 if (!IS_SILC_SERVER(server) || !server->connected)
436 cmd_return_error(CMDERR_NOT_CONNECTED);
438 g_free_and_null(server->away_reason);
439 if ((data) && (*data != '\0'))
440 server->away_reason = g_strdup(data);
442 silc_command_exec(server, "UMODE",
443 (server->away_reason != NULL) ? "+g" : "-g");
447 int type; /* 1 = msg, 2 = channel */
449 SILC_SERVER_REC *server;
452 /* Key agreement callback that is called after the key agreement protocol
453 has been performed. This is called also if error occured during the
454 key agreement protocol. The `key' is the allocated key material and
455 the caller is responsible of freeing it. The `key' is NULL if error
456 has occured. The application can freely use the `key' to whatever
457 purpose it needs. See lib/silcske/silcske.h for the definition of
458 the SilcSKEKeyMaterial structure. */
460 static void keyagr_completion(SilcClient client,
461 SilcClientConnection conn,
462 SilcClientEntry client_entry,
463 SilcKeyAgreementStatus status,
464 SilcSKEKeyMaterial *key,
467 KeyInternal i = (KeyInternal)context;
470 case SILC_KEY_AGREEMENT_OK:
471 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
472 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
475 /* Set the private key for this client */
476 silc_client_del_private_message_key(client, conn, client_entry);
477 silc_client_add_private_message_key_ske(client, conn, client_entry,
478 NULL, NULL, key, i->responder);
479 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
480 SILCTXT_KEY_AGREEMENT_PRIVMSG,
481 client_entry->nickname);
482 silc_ske_free_key_material(key);
487 case SILC_KEY_AGREEMENT_ERROR:
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,
546 SilcClientEntry *clients,
547 SilcUInt32 clients_count,
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 *entrys, client_entry = NULL;
574 SilcUInt32 entry_count;
575 SILC_CHANNEL_REC *chanrec = NULL;
576 SilcChannelEntry channel_entry = NULL;
577 char *nickname = NULL, *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;
586 CMD_SILC_SERVER(server);
588 if (!server || !IS_SILC_SERVER(server) || !server->connected)
589 cmd_return_error(CMDERR_NOT_CONNECTED);
593 /* Now parse all arguments */
594 tmp = g_strconcat("KEY", " ", data, NULL);
595 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
599 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
602 if (!strcasecmp(argv[1], "msg"))
604 if (!strcasecmp(argv[1], "channel"))
608 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
611 if (argv[2][0] == '*') {
612 nickname = strdup("*");
614 /* Parse the typed nickname. */
615 if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
616 printformat_module("fe-common/silc", server, NULL,
617 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
621 /* Find client entry */
622 entrys = silc_client_get_clients_local(silc_client, conn, nickname,
623 argv[2], &entry_count);
625 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
626 inter->server = server;
627 inter->data = strdup(data);
628 inter->nick = strdup(nickname);
630 silc_client_get_clients(silc_client, conn, nickname, argv[2],
631 silc_client_command_key_get_clients, inter);
634 client_entry = entrys[0];
640 /* Get channel entry */
643 if (argv[2][0] == '*') {
644 if (!conn->current_channel) {
646 cmd_return_error(CMDERR_NOT_JOINED);
648 name = conn->current_channel->channel_name;
653 chanrec = silc_channel_find(server, name);
654 if (chanrec == NULL) {
656 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
658 channel_entry = chanrec->entry;
662 if (!strcasecmp(argv[3], "set")) {
666 char *cipher = NULL, *hmac = NULL;
668 if (type == 1 && client_entry) {
669 /* Set private message key */
670 bool responder = FALSE;
672 silc_client_del_private_message_key(silc_client, conn, client_entry);
675 if (!strcasecmp(argv[5], "-responder"))
681 if (!strcasecmp(argv[6], "-responder"))
687 if (!strcasecmp(argv[7], "-responder"))
691 silc_client_add_private_message_key(silc_client, conn, client_entry,
693 argv[4], argv_lens[4],
695 TRUE : FALSE), responder);
697 /* Send the key to the remote client so that it starts using it
699 /* XXX for now we don't do this. This feature is pretty stupid
700 and should perhaps be removed altogether from SILC.
701 silc_client_send_private_message_key(silc_client, conn,
704 } else if (type == 2) {
705 /* Set private channel key */
706 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
707 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
708 SILCTXT_CH_PRIVATE_KEY_NOMODE,
709 channel_entry->channel_name);
718 if (!silc_client_add_channel_private_key(silc_client, conn,
722 argv_lens[4], NULL)) {
723 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
724 SILCTXT_CH_PRIVATE_KEY_ERROR,
725 channel_entry->channel_name);
729 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
730 SILCTXT_CH_PRIVATE_KEY_ADD,
731 channel_entry->channel_name);
739 if (!strcasecmp(argv[3], "unset")) {
742 if (type == 1 && client_entry) {
743 /* Unset private message key */
744 silc_client_del_private_message_key(silc_client, conn, client_entry);
745 } else if (type == 2) {
746 /* Unset channel key(s) */
747 SilcChannelPrivateKey *keys;
748 SilcUInt32 keys_count;
752 silc_client_del_channel_private_keys(silc_client, conn,
756 number = atoi(argv[4]);
757 keys = silc_client_list_channel_private_keys(silc_client, conn,
763 if (!number || number > keys_count) {
764 silc_client_free_channel_private_keys(keys, keys_count);
768 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
770 silc_client_free_channel_private_keys(keys, keys_count);
778 if (!strcasecmp(argv[3], "list")) {
782 SilcPrivateMessageKeys keys;
783 SilcUInt32 keys_count;
787 keys = silc_client_list_private_message_keys(silc_client, conn,
792 /* list the private message key(s) */
793 if (nickname[0] == '*') {
794 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
795 SILCTXT_PRIVATE_KEY_LIST);
796 for (k = 0; k < keys_count; k++) {
797 memset(buf, 0, sizeof(buf));
798 strncat(buf, " ", 2);
799 len = strlen(keys[k].client_entry->nickname);
800 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
802 for (i = 0; i < 30 - len; i++)
806 len = strlen(keys[k].cipher);
807 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
809 for (i = 0; i < 14 - len; i++)
814 strcat(buf, "<hidden>");
816 strcat(buf, "*generated*");
818 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
821 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
822 SILCTXT_PRIVATE_KEY_LIST_NICK,
823 client_entry->nickname);
824 for (k = 0; k < keys_count; k++) {
825 if (keys[k].client_entry != client_entry)
828 memset(buf, 0, sizeof(buf));
829 strncat(buf, " ", 2);
830 len = strlen(keys[k].client_entry->nickname);
831 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
833 for (i = 0; i < 30 - len; i++)
837 len = strlen(keys[k].cipher);
838 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
840 for (i = 0; i < 14 - len; i++)
845 strcat(buf, "<hidden>");
847 strcat(buf, "*generated*");
849 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
853 silc_client_free_private_message_keys(keys, keys_count);
855 } else if (type == 2) {
856 SilcChannelPrivateKey *keys;
857 SilcUInt32 keys_count;
861 keys = silc_client_list_channel_private_keys(silc_client, conn,
865 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
866 SILCTXT_CH_PRIVATE_KEY_LIST,
867 channel_entry->channel_name);
872 for (k = 0; k < keys_count; k++) {
873 memset(buf, 0, sizeof(buf));
874 strncat(buf, " ", 2);
876 len = strlen(silc_cipher_get_name(keys[k]->cipher));
877 strncat(buf, silc_cipher_get_name(keys[k]->cipher),
878 len > 16 ? 16 : len);
880 for (i = 0; i < 16 - len; i++)
884 len = strlen(silc_hmac_get_name(keys[k]->hmac));
885 strncat(buf, silc_hmac_get_name(keys[k]->hmac), len > 16 ? 16 : len);
887 for (i = 0; i < 16 - len; i++)
891 strcat(buf, "<hidden>");
893 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
896 silc_client_free_channel_private_keys(keys, keys_count);
902 /* Send command is used to send key agreement */
903 if (!strcasecmp(argv[3], "agreement")) {
909 port = atoi(argv[5]);
911 internal = silc_calloc(1, sizeof(*internal));
912 internal->type = type;
913 internal->server = server;
916 if (settings_get_bool("use_auto_addr")) {
918 hostname = (char *)settings_get_str("auto_public_ip");
920 /* If the hostname isn't set, treat this case as if auto_public_ip
922 if ((hostname) && (*hostname == '\0')) {
925 bindhost = (char *)settings_get_str("auto_bind_ip");
927 /* if the bind_ip isn't set, but the public_ip IS, then assume then
928 public_ip is the same value as the bind_ip. */
929 if ((bindhost) && (*bindhost == '\0'))
931 port = settings_get_int("auto_bind_port");
933 } /* if use_auto_addr */
937 /* Start command is used to start key agreement (after receiving the
938 key_agreement client operation). */
939 if (!strcasecmp(argv[3], "negotiate")) {
945 port = atoi(argv[5]);
947 internal = silc_calloc(1, sizeof(*internal));
948 internal->type = type;
949 internal->server = server;
952 /* Change current channel private key */
953 if (!strcasecmp(argv[3], "change")) {
956 /* Unset channel key(s) */
957 SilcChannelPrivateKey *keys;
958 SilcUInt32 keys_count;
961 keys = silc_client_list_channel_private_keys(silc_client, conn,
969 if (chanrec->cur_key >= keys_count)
970 chanrec->cur_key = 0;
974 number = atoi(argv[4]);
975 if (!number || number > keys_count)
976 chanrec->cur_key = 0;
978 chanrec->cur_key = number - 1;
981 /* Set the current channel private key */
982 silc_client_current_channel_private_key(silc_client, conn,
984 keys[chanrec->cur_key]);
985 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
986 SILCTXT_CH_PRIVATE_KEY_CHANGE, chanrec->cur_key + 1,
987 channel_entry->channel_name);
989 silc_client_free_channel_private_keys(keys, keys_count);
995 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
996 "Usage: /KEY msg|channel <nickname|channel> "
997 "set|unset|agreement|negotiate [<arguments>]");
1001 if (command == 4 && client_entry) {
1002 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1003 SILCTXT_KEY_AGREEMENT, argv[2]);
1004 internal->responder = TRUE;
1005 silc_client_send_key_agreement(
1006 silc_client, conn, client_entry, hostname,
1008 settings_get_int("key_exchange_timeout_secs"),
1009 keyagr_completion, internal);
1011 silc_free(internal);
1015 if (command == 5 && client_entry && hostname) {
1016 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1017 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
1018 internal->responder = FALSE;
1019 silc_client_perform_key_agreement(silc_client, conn, client_entry,
1020 hostname, port, keyagr_completion,
1026 silc_free(nickname);
1029 void silc_list_key(const char *pub_filename, int verbose)
1031 SilcPublicKey public_key;
1032 SilcPublicKeyIdentifier ident;
1033 char *fingerprint, *babbleprint;
1037 SilcUInt32 key_len = 0;
1038 int is_server_key = (strstr(pub_filename, "serverkeys") != NULL);
1040 if (silc_pkcs_load_public_key((char *)pub_filename, &public_key,
1041 SILC_PKCS_FILE_PEM) == FALSE)
1042 if (silc_pkcs_load_public_key((char *)pub_filename, &public_key,
1043 SILC_PKCS_FILE_BIN) == FALSE) {
1044 printformat_module("fe-common/silc", NULL, NULL,
1045 MSGLEVEL_CRAP, SILCTXT_LISTKEY_LOADPUB,
1050 ident = silc_pkcs_decode_identifier(public_key->identifier);
1052 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1053 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1054 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1056 if (silc_pkcs_alloc(public_key->name, &pkcs)) {
1057 key_len = silc_pkcs_public_key_set(pkcs, public_key);
1058 silc_pkcs_free(pkcs);
1061 printformat_module("fe-common/silc", NULL, NULL,
1062 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_FILE,
1066 printformat_module("fe-common/silc", NULL, NULL,
1067 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_ALG,
1069 if (key_len && verbose)
1070 printformat_module("fe-common/silc", NULL, NULL,
1071 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_BITS,
1072 (unsigned int)key_len);
1073 if (ident->realname && (!is_server_key || verbose))
1074 printformat_module("fe-common/silc", NULL, NULL,
1075 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_RN,
1077 if (ident->username && verbose)
1078 printformat_module("fe-common/silc", NULL, NULL,
1079 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_UN,
1081 if (ident->host && (is_server_key || verbose))
1082 printformat_module("fe-common/silc", NULL, NULL,
1083 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_HN,
1085 if (ident->email && verbose)
1086 printformat_module("fe-common/silc", NULL, NULL,
1087 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_EMAIL,
1089 if (ident->org && verbose)
1090 printformat_module("fe-common/silc", NULL, NULL,
1091 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_ORG,
1093 if (ident->country && verbose)
1094 printformat_module("fe-common/silc", NULL, NULL,
1095 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_C,
1099 printformat_module("fe-common/silc", NULL, NULL,
1100 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_FINGER,
1102 printformat_module("fe-common/silc", NULL, NULL,
1103 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_BABL,
1107 silc_free(fingerprint);
1108 silc_free(babbleprint);
1110 silc_pkcs_public_key_free(public_key);
1111 silc_pkcs_free_identifier(ident);
1116 void silc_list_keys_in_dir(const char *dirname, const char *where)
1119 struct dirent *entry;
1121 dir = opendir(dirname);
1124 cmd_return_error(CMDERR_ERRNO);
1126 printformat_module("fe-common/silc", NULL, NULL,
1127 MSGLEVEL_CRAP, SILCTXT_LISTKEY_LIST,
1132 while ((entry = readdir(dir)) != NULL) {
1133 /* try to open everything that isn't a directory */
1137 snprintf(filename, sizeof(filename) - 1, "%s/%s", dirname, entry->d_name);
1138 if (!stat(filename, &buf) && S_ISREG(buf.st_mode))
1139 silc_list_key(filename, FALSE);
1145 void silc_list_file(const char *filename)
1151 snprintf(path, sizeof(path) - 1, "%s", filename);
1152 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1155 snprintf(path, sizeof(path) - 1, "%s/%s", get_irssi_dir(), filename);
1156 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1159 snprintf(path,sizeof(path) - 1, "%s/clientkeys/%s", get_irssi_dir(),
1161 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1164 snprintf(path,sizeof(path) - 1, "%s/serverkeys/%s", get_irssi_dir(),
1166 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1173 silc_list_key(path, TRUE);
1177 /* Lists locally saved client and server public keys. */
1178 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
1181 GHashTable *optlist;
1186 if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS |
1187 PARAM_FLAG_GETREST, "listkeys", &optlist,
1191 if (*filename != '\0') {
1193 silc_list_file(filename);
1196 int clients, servers;
1198 clients = (g_hash_table_lookup(optlist, "clients") != NULL);
1199 servers = (g_hash_table_lookup(optlist, "servers") != NULL);
1201 if (!(clients || servers))
1202 clients = servers = 1;
1205 snprintf(dirname, sizeof(dirname) - 1, "%s/serverkeys", get_irssi_dir());
1206 silc_list_keys_in_dir(dirname, "server");
1210 snprintf(dirname, sizeof(dirname) - 1, "%s/clientkeys", get_irssi_dir());
1211 silc_list_keys_in_dir(dirname, "client");
1214 cmd_params_free(free_arg);
1217 void silc_channels_init(void)
1219 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1220 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1221 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1222 signal_add("gui exit", (SIGNAL_FUNC) sig_gui_quit);
1223 signal_add("mime", (SIGNAL_FUNC) sig_mime);
1225 command_bind_silc("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1226 command_bind_silc("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1227 command_bind_silc("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1228 command_bind_silc("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1229 command_bind_silc("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1230 command_bind_silc("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1231 command_bind("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
1233 command_set_options("listkeys", "clients servers");
1234 command_set_options("action", "sign channel");
1235 command_set_options("notice", "sign channel");
1237 silc_nicklist_init();
1240 void silc_channels_deinit(void)
1242 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1243 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1244 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1245 signal_remove("gui exit", (SIGNAL_FUNC) sig_gui_quit);
1246 signal_remove("mime", (SIGNAL_FUNC) sig_mime);
1248 command_unbind("part", (SIGNAL_FUNC) command_part);
1249 command_unbind("me", (SIGNAL_FUNC) command_me);
1250 command_unbind("action", (SIGNAL_FUNC) command_action);
1251 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1252 command_unbind("away", (SIGNAL_FUNC) command_away);
1253 command_unbind("key", (SIGNAL_FUNC) command_key);
1254 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
1256 silc_nicklist_deinit();