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)
117 SILC_CHANNEL_REC *chanrec;
118 CHANNEL_SETUP_REC *schannel;
121 list = g_strsplit(channels, ",", -1);
122 for (tmp = list; *tmp != NULL; tmp++) {
123 chanrec = silc_channel_find(server, *tmp);
128 key = strchr(channel, ' ');
133 tmpstr = g_string_new(NULL);
135 schannel = channel_setup_find(channel, server->connrec->chatnet);
136 if (key && *key != '\0')
137 g_string_sprintfa(tmpstr, "%s %s", channel, key);
138 else if (schannel && schannel->password && schannel->password[0] != '\0')
139 g_string_sprintfa(tmpstr, "%s %s", channel, schannel->password);
141 g_string_sprintfa(tmpstr, "%s", channel);
143 silc_command_exec(server, "JOIN", tmpstr->str);
145 g_string_free(tmpstr, FALSE);
151 static void sig_connected(SILC_SERVER_REC *server)
153 if (IS_SILC_SERVER(server))
154 server->channels_join = (void *) silc_channels_join;
157 /* "server quit" signal from the core to indicate that QUIT command
160 static void sig_server_quit(SILC_SERVER_REC *server, const char *msg)
162 if (IS_SILC_SERVER(server) && server->conn && server->conn->sock)
163 silc_command_exec(server, "QUIT", msg);
166 static void sig_gui_quit(SILC_SERVER_REC *server, const char *msg)
168 silc_client_stop(silc_client);
171 /* Find Irssi channel entry by SILC channel entry */
173 SILC_CHANNEL_REC *silc_channel_find_entry(SILC_SERVER_REC *server,
174 SilcChannelEntry entry)
178 g_return_val_if_fail(IS_SILC_SERVER(server), NULL);
180 for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
181 SILC_CHANNEL_REC *rec = tmp->data;
183 if (rec->entry == entry)
190 /* PART (LEAVE) command. */
192 static void command_part(const char *data, SILC_SERVER_REC *server,
195 SILC_CHANNEL_REC *chanrec;
198 CMD_SILC_SERVER(server);
200 if (!IS_SILC_SERVER(server) || !server->connected)
201 cmd_return_error(CMDERR_NOT_CONNECTED);
203 if (!strcmp(data, "*") || *data == '\0') {
204 if (!IS_SILC_CHANNEL(item))
205 cmd_return_error(CMDERR_NOT_JOINED);
206 data = item->visible_name;
209 chanrec = silc_channel_find(server, data);
211 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
213 memset(userhost, 0, sizeof(userhost));
214 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
215 server->conn->local_entry->username,
216 server->conn->local_entry->hostname);
217 signal_emit("message part", 5, server, chanrec->name,
218 server->nick, userhost, "");
220 chanrec->left = TRUE;
221 silc_command_exec(server, "LEAVE", chanrec->name);
222 /* enable queueing because we destroy the channel immedially */
223 silc_queue_enable(server->conn);
226 channel_destroy(CHANNEL(chanrec));
230 /* ACTION local command. */
232 static void command_action(const char *data, SILC_SERVER_REC *server,
237 char *message = NULL;
241 CMD_SILC_SERVER(server);
242 if (!IS_SILC_SERVER(server) || !server->connected)
243 cmd_return_error(CMDERR_NOT_CONNECTED);
245 if ((item != NULL) && (!IS_SILC_CHANNEL(item) && !IS_SILC_QUERY(item)))
246 cmd_return_error(CMDERR_NOT_JOINED);
248 /* Now parse all arguments */
249 if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS |
251 "action", &optlist, &target, &msg))
254 if (*target == '\0' || *msg == '\0')
255 cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
257 if (strcmp(target, "*") == 0) {
258 /* send to active channel/query */
260 cmd_param_error(CMDERR_NOT_JOINED);
262 target_type = IS_SILC_CHANNEL(item) ?
263 SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
264 target = (char *)window_item_get_target(item);
265 } else if (g_hash_table_lookup(optlist, "channel") != NULL)
266 target_type = SEND_TARGET_CHANNEL;
268 target_type = SEND_TARGET_NICK;
271 if (!silc_term_utf8()) {
272 int len = silc_utf8_encoded_len(msg, strlen(msg),
274 message = silc_calloc(len + 1, sizeof(*message));
275 g_return_if_fail(message != NULL);
276 silc_utf8_encode(msg, strlen(msg), SILC_STRING_LOCALE,
280 if (target != NULL) {
281 if (target_type == SEND_TARGET_CHANNEL) {
282 if (silc_send_channel(server, target, (message != NULL ? message : msg),
283 SILC_MESSAGE_FLAG_ACTION | SILC_MESSAGE_FLAG_UTF8 |
284 (g_hash_table_lookup(optlist, "sign") != NULL ?
285 SILC_MESSAGE_FLAG_SIGNED : 0))) {
286 if (g_hash_table_lookup(optlist, "sign"))
287 signal_emit("message silc signed_own_action", 3, server, msg, target);
289 signal_emit("message silc own_action", 3, server, msg, target);
292 if (silc_send_msg(server, target, (message != NULL ? message : msg),
293 (message != NULL ? strlen(message) : strlen(msg)),
294 SILC_MESSAGE_FLAG_ACTION | SILC_MESSAGE_FLAG_UTF8 |
295 (g_hash_table_lookup(optlist, "sign") != NULL ?
296 SILC_MESSAGE_FLAG_SIGNED : 0))) {
297 if (g_hash_table_lookup(optlist, "sign"))
298 signal_emit("message silc signed_own_private_action", 3,
299 server, msg, target);
301 signal_emit("message silc own_private_action", 3,
302 server, msg, target);
307 cmd_params_free(free_arg);
311 /* ME local command. */
313 static void command_me(const char *data, SILC_SERVER_REC *server,
318 CMD_SILC_SERVER(server);
319 if (!IS_SILC_SERVER(server) || !server->connected)
320 cmd_return_error(CMDERR_NOT_CONNECTED);
322 if (!IS_SILC_CHANNEL(item) && !IS_SILC_QUERY(item))
323 cmd_return_error(CMDERR_NOT_JOINED);
325 if (IS_SILC_CHANNEL(item))
326 tmpcmd = g_strdup_printf("-channel %s %s", item->visible_name, data);
328 tmpcmd = g_strdup_printf("%s %s", item->visible_name, data);
330 command_action(tmpcmd, server, item);
334 /* NOTICE local command. */
336 static void command_notice(const char *data, SILC_SERVER_REC *server,
341 char *message = NULL;
345 CMD_SILC_SERVER(server);
346 if (!IS_SILC_SERVER(server) || !server->connected)
347 cmd_return_error(CMDERR_NOT_CONNECTED);
349 if ((item != NULL) && (!IS_SILC_CHANNEL(item) && !IS_SILC_QUERY(item)))
350 cmd_return_error(CMDERR_NOT_JOINED);
352 /* Now parse all arguments */
353 if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS |
355 "notice", &optlist, &target, &msg))
358 if (*target == '\0' || *msg == '\0')
359 cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
361 if (strcmp(target, "*") == 0) {
362 /* send to active channel/query */
364 cmd_param_error(CMDERR_NOT_JOINED);
366 target_type = IS_SILC_CHANNEL(item) ?
367 SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
368 target = (char *)window_item_get_target(item);
369 } else if (g_hash_table_lookup(optlist, "channel") != NULL)
370 target_type = SEND_TARGET_CHANNEL;
372 target_type = SEND_TARGET_NICK;
375 if (!silc_term_utf8()) {
376 int len = silc_utf8_encoded_len(msg, strlen(msg),
378 message = silc_calloc(len + 1, sizeof(*message));
379 g_return_if_fail(message != NULL);
380 silc_utf8_encode(msg, strlen(msg), SILC_STRING_LOCALE,
384 if (target != NULL) {
385 if (target_type == SEND_TARGET_CHANNEL) {
386 if (silc_send_channel(server, target, (message != NULL ? message : msg),
387 SILC_MESSAGE_FLAG_NOTICE | SILC_MESSAGE_FLAG_UTF8 |
388 (g_hash_table_lookup(optlist, "sign") != NULL ?
389 SILC_MESSAGE_FLAG_SIGNED : 0))) {
390 if (g_hash_table_lookup(optlist, "sign"))
391 signal_emit("message silc signed_own_notice", 3, server, msg, target);
393 signal_emit("message silc own_notice", 3, server, msg, target);
396 if (silc_send_msg(server, target, (message != NULL ? message : msg),
397 (message != NULL ? strlen(message) : strlen(msg)),
398 SILC_MESSAGE_FLAG_NOTICE | SILC_MESSAGE_FLAG_UTF8 |
399 (g_hash_table_lookup(optlist, "sign") != NULL ?
400 SILC_MESSAGE_FLAG_SIGNED : 0))) {
401 if (g_hash_table_lookup(optlist, "sign"))
402 signal_emit("message silc signed_own_private_notice", 3,
403 server, msg, target);
405 signal_emit("message silc own_private_notice", 3,
406 server, msg, target);
411 cmd_params_free(free_arg);
415 /* AWAY local command. Sends UMODE command that sets the SILC_UMODE_GONE
418 bool silc_set_away(const char *reason, SILC_SERVER_REC *server)
422 if (!IS_SILC_SERVER(server) || !server->connected)
425 if (*reason == '\0') {
426 /* Remove any possible away message */
427 silc_client_set_away_message(silc_client, server->conn, NULL);
430 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
433 /* Set the away message */
434 silc_client_set_away_message(silc_client, server->conn, (char *)reason);
437 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
438 SILCTXT_SET_AWAY, reason);
441 server->usermode_away = set;
442 g_free_and_null(server->away_reason);
444 server->away_reason = g_strdup((char *)reason);
446 signal_emit("away mode changed", 1, server);
451 static void command_away(const char *data, SILC_SERVER_REC *server,
454 CMD_SILC_SERVER(server);
456 if (!IS_SILC_SERVER(server) || !server->connected)
457 cmd_return_error(CMDERR_NOT_CONNECTED);
459 g_free_and_null(server->away_reason);
460 if ((data) && (*data != '\0'))
461 server->away_reason = g_strdup(data);
463 silc_command_exec(server, "UMODE",
464 (server->away_reason != NULL) ? "+g" : "-g");
468 int type; /* 1 = msg, 2 = channel */
470 SILC_SERVER_REC *server;
473 /* Key agreement callback that is called after the key agreement protocol
474 has been performed. This is called also if error occured during the
475 key agreement protocol. The `key' is the allocated key material and
476 the caller is responsible of freeing it. The `key' is NULL if error
477 has occured. The application can freely use the `key' to whatever
478 purpose it needs. See lib/silcske/silcske.h for the definition of
479 the SilcSKEKeyMaterial structure. */
481 static void keyagr_completion(SilcClient client,
482 SilcClientConnection conn,
483 SilcClientEntry client_entry,
484 SilcKeyAgreementStatus status,
485 SilcSKEKeyMaterial *key,
488 KeyInternal i = (KeyInternal)context;
491 case SILC_KEY_AGREEMENT_OK:
492 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
493 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
496 /* Set the private key for this client */
497 silc_client_del_private_message_key(client, conn, client_entry);
498 silc_client_add_private_message_key_ske(client, conn, client_entry,
499 NULL, NULL, key, i->responder);
500 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
501 SILCTXT_KEY_AGREEMENT_PRIVMSG,
502 client_entry->nickname);
503 silc_ske_free_key_material(key);
508 case SILC_KEY_AGREEMENT_ERROR:
509 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
510 SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
513 case SILC_KEY_AGREEMENT_FAILURE:
514 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
515 SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
518 case SILC_KEY_AGREEMENT_TIMEOUT:
519 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
520 SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
523 case SILC_KEY_AGREEMENT_ABORTED:
524 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
525 SILCTXT_KEY_AGREEMENT_ABORTED, client_entry->nickname);
528 case SILC_KEY_AGREEMENT_ALREADY_STARTED:
529 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
530 SILCTXT_KEY_AGREEMENT_ALREADY_STARTED,
531 client_entry->nickname);
534 case SILC_KEY_AGREEMENT_SELF_DENIED:
535 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
536 SILCTXT_KEY_AGREEMENT_SELF_DENIED);
547 /* Local command KEY. This command is used to set and unset private
548 keys for channels, set and unset private keys for private messages
549 with remote clients and to send key agreement requests and
550 negotiate the key agreement protocol with remote client. The
551 key agreement is supported only to negotiate private message keys,
552 it currently cannot be used to negotiate private keys for channels,
553 as it is not convenient for that purpose. */
556 SILC_SERVER_REC *server;
562 /* Callback to be called after client information is resolved from the
565 static void silc_client_command_key_get_clients(SilcClient client,
566 SilcClientConnection conn,
567 SilcClientEntry *clients,
568 SilcUInt32 clients_count,
571 KeyGetClients internal = (KeyGetClients)context;
574 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s",
576 silc_free(internal->data);
577 silc_free(internal->nick);
582 signal_emit("command key", 3, internal->data, internal->server,
585 silc_free(internal->data);
586 silc_free(internal->nick);
590 static void command_key(const char *data, SILC_SERVER_REC *server,
593 SilcClientConnection conn;
594 SilcClientEntry *entrys, client_entry = NULL;
595 SilcUInt32 entry_count;
596 SILC_CHANNEL_REC *chanrec = NULL;
597 SilcChannelEntry channel_entry = NULL;
598 char *nickname = NULL, *tmp;
599 int command = 0, port = 0, type = 0;
600 char *hostname = NULL;
601 KeyInternal internal = NULL;
603 unsigned char **argv;
604 SilcUInt32 *argv_lens, *argv_types;
605 char *bindhost = NULL;
607 CMD_SILC_SERVER(server);
609 if (!server || !IS_SILC_SERVER(server) || !server->connected)
610 cmd_return_error(CMDERR_NOT_CONNECTED);
614 /* Now parse all arguments */
615 tmp = g_strconcat("KEY", " ", data, NULL);
616 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
620 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
623 if (!strcasecmp(argv[1], "msg"))
625 if (!strcasecmp(argv[1], "channel"))
629 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
632 if (argv[2][0] == '*') {
633 nickname = strdup("*");
635 /* Parse the typed nickname. */
636 if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
637 printformat_module("fe-common/silc", server, NULL,
638 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
642 /* Find client entry */
643 entrys = silc_client_get_clients_local(silc_client, conn, nickname,
644 argv[2], &entry_count);
646 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
647 inter->server = server;
648 inter->data = strdup(data);
649 inter->nick = strdup(nickname);
651 silc_client_get_clients(silc_client, conn, nickname, argv[2],
652 silc_client_command_key_get_clients, inter);
655 client_entry = entrys[0];
661 /* Get channel entry */
664 if (argv[2][0] == '*') {
665 if (!conn->current_channel) {
667 cmd_return_error(CMDERR_NOT_JOINED);
669 name = conn->current_channel->channel_name;
674 chanrec = silc_channel_find(server, name);
675 if (chanrec == NULL) {
677 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
679 channel_entry = chanrec->entry;
683 if (!strcasecmp(argv[3], "set")) {
687 char *cipher = NULL, *hmac = NULL;
689 if (type == 1 && client_entry) {
690 /* Set private message key */
691 bool responder = FALSE;
693 silc_client_del_private_message_key(silc_client, conn, client_entry);
696 if (!strcasecmp(argv[5], "-responder"))
702 if (!strcasecmp(argv[6], "-responder"))
708 if (!strcasecmp(argv[7], "-responder"))
712 silc_client_add_private_message_key(silc_client, conn, client_entry,
714 argv[4], argv_lens[4],
716 TRUE : FALSE), responder);
718 /* Send the key to the remote client so that it starts using it
720 /* XXX for now we don't do this. This feature is pretty stupid
721 and should perhaps be removed altogether from SILC.
722 silc_client_send_private_message_key(silc_client, conn,
725 } else if (type == 2) {
726 /* Set private channel key */
727 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
728 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
729 SILCTXT_CH_PRIVATE_KEY_NOMODE,
730 channel_entry->channel_name);
739 if (!silc_client_add_channel_private_key(silc_client, conn,
743 argv_lens[4], NULL)) {
744 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
745 SILCTXT_CH_PRIVATE_KEY_ERROR,
746 channel_entry->channel_name);
750 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
751 SILCTXT_CH_PRIVATE_KEY_ADD,
752 channel_entry->channel_name);
760 if (!strcasecmp(argv[3], "unset")) {
763 if (type == 1 && client_entry) {
764 /* Unset private message key */
765 silc_client_del_private_message_key(silc_client, conn, client_entry);
766 } else if (type == 2) {
767 /* Unset channel key(s) */
768 SilcChannelPrivateKey *keys;
769 SilcUInt32 keys_count;
773 silc_client_del_channel_private_keys(silc_client, conn,
777 number = atoi(argv[4]);
778 keys = silc_client_list_channel_private_keys(silc_client, conn,
784 if (!number || number > keys_count) {
785 silc_client_free_channel_private_keys(keys, keys_count);
789 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
791 silc_client_free_channel_private_keys(keys, keys_count);
799 if (!strcasecmp(argv[3], "list")) {
803 SilcPrivateMessageKeys keys;
804 SilcUInt32 keys_count;
808 keys = silc_client_list_private_message_keys(silc_client, conn,
813 /* list the private message key(s) */
814 if (nickname[0] == '*') {
815 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
816 SILCTXT_PRIVATE_KEY_LIST);
817 for (k = 0; k < keys_count; k++) {
818 memset(buf, 0, sizeof(buf));
819 strncat(buf, " ", 2);
820 len = strlen(keys[k].client_entry->nickname);
821 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
823 for (i = 0; i < 30 - len; i++)
827 len = strlen(keys[k].cipher);
828 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
830 for (i = 0; i < 14 - len; i++)
835 strcat(buf, "<hidden>");
837 strcat(buf, "*generated*");
839 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
842 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
843 SILCTXT_PRIVATE_KEY_LIST_NICK,
844 client_entry->nickname);
845 for (k = 0; k < keys_count; k++) {
846 if (keys[k].client_entry != client_entry)
849 memset(buf, 0, sizeof(buf));
850 strncat(buf, " ", 2);
851 len = strlen(keys[k].client_entry->nickname);
852 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
854 for (i = 0; i < 30 - len; i++)
858 len = strlen(keys[k].cipher);
859 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
861 for (i = 0; i < 14 - len; i++)
866 strcat(buf, "<hidden>");
868 strcat(buf, "*generated*");
870 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
874 silc_client_free_private_message_keys(keys, keys_count);
876 } else if (type == 2) {
877 SilcChannelPrivateKey *keys;
878 SilcUInt32 keys_count;
882 keys = silc_client_list_channel_private_keys(silc_client, conn,
886 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
887 SILCTXT_CH_PRIVATE_KEY_LIST,
888 channel_entry->channel_name);
893 for (k = 0; k < keys_count; k++) {
894 memset(buf, 0, sizeof(buf));
895 strncat(buf, " ", 2);
897 len = strlen(silc_cipher_get_name(keys[k]->cipher));
898 strncat(buf, silc_cipher_get_name(keys[k]->cipher),
899 len > 16 ? 16 : len);
901 for (i = 0; i < 16 - len; i++)
905 len = strlen(silc_hmac_get_name(keys[k]->hmac));
906 strncat(buf, silc_hmac_get_name(keys[k]->hmac), len > 16 ? 16 : len);
908 for (i = 0; i < 16 - len; i++)
912 strcat(buf, "<hidden>");
914 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
917 silc_client_free_channel_private_keys(keys, keys_count);
923 /* Send command is used to send key agreement */
924 if (!strcasecmp(argv[3], "agreement")) {
930 port = atoi(argv[5]);
932 internal = silc_calloc(1, sizeof(*internal));
933 internal->type = type;
934 internal->server = server;
937 if (settings_get_bool("use_auto_addr")) {
939 hostname = (char *)settings_get_str("auto_public_ip");
941 /* If the hostname isn't set, treat this case as if auto_public_ip
943 if ((hostname) && (*hostname == '\0')) {
946 bindhost = (char *)settings_get_str("auto_bind_ip");
948 /* if the bind_ip isn't set, but the public_ip IS, then assume then
949 public_ip is the same value as the bind_ip. */
950 if ((bindhost) && (*bindhost == '\0'))
952 port = settings_get_int("auto_bind_port");
954 } /* if use_auto_addr */
958 /* Start command is used to start key agreement (after receiving the
959 key_agreement client operation). */
960 if (!strcasecmp(argv[3], "negotiate")) {
966 port = atoi(argv[5]);
968 internal = silc_calloc(1, sizeof(*internal));
969 internal->type = type;
970 internal->server = server;
973 /* Change current channel private key */
974 if (!strcasecmp(argv[3], "change")) {
977 /* Unset channel key(s) */
978 SilcChannelPrivateKey *keys;
979 SilcUInt32 keys_count;
982 keys = silc_client_list_channel_private_keys(silc_client, conn,
990 if (chanrec->cur_key >= keys_count)
991 chanrec->cur_key = 0;
995 number = atoi(argv[4]);
996 if (!number || number > keys_count)
997 chanrec->cur_key = 0;
999 chanrec->cur_key = number - 1;
1002 /* Set the current channel private key */
1003 silc_client_current_channel_private_key(silc_client, conn,
1005 keys[chanrec->cur_key]);
1006 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1007 SILCTXT_CH_PRIVATE_KEY_CHANGE, chanrec->cur_key + 1,
1008 channel_entry->channel_name);
1010 silc_client_free_channel_private_keys(keys, keys_count);
1016 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
1017 "Usage: /KEY msg|channel <nickname|channel> "
1018 "set|unset|agreement|negotiate [<arguments>]");
1022 if (command == 4 && client_entry) {
1023 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1024 SILCTXT_KEY_AGREEMENT, argv[2]);
1025 internal->responder = TRUE;
1026 silc_client_send_key_agreement(
1027 silc_client, conn, client_entry, hostname,
1029 settings_get_int("key_exchange_timeout_secs"),
1030 keyagr_completion, internal);
1032 silc_free(internal);
1036 if (command == 5 && client_entry && hostname) {
1037 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1038 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
1039 internal->responder = FALSE;
1040 silc_client_perform_key_agreement(silc_client, conn, client_entry,
1041 hostname, port, keyagr_completion,
1047 silc_free(nickname);
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);
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);
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("gui exit", (SIGNAL_FUNC) sig_gui_quit);
1244 signal_add("mime", (SIGNAL_FUNC) sig_mime);
1246 command_bind_silc("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1247 command_bind_silc("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1248 command_bind_silc("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1249 command_bind_silc("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1250 command_bind_silc("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1251 command_bind_silc("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1252 command_bind("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
1254 command_set_options("listkeys", "clients servers");
1255 command_set_options("action", "sign channel");
1256 command_set_options("notice", "sign channel");
1258 silc_nicklist_init();
1261 void silc_channels_deinit(void)
1263 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1264 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1265 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1266 signal_remove("gui exit", (SIGNAL_FUNC) sig_gui_quit);
1267 signal_remove("mime", (SIGNAL_FUNC) sig_mime);
1269 command_unbind("part", (SIGNAL_FUNC) command_part);
1270 command_unbind("me", (SIGNAL_FUNC) command_me);
1271 command_unbind("action", (SIGNAL_FUNC) command_action);
1272 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1273 command_unbind("away", (SIGNAL_FUNC) command_away);
1274 command_unbind("key", (SIGNAL_FUNC) command_key);
1275 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
1277 silc_nicklist_deinit();