2 silc-channels.c : irssi
4 Copyright (C) 2000 - 2001, 2004, 2006, 2007 Timo Sirainen
5 Pekka Riikonen <priikone@silcnet.org>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "net-nonblock.h"
25 #include "net-sendbuffer.h"
34 #include "special-vars.h"
36 #include "channels-setup.h"
38 #include "silc-servers.h"
39 #include "silc-channels.h"
40 #include "silc-queries.h"
41 #include "silc-nicklist.h"
42 #include "silc-cmdqueue.h"
43 #include "window-item-def.h"
45 #include "fe-common/core/printtext.h"
46 #include "fe-common/silc/module-formats.h"
48 #include "silc-commands.h"
50 void sig_mime(SILC_SERVER_REC *server, SILC_CHANNEL_REC *channel,
51 const char *blob, const char *nick, int verified)
53 unsigned char *message;
54 SilcUInt32 message_len;
57 if (!(IS_SILC_SERVER(server)))
60 message = silc_unescape_data(blob, &message_len);
62 mime = silc_mime_decode(NULL, message, message_len);
68 printformat_module("fe-common/silc", server,
69 channel == NULL ? NULL : channel->name,
70 MSGLEVEL_CRAP, SILCTXT_MESSAGE_DATA,
71 nick == NULL ? "[<unknown>]" : nick,
72 silc_mime_get_field(mime, "Content-Type"));
78 SILC_CHANNEL_REC *silc_channel_create(SILC_SERVER_REC *server,
80 const char *visible_name,
83 SILC_CHANNEL_REC *rec;
85 g_return_val_if_fail(server == NULL || IS_SILC_SERVER(server), NULL);
86 g_return_val_if_fail(name != NULL, NULL);
88 rec = g_new0(SILC_CHANNEL_REC, 1);
89 rec->chat_type = SILC_PROTOCOL;
90 channel_init((CHANNEL_REC *)rec, (SERVER_REC *)server, name, name,
95 static void sig_channel_destroyed(SILC_CHANNEL_REC *channel)
97 if (!IS_SILC_CHANNEL(channel))
99 if (channel->server && channel->server->disconnected)
102 if (channel->server != NULL && !channel->left && !channel->kicked) {
103 /* destroying channel record without actually
104 having left the channel yet */
105 silc_command_exec(channel->server, "LEAVE", channel->name);
106 /* enable queueing because we destroy the channel immedially */
107 silc_queue_enable(channel->server->conn);
111 static void silc_channels_join(SILC_SERVER_REC *server,
112 const char *channels, int automatic)
116 SILC_CHANNEL_REC *chanrec;
117 CHANNEL_SETUP_REC *schannel;
120 list = g_strsplit(channels, ",", -1);
121 for (tmp = list; *tmp != NULL; tmp++) {
122 chanrec = silc_channel_find(server, *tmp);
127 key = strchr(channel, ' ');
132 tmpstr = g_string_new(NULL);
134 schannel = channel_setup_find(channel, server->connrec->chatnet);
135 if (key && *key != '\0')
136 g_string_sprintfa(tmpstr, "%s %s", channel, key);
137 else if (schannel && schannel->password && schannel->password[0] != '\0')
138 g_string_sprintfa(tmpstr, "%s %s", channel, schannel->password);
140 g_string_sprintfa(tmpstr, "%s", channel);
143 silc_command_exec(server, "JOIN", tmpstr->str);
144 g_string_free(tmpstr, FALSE);
150 static void sig_connected(SILC_SERVER_REC *server)
152 if (IS_SILC_SERVER(server))
153 server->channels_join = (void *) silc_channels_join;
156 /* "server quit" signal from the core to indicate that QUIT command
159 static void sig_server_quit(SILC_SERVER_REC *server, const char *msg)
161 if (IS_SILC_SERVER(server) && server->conn)
162 silc_command_exec(server, "QUIT", msg);
165 static void sig_silc_channel_joined(SILC_CHANNEL_REC *channel)
167 CHANNEL_SETUP_REC *rec;
169 if (!IS_SILC_CHANNEL(channel))
171 if (channel->server && channel->server->disconnected)
173 if (!channel->server)
175 if (channel->session_rejoin)
178 rec = channel_setup_find(channel->name, channel->server->connrec->chatnet);
180 if (rec == NULL || rec->autosendcmd == NULL || !*rec->autosendcmd)
183 eval_special_string(rec->autosendcmd, "", (SERVER_REC*)channel->server, (CHANNEL_REC*)channel);
186 /* Find Irssi channel entry by SILC channel entry */
188 SILC_CHANNEL_REC *silc_channel_find_entry(SILC_SERVER_REC *server,
189 SilcChannelEntry entry)
193 g_return_val_if_fail(IS_SILC_SERVER(server), NULL);
195 for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
196 SILC_CHANNEL_REC *rec = tmp->data;
198 if (rec->entry == entry)
205 /* PART (LEAVE) command. */
207 static void command_part(const char *data, SILC_SERVER_REC *server,
210 SILC_CHANNEL_REC *chanrec;
213 CMD_SILC_SERVER(server);
215 if (!IS_SILC_SERVER(server) || !server->connected)
216 cmd_return_error(CMDERR_NOT_CONNECTED);
218 if (!strcmp(data, "*") || *data == '\0') {
219 if (!IS_SILC_CHANNEL(item))
220 cmd_return_error(CMDERR_NOT_JOINED);
221 data = item->visible_name;
224 chanrec = silc_channel_find(server, data);
226 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
228 memset(userhost, 0, sizeof(userhost));
229 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
230 server->conn->local_entry->username,
231 server->conn->local_entry->hostname);
232 signal_emit("message part", 5, server, chanrec->name,
233 server->nick, userhost, "");
235 chanrec->left = TRUE;
236 silc_command_exec(server, "LEAVE", chanrec->name);
237 /* enable queueing because we destroy the channel immedially */
238 silc_queue_enable(server->conn);
241 channel_destroy(CHANNEL(chanrec));
245 /* ACTION local command. */
247 static void command_action(const char *data, SILC_SERVER_REC *server,
252 char *message = NULL;
255 SilcBool sign = FALSE;
257 CMD_SILC_SERVER(server);
258 if (!IS_SILC_SERVER(server) || !server->connected)
259 cmd_return_error(CMDERR_NOT_CONNECTED);
261 if ((item != NULL) && (!IS_SILC_CHANNEL(item) && !IS_SILC_QUERY(item)))
262 cmd_return_error(CMDERR_NOT_JOINED);
264 /* Now parse all arguments */
265 if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS |
267 "action", &optlist, &target, &msg))
270 if (*target == '\0' || *msg == '\0')
271 cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
273 if (strcmp(target, "*") == 0) {
274 /* send to active channel/query */
276 cmd_param_error(CMDERR_NOT_JOINED);
278 target_type = IS_SILC_CHANNEL(item) ?
279 SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
280 target = (char *)window_item_get_target(item);
281 } else if (g_hash_table_lookup(optlist, "channel") != NULL)
282 target_type = SEND_TARGET_CHANNEL;
284 target_type = SEND_TARGET_NICK;
287 if (!silc_term_utf8()) {
288 int len = silc_utf8_encoded_len(msg, strlen(msg),
290 message = silc_calloc(len + 1, sizeof(*message));
291 g_return_if_fail(message != NULL);
292 silc_utf8_encode(msg, strlen(msg), SILC_STRING_LOCALE,
296 if (target != NULL) {
297 if (target_type == SEND_TARGET_CHANNEL) {
298 sign = (g_hash_table_lookup(optlist, "sign") ? TRUE :
299 settings_get_bool("sign_channel_messages") ? TRUE : FALSE);
300 if (silc_send_channel(server, target, (message != NULL ? message : msg),
301 SILC_MESSAGE_FLAG_ACTION | SILC_MESSAGE_FLAG_UTF8 |
302 (sign ? SILC_MESSAGE_FLAG_SIGNED : 0))) {
303 if (g_hash_table_lookup(optlist, "sign"))
304 signal_emit("message silc signed_own_action", 3, server, msg, target);
306 signal_emit("message silc own_action", 3, server, msg, target);
309 sign = (g_hash_table_lookup(optlist, "sign") ? TRUE :
310 settings_get_bool("sign_private_messages") ? TRUE : FALSE);
311 if (silc_send_msg(server, target, (message != NULL ? message : msg),
312 (message != NULL ? strlen(message) : strlen(msg)),
313 SILC_MESSAGE_FLAG_ACTION | SILC_MESSAGE_FLAG_UTF8 |
314 (sign ? SILC_MESSAGE_FLAG_SIGNED : 0))) {
315 if (g_hash_table_lookup(optlist, "sign"))
316 signal_emit("message silc signed_own_private_action", 3,
317 server, msg, target);
319 signal_emit("message silc own_private_action", 3,
320 server, msg, target);
325 cmd_params_free(free_arg);
329 /* ME local command. */
331 static void command_me(const char *data, SILC_SERVER_REC *server,
336 CMD_SILC_SERVER(server);
337 if (!IS_SILC_SERVER(server) || !server->connected)
338 cmd_return_error(CMDERR_NOT_CONNECTED);
340 if (!IS_SILC_CHANNEL(item) && !IS_SILC_QUERY(item))
341 cmd_return_error(CMDERR_NOT_JOINED);
343 if (IS_SILC_CHANNEL(item))
344 tmpcmd = g_strdup_printf("-channel %s %s", item->visible_name, data);
346 tmpcmd = g_strdup_printf("%s %s", item->visible_name, data);
348 command_action(tmpcmd, server, item);
352 /* NOTICE local command. */
354 static void command_notice(const char *data, SILC_SERVER_REC *server,
359 char *message = NULL;
364 CMD_SILC_SERVER(server);
365 if (!IS_SILC_SERVER(server) || !server->connected)
366 cmd_return_error(CMDERR_NOT_CONNECTED);
368 if ((item != NULL) && (!IS_SILC_CHANNEL(item) && !IS_SILC_QUERY(item)))
369 cmd_return_error(CMDERR_NOT_JOINED);
371 /* Now parse all arguments */
372 if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS |
374 "notice", &optlist, &target, &msg))
377 if (*target == '\0' || *msg == '\0')
378 cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
380 if (strcmp(target, "*") == 0) {
381 /* send to active channel/query */
383 cmd_param_error(CMDERR_NOT_JOINED);
385 target_type = IS_SILC_CHANNEL(item) ?
386 SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
387 target = (char *)window_item_get_target(item);
388 } else if (g_hash_table_lookup(optlist, "channel") != NULL)
389 target_type = SEND_TARGET_CHANNEL;
391 target_type = SEND_TARGET_NICK;
394 if (!silc_term_utf8()) {
395 int len = silc_utf8_encoded_len(msg, strlen(msg),
397 message = silc_calloc(len + 1, sizeof(*message));
398 g_return_if_fail(message != NULL);
399 silc_utf8_encode(msg, strlen(msg), SILC_STRING_LOCALE,
403 if (target != NULL) {
404 if (target_type == SEND_TARGET_CHANNEL) {
405 sign = (g_hash_table_lookup(optlist, "sign") ? TRUE :
406 settings_get_bool("sign_channel_messages") ? TRUE : FALSE);
407 if (silc_send_channel(server, target, (message != NULL ? message : msg),
408 SILC_MESSAGE_FLAG_NOTICE | SILC_MESSAGE_FLAG_UTF8 |
409 (sign ? SILC_MESSAGE_FLAG_SIGNED : 0))) {
410 if (g_hash_table_lookup(optlist, "sign"))
411 signal_emit("message silc signed_own_notice", 3, server, msg, target);
413 signal_emit("message silc own_notice", 3, server, msg, target);
416 sign = (g_hash_table_lookup(optlist, "sign") ? TRUE :
417 settings_get_bool("sign_private_messages") ? TRUE : FALSE);
418 if (silc_send_msg(server, target, (message != NULL ? message : msg),
419 (message != NULL ? strlen(message) : strlen(msg)),
420 SILC_MESSAGE_FLAG_NOTICE | SILC_MESSAGE_FLAG_UTF8 |
421 (sign ? SILC_MESSAGE_FLAG_SIGNED : 0))) {
422 if (g_hash_table_lookup(optlist, "sign"))
423 signal_emit("message silc signed_own_private_notice", 3,
424 server, msg, target);
426 signal_emit("message silc own_private_notice", 3,
427 server, msg, target);
432 cmd_params_free(free_arg);
436 /* AWAY local command. Sends UMODE command that sets the SILC_UMODE_GONE
439 bool silc_set_away(const char *reason, SILC_SERVER_REC *server)
443 if (!IS_SILC_SERVER(server) || !server->connected)
446 if (*reason == '\0') {
447 /* Remove any possible away message */
448 silc_client_set_away_message(silc_client, server->conn, NULL);
451 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
454 /* Set the away message */
455 silc_client_set_away_message(silc_client, server->conn, (char *)reason);
458 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
459 SILCTXT_SET_AWAY, reason);
462 server->usermode_away = set;
463 g_free_and_null(server->away_reason);
465 server->away_reason = g_strdup((char *)reason);
467 signal_emit("away mode changed", 1, server);
472 static void command_away(const char *data, SILC_SERVER_REC *server,
475 CMD_SILC_SERVER(server);
477 if (!IS_SILC_SERVER(server) || !server->connected)
478 cmd_return_error(CMDERR_NOT_CONNECTED);
480 g_free_and_null(server->away_reason);
481 if ((data) && (*data != '\0'))
482 server->away_reason = g_strdup(data);
484 silc_command_exec(server, "UMODE",
485 (server->away_reason != NULL) ? "+g" : "-g");
489 SILC_SERVER_REC *server;
490 int type; /* 1 = msg, 2 = channel */
494 /* Key agreement callback that is called after the key agreement protocol
495 has been performed. This is called also if error occured during the
496 key agreement protocol. The `key' is the allocated key material and
497 the caller is responsible of freeing it. The `key' is NULL if error
498 has occured. The application can freely use the `key' to whatever
499 purpose it needs. See lib/silcske/silcske.h for the definition of
500 the SilcSKEKeyMaterial structure. */
502 static void keyagr_completion(SilcClient client,
503 SilcClientConnection conn,
504 SilcClientEntry client_entry,
505 SilcKeyAgreementStatus status,
506 SilcSKEKeyMaterial key,
509 KeyInternal i = (KeyInternal)context;
512 case SILC_KEY_AGREEMENT_OK:
513 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
514 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
517 /* Set the private key for this client */
518 silc_client_del_private_message_key(client, conn, client_entry);
519 silc_client_add_private_message_key_ske(client, conn, client_entry,
521 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
522 SILCTXT_KEY_AGREEMENT_PRIVMSG,
523 client_entry->nickname);
524 silc_ske_free_key_material(key);
529 case SILC_KEY_AGREEMENT_ERROR:
530 case SILC_KEY_AGREEMENT_NO_MEMORY:
531 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
532 SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
535 case SILC_KEY_AGREEMENT_FAILURE:
536 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
537 SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
540 case SILC_KEY_AGREEMENT_TIMEOUT:
541 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
542 SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
545 case SILC_KEY_AGREEMENT_ABORTED:
546 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
547 SILCTXT_KEY_AGREEMENT_ABORTED, client_entry->nickname);
550 case SILC_KEY_AGREEMENT_ALREADY_STARTED:
551 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
552 SILCTXT_KEY_AGREEMENT_ALREADY_STARTED,
553 client_entry->nickname);
556 case SILC_KEY_AGREEMENT_SELF_DENIED:
557 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
558 SILCTXT_KEY_AGREEMENT_SELF_DENIED);
569 /* Local command KEY. This command is used to set and unset private
570 keys for channels, set and unset private keys for private messages
571 with remote clients and to send key agreement requests and
572 negotiate the key agreement protocol with remote client. The
573 key agreement is supported only to negotiate private message keys,
574 it currently cannot be used to negotiate private keys for channels,
575 as it is not convenient for that purpose. */
578 SILC_SERVER_REC *server;
584 /* Callback to be called after client information is resolved from the
587 static void silc_client_command_key_get_clients(SilcClient client,
588 SilcClientConnection conn,
593 KeyGetClients internal = (KeyGetClients)context;
596 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s",
598 silc_free(internal->data);
599 silc_free(internal->nick);
604 signal_emit("command key", 3, internal->data, internal->server,
607 silc_free(internal->data);
608 silc_free(internal->nick);
612 static void command_key(const char *data, SILC_SERVER_REC *server,
615 SilcClientConnection conn;
616 SilcClientEntry client_entry = NULL;
618 SILC_CHANNEL_REC *chanrec = NULL;
619 SilcChannelEntry channel_entry = NULL;
620 char *nickname = NULL, *tmp;
621 int command = 0, port = 0, type = 0;
622 char *hostname = NULL;
623 KeyInternal internal = NULL;
625 unsigned char **argv;
626 SilcUInt32 *argv_lens, *argv_types;
627 char *bindhost = NULL;
628 SilcChannelPrivateKey ch = NULL;
630 SilcBool udp = FALSE;
633 CMD_SILC_SERVER(server);
635 if (!server || !IS_SILC_SERVER(server) || !server->connected)
636 cmd_return_error(CMDERR_NOT_CONNECTED);
640 /* Now parse all arguments */
641 tmp = g_strconcat("KEY", " ", data, NULL);
642 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
646 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
649 if (!strcasecmp(argv[1], "msg"))
651 if (!strcasecmp(argv[1], "channel"))
655 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
658 if (argv[2][0] == '*') {
659 nickname = strdup("*");
661 /* Parse the typed nickname. */
662 silc_client_nickname_parse(silc_client, conn, argv[2], &nickname);
664 nickname = strdup(argv[2]);
666 /* Find client entry */
667 clients = silc_client_get_clients_local(silc_client, conn, argv[2],
670 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
671 inter->server = server;
672 inter->data = strdup(data);
673 inter->nick = strdup(nickname);
675 silc_client_get_clients(silc_client, conn, nickname, NULL,
676 silc_client_command_key_get_clients, inter);
680 client_entry = silc_dlist_get(clients);
681 silc_client_list_free(silc_client, conn, clients);
686 /* Get channel entry */
689 if (argv[2][0] == '*') {
690 if (!conn->current_channel)
691 cmd_return_error(CMDERR_NOT_JOINED);
692 name = conn->current_channel->channel_name;
697 chanrec = silc_channel_find(server, name);
699 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
700 channel_entry = chanrec->entry;
704 if (!strcasecmp(argv[3], "set")) {
708 char *cipher = NULL, *hmac = NULL;
715 if (type == 1 && client_entry) {
716 /* Set private message key */
717 silc_client_del_private_message_key(silc_client, conn, client_entry);
718 silc_client_add_private_message_key(silc_client, conn, client_entry,
720 argv[4], argv_lens[4]);
721 } else if (type == 2) {
722 /* Set private channel key */
723 if (!(channel_entry) || !(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
724 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
725 SILCTXT_CH_PRIVATE_KEY_NOMODE,
726 channel_entry->channel_name);
730 if (!silc_client_add_channel_private_key(silc_client, conn,
734 argv_lens[4], NULL)) {
735 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
736 SILCTXT_CH_PRIVATE_KEY_ERROR,
737 channel_entry->channel_name);
741 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
742 SILCTXT_CH_PRIVATE_KEY_ADD,
743 channel_entry->channel_name);
751 if (!strcasecmp(argv[3], "unset")) {
754 if (type == 1 && client_entry) {
755 /* Unset private message key */
756 silc_client_del_private_message_key(silc_client, conn, client_entry);
757 } else if (type == 2) {
758 /* Unset channel key(s) */
762 silc_client_del_channel_private_keys(silc_client, conn,
766 number = atoi(argv[4]);
767 ckeys = silc_client_list_channel_private_keys(silc_client, conn,
772 silc_dlist_start(ckeys);
773 if (!number || number > silc_dlist_count(ckeys)) {
774 silc_dlist_uninit(ckeys);
778 for (i = 0; i < number; i++)
779 ch = silc_dlist_get(ckeys);
783 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
785 silc_dlist_uninit(ckeys);
793 if (!strcasecmp(argv[3], "list")) {
797 SilcPrivateMessageKeys keys;
798 SilcUInt32 keys_count;
802 keys = silc_client_list_private_message_keys(silc_client, conn,
807 /* list the private message key(s) */
808 if (nickname[0] == '*') {
809 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
810 SILCTXT_PRIVATE_KEY_LIST);
811 for (k = 0; k < keys_count; k++) {
812 memset(buf, 0, sizeof(buf));
813 strncat(buf, " ", 2);
814 len = strlen(keys[k].client_entry->nickname);
815 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
817 for (i = 0; i < 30 - len; i++)
821 len = strlen(keys[k].cipher);
822 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
824 for (i = 0; i < 14 - len; i++)
829 strcat(buf, "<hidden>");
831 strcat(buf, "*generated*");
833 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
836 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
837 SILCTXT_PRIVATE_KEY_LIST_NICK,
838 client_entry->nickname);
839 for (k = 0; k < keys_count; k++) {
840 if (keys[k].client_entry != client_entry)
843 memset(buf, 0, sizeof(buf));
844 strncat(buf, " ", 2);
845 len = strlen(keys[k].client_entry->nickname);
846 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
848 for (i = 0; i < 30 - len; i++)
852 len = strlen(keys[k].cipher);
853 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
855 for (i = 0; i < 14 - len; i++)
860 strcat(buf, "<hidden>");
862 strcat(buf, "*generated*");
864 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
868 silc_client_free_private_message_keys(keys, keys_count);
870 } else if (type == 2) {
874 ckeys = silc_client_list_channel_private_keys(silc_client, conn,
877 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
878 SILCTXT_CH_PRIVATE_KEY_LIST,
879 channel_entry->channel_name);
884 silc_dlist_start(ckeys);
885 while ((ch = silc_dlist_get(ckeys))) {
886 memset(buf, 0, sizeof(buf));
887 strncat(buf, " ", 2);
889 len = strlen(silc_cipher_get_name(ch->send_key));
890 strncat(buf, silc_cipher_get_name(ch->send_key),
891 len > 16 ? 16 : len);
893 for (i = 0; i < 16 - len; i++)
897 len = strlen(silc_hmac_get_name(ch->hmac));
898 strncat(buf, silc_hmac_get_name(ch->hmac), len > 16 ? 16 : len);
900 for (i = 0; i < 16 - len; i++)
904 strcat(buf, "<hidden>");
906 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
909 silc_dlist_uninit(ckeys);
915 /* Send command is used to send key agreement */
916 if (!strcasecmp(argv[3], "agreement")) {
922 if (!strcasecmp(argv[5], "UDP"))
925 port = atoi(argv[5]);
930 internal = silc_calloc(1, sizeof(*internal));
931 internal->type = type;
932 internal->server = server;
935 if (settings_get_bool("use_auto_addr")) {
936 hostname = (char *)settings_get_str("auto_public_ip");
938 /* If the hostname isn't set, treat this case as if auto_public_ip
940 if ((hostname) && (*hostname == '\0')) {
943 bindhost = (char *)settings_get_str("auto_bind_ip");
945 /* if the bind_ip isn't set, but the public_ip IS, then assume then
946 public_ip is the same value as the bind_ip. */
947 if ((bindhost) && (*bindhost == '\0'))
949 port = settings_get_int("auto_bind_port");
951 } /* if use_auto_addr */
955 /* Start command is used to start key agreement (after receiving the
956 key_agreement client operation). */
957 if (!strcasecmp(argv[3], "negotiate")) {
963 if (!strcasecmp(argv[5], "UDP"))
966 port = atoi(argv[5]);
971 internal = silc_calloc(1, sizeof(*internal));
972 internal->type = type;
973 internal->server = server;
976 /* Change current channel private key */
977 if (!strcasecmp(argv[3], "change")) {
980 /* Unset channel key(s) */
983 ckeys = silc_client_list_channel_private_keys(silc_client, conn,
988 silc_dlist_start(ckeys);
991 if (chanrec->cur_key >= silc_dlist_count(ckeys))
992 chanrec->cur_key = 0;
996 number = atoi(argv[4]);
997 if (!number || number > silc_dlist_count(ckeys))
998 chanrec->cur_key = 0;
1000 chanrec->cur_key = number - 1;
1003 for (i = 0; i < chanrec->cur_key; i++)
1004 ch = silc_dlist_get(ckeys);
1008 /* Set the current channel private key */
1009 silc_client_current_channel_private_key(silc_client, conn,
1011 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1012 SILCTXT_CH_PRIVATE_KEY_CHANGE, i + 1,
1013 channel_entry->channel_name);
1015 silc_dlist_uninit(ckeys);
1021 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
1022 "Usage: /KEY msg|channel <nickname|channel> "
1023 "set|unset|agreement|negotiate [<arguments>]");
1027 if (command == 4 && client_entry) {
1028 SilcClientConnectionParams params;
1030 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1031 SILCTXT_KEY_AGREEMENT, argv[2]);
1032 internal->responder = TRUE;
1034 memset(¶ms, 0, sizeof(params));
1035 params.local_ip = hostname;
1036 params.bind_ip = bindhost;
1037 params.local_port = port;
1039 params.timeout_secs = settings_get_int("key_exchange_timeout_secs");
1041 silc_client_send_key_agreement(
1042 silc_client, conn, client_entry, ¶ms,
1043 irssi_pubkey, irssi_privkey,
1044 keyagr_completion, internal);
1046 silc_free(internal);
1050 if (command == 5 && client_entry && hostname) {
1051 SilcClientConnectionParams params;
1053 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1054 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
1055 internal->responder = FALSE;
1057 memset(¶ms, 0, sizeof(params));
1059 if (settings_get_bool("use_auto_addr")) {
1060 params.local_ip = (char *)settings_get_str("auto_public_ip");
1061 if ((params.local_ip) && (*params.local_ip == '\0')) {
1062 params.local_ip = silc_net_localip();
1064 params.bind_ip = (char *)settings_get_str("auto_bind_ip");
1065 if ((params.bind_ip) && (*params.bind_ip == '\0'))
1066 params.bind_ip = NULL;
1067 params.local_port = settings_get_int("auto_bind_port");
1070 if (!params.local_ip)
1071 params.local_ip = silc_net_localip();
1074 params.timeout_secs = settings_get_int("key_exchange_timeout_secs");
1076 silc_client_perform_key_agreement(silc_client, conn, client_entry, ¶ms,
1077 irssi_pubkey, irssi_privkey,
1078 hostname, port, keyagr_completion,
1084 silc_free(nickname);
1088 void silc_list_key(const char *pub_filename, int verbose)
1090 SilcPublicKey public_key;
1091 SilcPublicKeyIdentifier ident;
1092 SilcSILCPublicKey silc_pubkey;
1093 char *fingerprint, *babbleprint;
1096 SilcUInt32 key_len = 0;
1097 int is_server_key = (strstr(pub_filename, "serverkeys") != NULL);
1099 if (!silc_pkcs_load_public_key((char *)pub_filename, &public_key)) {
1100 printformat_module("fe-common/silc", NULL, NULL,
1101 MSGLEVEL_CRAP, SILCTXT_LISTKEY_LOADPUB,
1106 /* Print only SILC public keys */
1107 if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
1108 printformat_module("fe-common/silc", NULL, NULL,
1109 MSGLEVEL_CRAP, SILCTXT_LISTKEY_LOADPUB,
1114 silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
1115 ident = &silc_pubkey->identifier;
1117 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1120 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1121 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1122 key_len = silc_pkcs_public_key_get_len(public_key);
1124 printformat_module("fe-common/silc", NULL, NULL,
1125 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_FILE,
1129 printformat_module("fe-common/silc", NULL, NULL,
1130 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_ALG,
1131 silc_pkcs_get_name(public_key));
1132 if (key_len && verbose)
1133 printformat_module("fe-common/silc", NULL, NULL,
1134 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_BITS,
1135 (unsigned int)key_len);
1136 if (ident->version && verbose)
1137 printformat_module("fe-common/silc", NULL, NULL,
1138 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_VER,
1140 if (ident->realname && (!is_server_key || verbose))
1141 printformat_module("fe-common/silc", NULL, NULL,
1142 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_RN,
1144 if (ident->username && verbose)
1145 printformat_module("fe-common/silc", NULL, NULL,
1146 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_UN,
1148 if (ident->host && (is_server_key || verbose))
1149 printformat_module("fe-common/silc", NULL, NULL,
1150 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_HN,
1152 if (ident->email && verbose)
1153 printformat_module("fe-common/silc", NULL, NULL,
1154 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_EMAIL,
1156 if (ident->org && verbose)
1157 printformat_module("fe-common/silc", NULL, NULL,
1158 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_ORG,
1160 if (ident->country && verbose)
1161 printformat_module("fe-common/silc", NULL, NULL,
1162 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_C,
1166 printformat_module("fe-common/silc", NULL, NULL,
1167 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_FINGER,
1169 printformat_module("fe-common/silc", NULL, NULL,
1170 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_BABL,
1174 silc_free(fingerprint);
1175 silc_free(babbleprint);
1177 silc_pkcs_public_key_free(public_key);
1180 void silc_list_keys_in_dir(const char *dirname, const char *where)
1183 struct dirent *entry;
1185 dir = opendir(dirname);
1188 cmd_return_error(CMDERR_ERRNO);
1190 printformat_module("fe-common/silc", NULL, NULL,
1191 MSGLEVEL_CRAP, SILCTXT_LISTKEY_LIST,
1196 while ((entry = readdir(dir)) != NULL) {
1197 /* try to open everything that isn't a directory */
1201 snprintf(filename, sizeof(filename) - 1, "%s/%s", dirname, entry->d_name);
1202 if (!stat(filename, &buf) && S_ISREG(buf.st_mode))
1203 silc_list_key(filename, FALSE);
1209 void silc_list_file(const char *filename)
1215 snprintf(path, sizeof(path) - 1, "%s", filename);
1216 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1219 snprintf(path, sizeof(path) - 1, "%s/%s", get_irssi_dir(), filename);
1220 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1223 snprintf(path,sizeof(path) - 1, "%s/clientkeys/%s", get_irssi_dir(),
1225 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1228 snprintf(path,sizeof(path) - 1, "%s/serverkeys/%s", get_irssi_dir(),
1230 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1237 silc_list_key(path, TRUE);
1240 /* Lists locally saved client and server public keys. */
1241 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
1244 GHashTable *optlist;
1249 if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS |
1250 PARAM_FLAG_GETREST, "listkeys", &optlist,
1254 if (*filename != '\0') {
1256 silc_list_file(filename);
1259 int clients, servers;
1261 clients = (g_hash_table_lookup(optlist, "clients") != NULL);
1262 servers = (g_hash_table_lookup(optlist, "servers") != NULL);
1264 if (!(clients || servers))
1265 clients = servers = 1;
1268 snprintf(dirname, sizeof(dirname) - 1, "%s/serverkeys", get_irssi_dir());
1269 silc_list_keys_in_dir(dirname, "server");
1273 snprintf(dirname, sizeof(dirname) - 1, "%s/clientkeys", get_irssi_dir());
1274 silc_list_keys_in_dir(dirname, "client");
1277 cmd_params_free(free_arg);
1280 void silc_channels_init(void)
1282 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1283 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1284 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1285 signal_add("mime", (SIGNAL_FUNC) sig_mime);
1286 signal_add("channel joined", (SIGNAL_FUNC) sig_silc_channel_joined);
1288 command_bind_silc("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1289 command_bind_silc("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1290 command_bind_silc("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1291 command_bind_silc("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1292 command_bind_silc("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1293 command_bind_silc("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1294 command_bind("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
1296 command_set_options("listkeys", "clients servers");
1297 command_set_options("action", "sign channel");
1298 command_set_options("notice", "sign channel");
1300 silc_nicklist_init();
1303 void silc_channels_deinit(void)
1305 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1306 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1307 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1308 signal_remove("mime", (SIGNAL_FUNC) sig_mime);
1309 signal_remove("channel joined", (SIGNAL_FUNC) sig_silc_channel_joined);
1311 command_unbind("part", (SIGNAL_FUNC) command_part);
1312 command_unbind("me", (SIGNAL_FUNC) command_me);
1313 command_unbind("action", (SIGNAL_FUNC) command_action);
1314 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1315 command_unbind("away", (SIGNAL_FUNC) command_away);
1316 command_unbind("key", (SIGNAL_FUNC) command_key);
1317 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
1319 silc_nicklist_deinit();