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->session_rejoin)
176 rec = channel_setup_find(channel->name, channel->server->connrec->chatnet);
178 if (rec == NULL || rec->autosendcmd == NULL || !*rec->autosendcmd)
181 eval_special_string(rec->autosendcmd, "", (SERVER_REC*)channel->server, (CHANNEL_REC*)channel);
184 /* Find Irssi channel entry by SILC channel entry */
186 SILC_CHANNEL_REC *silc_channel_find_entry(SILC_SERVER_REC *server,
187 SilcChannelEntry entry)
191 g_return_val_if_fail(IS_SILC_SERVER(server), NULL);
193 for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
194 SILC_CHANNEL_REC *rec = tmp->data;
196 if (rec->entry == entry)
203 /* PART (LEAVE) command. */
205 static void command_part(const char *data, SILC_SERVER_REC *server,
208 SILC_CHANNEL_REC *chanrec;
211 CMD_SILC_SERVER(server);
213 if (!IS_SILC_SERVER(server) || !server->connected)
214 cmd_return_error(CMDERR_NOT_CONNECTED);
216 if (!strcmp(data, "*") || *data == '\0') {
217 if (!IS_SILC_CHANNEL(item))
218 cmd_return_error(CMDERR_NOT_JOINED);
219 data = item->visible_name;
222 chanrec = silc_channel_find(server, data);
224 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
226 memset(userhost, 0, sizeof(userhost));
227 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
228 server->conn->local_entry->username,
229 server->conn->local_entry->hostname);
230 signal_emit("message part", 5, server, chanrec->name,
231 server->nick, userhost, "");
233 chanrec->left = TRUE;
234 silc_command_exec(server, "LEAVE", chanrec->name);
235 /* enable queueing because we destroy the channel immedially */
236 silc_queue_enable(server->conn);
239 channel_destroy(CHANNEL(chanrec));
243 /* ACTION local command. */
245 static void command_action(const char *data, SILC_SERVER_REC *server,
250 char *message = NULL;
253 SilcBool sign = FALSE;
255 CMD_SILC_SERVER(server);
256 if (!IS_SILC_SERVER(server) || !server->connected)
257 cmd_return_error(CMDERR_NOT_CONNECTED);
259 if ((item != NULL) && (!IS_SILC_CHANNEL(item) && !IS_SILC_QUERY(item)))
260 cmd_return_error(CMDERR_NOT_JOINED);
262 /* Now parse all arguments */
263 if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS |
265 "action", &optlist, &target, &msg))
268 if (*target == '\0' || *msg == '\0')
269 cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
271 if (strcmp(target, "*") == 0) {
272 /* send to active channel/query */
274 cmd_param_error(CMDERR_NOT_JOINED);
276 target_type = IS_SILC_CHANNEL(item) ?
277 SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
278 target = (char *)window_item_get_target(item);
279 } else if (g_hash_table_lookup(optlist, "channel") != NULL)
280 target_type = SEND_TARGET_CHANNEL;
282 target_type = SEND_TARGET_NICK;
285 if (!silc_term_utf8()) {
286 int len = silc_utf8_encoded_len(msg, strlen(msg),
288 message = silc_calloc(len + 1, sizeof(*message));
289 g_return_if_fail(message != NULL);
290 silc_utf8_encode(msg, strlen(msg), SILC_STRING_LOCALE,
294 if (target != NULL) {
295 if (target_type == SEND_TARGET_CHANNEL) {
296 sign = (g_hash_table_lookup(optlist, "sign") ? TRUE :
297 settings_get_bool("sign_channel_messages") ? TRUE : FALSE);
298 if (silc_send_channel(server, target, (message != NULL ? message : msg),
299 SILC_MESSAGE_FLAG_ACTION | SILC_MESSAGE_FLAG_UTF8 |
300 (sign ? SILC_MESSAGE_FLAG_SIGNED : 0))) {
301 if (g_hash_table_lookup(optlist, "sign"))
302 signal_emit("message silc signed_own_action", 3, server, msg, target);
304 signal_emit("message silc own_action", 3, server, msg, target);
307 sign = (g_hash_table_lookup(optlist, "sign") ? TRUE :
308 settings_get_bool("sign_private_messages") ? TRUE : FALSE);
309 if (silc_send_msg(server, target, (message != NULL ? message : msg),
310 (message != NULL ? strlen(message) : strlen(msg)),
311 SILC_MESSAGE_FLAG_ACTION | SILC_MESSAGE_FLAG_UTF8 |
312 (sign ? SILC_MESSAGE_FLAG_SIGNED : 0))) {
313 if (g_hash_table_lookup(optlist, "sign"))
314 signal_emit("message silc signed_own_private_action", 3,
315 server, msg, target);
317 signal_emit("message silc own_private_action", 3,
318 server, msg, target);
323 cmd_params_free(free_arg);
327 /* ME local command. */
329 static void command_me(const char *data, SILC_SERVER_REC *server,
334 CMD_SILC_SERVER(server);
335 if (!IS_SILC_SERVER(server) || !server->connected)
336 cmd_return_error(CMDERR_NOT_CONNECTED);
338 if (!IS_SILC_CHANNEL(item) && !IS_SILC_QUERY(item))
339 cmd_return_error(CMDERR_NOT_JOINED);
341 if (IS_SILC_CHANNEL(item))
342 tmpcmd = g_strdup_printf("-channel %s %s", item->visible_name, data);
344 tmpcmd = g_strdup_printf("%s %s", item->visible_name, data);
346 command_action(tmpcmd, server, item);
350 /* NOTICE local command. */
352 static void command_notice(const char *data, SILC_SERVER_REC *server,
357 char *message = NULL;
362 CMD_SILC_SERVER(server);
363 if (!IS_SILC_SERVER(server) || !server->connected)
364 cmd_return_error(CMDERR_NOT_CONNECTED);
366 if ((item != NULL) && (!IS_SILC_CHANNEL(item) && !IS_SILC_QUERY(item)))
367 cmd_return_error(CMDERR_NOT_JOINED);
369 /* Now parse all arguments */
370 if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS |
372 "notice", &optlist, &target, &msg))
375 if (*target == '\0' || *msg == '\0')
376 cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
378 if (strcmp(target, "*") == 0) {
379 /* send to active channel/query */
381 cmd_param_error(CMDERR_NOT_JOINED);
383 target_type = IS_SILC_CHANNEL(item) ?
384 SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
385 target = (char *)window_item_get_target(item);
386 } else if (g_hash_table_lookup(optlist, "channel") != NULL)
387 target_type = SEND_TARGET_CHANNEL;
389 target_type = SEND_TARGET_NICK;
392 if (!silc_term_utf8()) {
393 int len = silc_utf8_encoded_len(msg, strlen(msg),
395 message = silc_calloc(len + 1, sizeof(*message));
396 g_return_if_fail(message != NULL);
397 silc_utf8_encode(msg, strlen(msg), SILC_STRING_LOCALE,
401 if (target != NULL) {
402 if (target_type == SEND_TARGET_CHANNEL) {
403 sign = (g_hash_table_lookup(optlist, "sign") ? TRUE :
404 settings_get_bool("sign_channel_messages") ? TRUE : FALSE);
405 if (silc_send_channel(server, target, (message != NULL ? message : msg),
406 SILC_MESSAGE_FLAG_NOTICE | SILC_MESSAGE_FLAG_UTF8 |
407 (sign ? SILC_MESSAGE_FLAG_SIGNED : 0))) {
408 if (g_hash_table_lookup(optlist, "sign"))
409 signal_emit("message silc signed_own_notice", 3, server, msg, target);
411 signal_emit("message silc own_notice", 3, server, msg, target);
414 sign = (g_hash_table_lookup(optlist, "sign") ? TRUE :
415 settings_get_bool("sign_private_messages") ? TRUE : FALSE);
416 if (silc_send_msg(server, target, (message != NULL ? message : msg),
417 (message != NULL ? strlen(message) : strlen(msg)),
418 SILC_MESSAGE_FLAG_NOTICE | SILC_MESSAGE_FLAG_UTF8 |
419 (sign ? SILC_MESSAGE_FLAG_SIGNED : 0))) {
420 if (g_hash_table_lookup(optlist, "sign"))
421 signal_emit("message silc signed_own_private_notice", 3,
422 server, msg, target);
424 signal_emit("message silc own_private_notice", 3,
425 server, msg, target);
430 cmd_params_free(free_arg);
434 /* AWAY local command. Sends UMODE command that sets the SILC_UMODE_GONE
437 bool silc_set_away(const char *reason, SILC_SERVER_REC *server)
441 if (!IS_SILC_SERVER(server) || !server->connected)
444 if (*reason == '\0') {
445 /* Remove any possible away message */
446 silc_client_set_away_message(silc_client, server->conn, NULL);
449 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
452 /* Set the away message */
453 silc_client_set_away_message(silc_client, server->conn, (char *)reason);
456 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
457 SILCTXT_SET_AWAY, reason);
460 server->usermode_away = set;
461 g_free_and_null(server->away_reason);
463 server->away_reason = g_strdup((char *)reason);
465 signal_emit("away mode changed", 1, server);
470 static void command_away(const char *data, SILC_SERVER_REC *server,
473 CMD_SILC_SERVER(server);
475 if (!IS_SILC_SERVER(server) || !server->connected)
476 cmd_return_error(CMDERR_NOT_CONNECTED);
478 g_free_and_null(server->away_reason);
479 if ((data) && (*data != '\0'))
480 server->away_reason = g_strdup(data);
482 silc_command_exec(server, "UMODE",
483 (server->away_reason != NULL) ? "+g" : "-g");
487 SILC_SERVER_REC *server;
488 int type; /* 1 = msg, 2 = channel */
492 /* Key agreement callback that is called after the key agreement protocol
493 has been performed. This is called also if error occured during the
494 key agreement protocol. The `key' is the allocated key material and
495 the caller is responsible of freeing it. The `key' is NULL if error
496 has occured. The application can freely use the `key' to whatever
497 purpose it needs. See lib/silcske/silcske.h for the definition of
498 the SilcSKEKeyMaterial structure. */
500 static void keyagr_completion(SilcClient client,
501 SilcClientConnection conn,
502 SilcClientEntry client_entry,
503 SilcKeyAgreementStatus status,
504 SilcSKEKeyMaterial key,
507 KeyInternal i = (KeyInternal)context;
510 case SILC_KEY_AGREEMENT_OK:
511 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
512 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
515 /* Set the private key for this client */
516 silc_client_del_private_message_key(client, conn, client_entry);
517 silc_client_add_private_message_key_ske(client, conn, client_entry,
519 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
520 SILCTXT_KEY_AGREEMENT_PRIVMSG,
521 client_entry->nickname);
522 silc_ske_free_key_material(key);
527 case SILC_KEY_AGREEMENT_ERROR:
528 case SILC_KEY_AGREEMENT_NO_MEMORY:
529 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
530 SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
533 case SILC_KEY_AGREEMENT_FAILURE:
534 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
535 SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
538 case SILC_KEY_AGREEMENT_TIMEOUT:
539 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
540 SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
543 case SILC_KEY_AGREEMENT_ABORTED:
544 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
545 SILCTXT_KEY_AGREEMENT_ABORTED, client_entry->nickname);
548 case SILC_KEY_AGREEMENT_ALREADY_STARTED:
549 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
550 SILCTXT_KEY_AGREEMENT_ALREADY_STARTED,
551 client_entry->nickname);
554 case SILC_KEY_AGREEMENT_SELF_DENIED:
555 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
556 SILCTXT_KEY_AGREEMENT_SELF_DENIED);
567 /* Local command KEY. This command is used to set and unset private
568 keys for channels, set and unset private keys for private messages
569 with remote clients and to send key agreement requests and
570 negotiate the key agreement protocol with remote client. The
571 key agreement is supported only to negotiate private message keys,
572 it currently cannot be used to negotiate private keys for channels,
573 as it is not convenient for that purpose. */
576 SILC_SERVER_REC *server;
582 /* Callback to be called after client information is resolved from the
585 static void silc_client_command_key_get_clients(SilcClient client,
586 SilcClientConnection conn,
591 KeyGetClients internal = (KeyGetClients)context;
594 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s",
596 silc_free(internal->data);
597 silc_free(internal->nick);
602 signal_emit("command key", 3, internal->data, internal->server,
605 silc_free(internal->data);
606 silc_free(internal->nick);
610 static void command_key(const char *data, SILC_SERVER_REC *server,
613 SilcClientConnection conn;
614 SilcClientEntry client_entry = NULL;
616 SILC_CHANNEL_REC *chanrec = NULL;
617 SilcChannelEntry channel_entry = NULL;
618 char *nickname = NULL, *tmp;
619 int command = 0, port = 0, type = 0;
620 char *hostname = NULL;
621 KeyInternal internal = NULL;
623 unsigned char **argv;
624 SilcUInt32 *argv_lens, *argv_types;
625 char *bindhost = NULL;
626 SilcChannelPrivateKey ch = NULL;
628 SilcBool udp = FALSE;
631 CMD_SILC_SERVER(server);
633 if (!server || !IS_SILC_SERVER(server) || !server->connected)
634 cmd_return_error(CMDERR_NOT_CONNECTED);
638 /* Now parse all arguments */
639 tmp = g_strconcat("KEY", " ", data, NULL);
640 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
644 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
647 if (!strcasecmp(argv[1], "msg"))
649 if (!strcasecmp(argv[1], "channel"))
653 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
656 if (argv[2][0] == '*') {
657 nickname = strdup("*");
659 /* Parse the typed nickname. */
660 silc_client_nickname_parse(silc_client, conn, argv[2], &nickname);
662 nickname = strdup(argv[2]);
664 /* Find client entry */
665 clients = silc_client_get_clients_local(silc_client, conn, argv[2],
668 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
669 inter->server = server;
670 inter->data = strdup(data);
671 inter->nick = strdup(nickname);
673 silc_client_get_clients(silc_client, conn, nickname, NULL,
674 silc_client_command_key_get_clients, inter);
678 client_entry = silc_dlist_get(clients);
679 silc_client_list_free(silc_client, conn, clients);
684 /* Get channel entry */
687 if (argv[2][0] == '*') {
688 if (!conn->current_channel)
689 cmd_return_error(CMDERR_NOT_JOINED);
690 name = conn->current_channel->channel_name;
695 chanrec = silc_channel_find(server, name);
697 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
698 channel_entry = chanrec->entry;
702 if (!strcasecmp(argv[3], "set")) {
706 char *cipher = NULL, *hmac = NULL;
713 if (type == 1 && client_entry) {
714 /* Set private message key */
715 silc_client_del_private_message_key(silc_client, conn, client_entry);
716 silc_client_add_private_message_key(silc_client, conn, client_entry,
718 argv[4], argv_lens[4]);
719 } else if (type == 2) {
720 /* Set private channel key */
721 if (!(channel_entry) || !(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
722 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
723 SILCTXT_CH_PRIVATE_KEY_NOMODE,
724 channel_entry->channel_name);
728 if (!silc_client_add_channel_private_key(silc_client, conn,
732 argv_lens[4], NULL)) {
733 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
734 SILCTXT_CH_PRIVATE_KEY_ERROR,
735 channel_entry->channel_name);
739 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
740 SILCTXT_CH_PRIVATE_KEY_ADD,
741 channel_entry->channel_name);
749 if (!strcasecmp(argv[3], "unset")) {
752 if (type == 1 && client_entry) {
753 /* Unset private message key */
754 silc_client_del_private_message_key(silc_client, conn, client_entry);
755 } else if (type == 2) {
756 /* Unset channel key(s) */
760 silc_client_del_channel_private_keys(silc_client, conn,
764 number = atoi(argv[4]);
765 ckeys = silc_client_list_channel_private_keys(silc_client, conn,
770 silc_dlist_start(ckeys);
771 if (!number || number > silc_dlist_count(ckeys)) {
772 silc_dlist_uninit(ckeys);
776 for (i = 0; i < number; i++)
777 ch = silc_dlist_get(ckeys);
781 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
783 silc_dlist_uninit(ckeys);
791 if (!strcasecmp(argv[3], "list")) {
795 SilcPrivateMessageKeys keys;
796 SilcUInt32 keys_count;
800 keys = silc_client_list_private_message_keys(silc_client, conn,
805 /* list the private message key(s) */
806 if (nickname[0] == '*') {
807 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
808 SILCTXT_PRIVATE_KEY_LIST);
809 for (k = 0; k < keys_count; k++) {
810 memset(buf, 0, sizeof(buf));
811 strncat(buf, " ", 2);
812 len = strlen(keys[k].client_entry->nickname);
813 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
815 for (i = 0; i < 30 - len; i++)
819 len = strlen(keys[k].cipher);
820 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
822 for (i = 0; i < 14 - len; i++)
827 strcat(buf, "<hidden>");
829 strcat(buf, "*generated*");
831 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
834 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
835 SILCTXT_PRIVATE_KEY_LIST_NICK,
836 client_entry->nickname);
837 for (k = 0; k < keys_count; k++) {
838 if (keys[k].client_entry != client_entry)
841 memset(buf, 0, sizeof(buf));
842 strncat(buf, " ", 2);
843 len = strlen(keys[k].client_entry->nickname);
844 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
846 for (i = 0; i < 30 - len; i++)
850 len = strlen(keys[k].cipher);
851 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
853 for (i = 0; i < 14 - len; i++)
858 strcat(buf, "<hidden>");
860 strcat(buf, "*generated*");
862 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
866 silc_client_free_private_message_keys(keys, keys_count);
868 } else if (type == 2) {
872 ckeys = silc_client_list_channel_private_keys(silc_client, conn,
875 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
876 SILCTXT_CH_PRIVATE_KEY_LIST,
877 channel_entry->channel_name);
882 silc_dlist_start(ckeys);
883 while ((ch = silc_dlist_get(ckeys))) {
884 memset(buf, 0, sizeof(buf));
885 strncat(buf, " ", 2);
887 len = strlen(silc_cipher_get_name(ch->send_key));
888 strncat(buf, silc_cipher_get_name(ch->send_key),
889 len > 16 ? 16 : len);
891 for (i = 0; i < 16 - len; i++)
895 len = strlen(silc_hmac_get_name(ch->hmac));
896 strncat(buf, silc_hmac_get_name(ch->hmac), len > 16 ? 16 : len);
898 for (i = 0; i < 16 - len; i++)
902 strcat(buf, "<hidden>");
904 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
907 silc_dlist_uninit(ckeys);
913 /* Send command is used to send key agreement */
914 if (!strcasecmp(argv[3], "agreement")) {
920 if (!strcasecmp(argv[5], "UDP"))
923 port = atoi(argv[5]);
928 internal = silc_calloc(1, sizeof(*internal));
929 internal->type = type;
930 internal->server = server;
933 if (settings_get_bool("use_auto_addr")) {
934 hostname = (char *)settings_get_str("auto_public_ip");
936 /* If the hostname isn't set, treat this case as if auto_public_ip
938 if ((hostname) && (*hostname == '\0')) {
941 bindhost = (char *)settings_get_str("auto_bind_ip");
943 /* if the bind_ip isn't set, but the public_ip IS, then assume then
944 public_ip is the same value as the bind_ip. */
945 if ((bindhost) && (*bindhost == '\0'))
947 port = settings_get_int("auto_bind_port");
949 } /* if use_auto_addr */
953 /* Start command is used to start key agreement (after receiving the
954 key_agreement client operation). */
955 if (!strcasecmp(argv[3], "negotiate")) {
961 if (!strcasecmp(argv[5], "UDP"))
964 port = atoi(argv[5]);
969 internal = silc_calloc(1, sizeof(*internal));
970 internal->type = type;
971 internal->server = server;
974 /* Change current channel private key */
975 if (!strcasecmp(argv[3], "change")) {
978 /* Unset channel key(s) */
981 ckeys = silc_client_list_channel_private_keys(silc_client, conn,
986 silc_dlist_start(ckeys);
989 if (chanrec->cur_key >= silc_dlist_count(ckeys))
990 chanrec->cur_key = 0;
994 number = atoi(argv[4]);
995 if (!number || number > silc_dlist_count(ckeys))
996 chanrec->cur_key = 0;
998 chanrec->cur_key = number - 1;
1001 for (i = 0; i < chanrec->cur_key; i++)
1002 ch = silc_dlist_get(ckeys);
1006 /* Set the current channel private key */
1007 silc_client_current_channel_private_key(silc_client, conn,
1009 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1010 SILCTXT_CH_PRIVATE_KEY_CHANGE, i + 1,
1011 channel_entry->channel_name);
1013 silc_dlist_uninit(ckeys);
1019 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
1020 "Usage: /KEY msg|channel <nickname|channel> "
1021 "set|unset|agreement|negotiate [<arguments>]");
1025 if (command == 4 && client_entry) {
1026 SilcClientConnectionParams params;
1028 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1029 SILCTXT_KEY_AGREEMENT, argv[2]);
1030 internal->responder = TRUE;
1032 memset(¶ms, 0, sizeof(params));
1033 params.local_ip = hostname;
1034 params.bind_ip = bindhost;
1035 params.local_port = port;
1037 params.timeout_secs = settings_get_int("key_exchange_timeout_secs");
1039 silc_client_send_key_agreement(
1040 silc_client, conn, client_entry, ¶ms,
1041 irssi_pubkey, irssi_privkey,
1042 keyagr_completion, internal);
1044 silc_free(internal);
1048 if (command == 5 && client_entry && hostname) {
1049 SilcClientConnectionParams params;
1051 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1052 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
1053 internal->responder = FALSE;
1055 memset(¶ms, 0, sizeof(params));
1057 if (settings_get_bool("use_auto_addr")) {
1058 params.local_ip = (char *)settings_get_str("auto_public_ip");
1059 if ((params.local_ip) && (*params.local_ip == '\0')) {
1060 params.local_ip = silc_net_localip();
1062 params.bind_ip = (char *)settings_get_str("auto_bind_ip");
1063 if ((params.bind_ip) && (*params.bind_ip == '\0'))
1064 params.bind_ip = NULL;
1065 params.local_port = settings_get_int("auto_bind_port");
1068 if (!params.local_ip)
1069 params.local_ip = silc_net_localip();
1072 params.timeout_secs = settings_get_int("key_exchange_timeout_secs");
1074 silc_client_perform_key_agreement(silc_client, conn, client_entry, ¶ms,
1075 irssi_pubkey, irssi_privkey,
1076 hostname, port, keyagr_completion,
1082 silc_free(nickname);
1086 void silc_list_key(const char *pub_filename, int verbose)
1088 SilcPublicKey public_key;
1089 SilcPublicKeyIdentifier ident;
1090 SilcSILCPublicKey silc_pubkey;
1091 char *fingerprint, *babbleprint;
1094 SilcUInt32 key_len = 0;
1095 int is_server_key = (strstr(pub_filename, "serverkeys") != NULL);
1097 if (!silc_pkcs_load_public_key((char *)pub_filename, &public_key)) {
1098 printformat_module("fe-common/silc", NULL, NULL,
1099 MSGLEVEL_CRAP, SILCTXT_LISTKEY_LOADPUB,
1104 /* Print only SILC public keys */
1105 if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
1106 printformat_module("fe-common/silc", NULL, NULL,
1107 MSGLEVEL_CRAP, SILCTXT_LISTKEY_LOADPUB,
1112 silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
1113 ident = &silc_pubkey->identifier;
1115 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1118 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1119 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1120 key_len = silc_pkcs_public_key_get_len(public_key);
1122 printformat_module("fe-common/silc", NULL, NULL,
1123 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_FILE,
1127 printformat_module("fe-common/silc", NULL, NULL,
1128 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_ALG,
1129 silc_pkcs_get_name(public_key));
1130 if (key_len && verbose)
1131 printformat_module("fe-common/silc", NULL, NULL,
1132 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_BITS,
1133 (unsigned int)key_len);
1134 if (ident->version && verbose)
1135 printformat_module("fe-common/silc", NULL, NULL,
1136 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_VER,
1138 if (ident->realname && (!is_server_key || verbose))
1139 printformat_module("fe-common/silc", NULL, NULL,
1140 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_RN,
1142 if (ident->username && verbose)
1143 printformat_module("fe-common/silc", NULL, NULL,
1144 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_UN,
1146 if (ident->host && (is_server_key || verbose))
1147 printformat_module("fe-common/silc", NULL, NULL,
1148 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_HN,
1150 if (ident->email && verbose)
1151 printformat_module("fe-common/silc", NULL, NULL,
1152 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_EMAIL,
1154 if (ident->org && verbose)
1155 printformat_module("fe-common/silc", NULL, NULL,
1156 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_ORG,
1158 if (ident->country && verbose)
1159 printformat_module("fe-common/silc", NULL, NULL,
1160 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_C,
1164 printformat_module("fe-common/silc", NULL, NULL,
1165 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_FINGER,
1167 printformat_module("fe-common/silc", NULL, NULL,
1168 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_BABL,
1172 silc_free(fingerprint);
1173 silc_free(babbleprint);
1175 silc_pkcs_public_key_free(public_key);
1178 void silc_list_keys_in_dir(const char *dirname, const char *where)
1181 struct dirent *entry;
1183 dir = opendir(dirname);
1186 cmd_return_error(CMDERR_ERRNO);
1188 printformat_module("fe-common/silc", NULL, NULL,
1189 MSGLEVEL_CRAP, SILCTXT_LISTKEY_LIST,
1194 while ((entry = readdir(dir)) != NULL) {
1195 /* try to open everything that isn't a directory */
1199 snprintf(filename, sizeof(filename) - 1, "%s/%s", dirname, entry->d_name);
1200 if (!stat(filename, &buf) && S_ISREG(buf.st_mode))
1201 silc_list_key(filename, FALSE);
1207 void silc_list_file(const char *filename)
1213 snprintf(path, sizeof(path) - 1, "%s", filename);
1214 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1217 snprintf(path, sizeof(path) - 1, "%s/%s", get_irssi_dir(), filename);
1218 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1221 snprintf(path,sizeof(path) - 1, "%s/clientkeys/%s", get_irssi_dir(),
1223 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1226 snprintf(path,sizeof(path) - 1, "%s/serverkeys/%s", get_irssi_dir(),
1228 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1235 silc_list_key(path, TRUE);
1238 /* Lists locally saved client and server public keys. */
1239 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
1242 GHashTable *optlist;
1247 if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS |
1248 PARAM_FLAG_GETREST, "listkeys", &optlist,
1252 if (*filename != '\0') {
1254 silc_list_file(filename);
1257 int clients, servers;
1259 clients = (g_hash_table_lookup(optlist, "clients") != NULL);
1260 servers = (g_hash_table_lookup(optlist, "servers") != NULL);
1262 if (!(clients || servers))
1263 clients = servers = 1;
1266 snprintf(dirname, sizeof(dirname) - 1, "%s/serverkeys", get_irssi_dir());
1267 silc_list_keys_in_dir(dirname, "server");
1271 snprintf(dirname, sizeof(dirname) - 1, "%s/clientkeys", get_irssi_dir());
1272 silc_list_keys_in_dir(dirname, "client");
1275 cmd_params_free(free_arg);
1278 void silc_channels_init(void)
1280 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1281 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1282 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1283 signal_add("mime", (SIGNAL_FUNC) sig_mime);
1284 signal_add("channel joined", (SIGNAL_FUNC) sig_silc_channel_joined);
1286 command_bind_silc("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1287 command_bind_silc("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1288 command_bind_silc("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1289 command_bind_silc("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1290 command_bind_silc("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1291 command_bind_silc("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1292 command_bind("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
1294 command_set_options("listkeys", "clients servers");
1295 command_set_options("action", "sign channel");
1296 command_set_options("notice", "sign channel");
1298 silc_nicklist_init();
1301 void silc_channels_deinit(void)
1303 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1304 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1305 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1306 signal_remove("mime", (SIGNAL_FUNC) sig_mime);
1307 signal_remove("channel joined", (SIGNAL_FUNC) sig_silc_channel_joined);
1309 command_unbind("part", (SIGNAL_FUNC) command_part);
1310 command_unbind("me", (SIGNAL_FUNC) command_me);
1311 command_unbind("action", (SIGNAL_FUNC) command_action);
1312 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1313 command_unbind("away", (SIGNAL_FUNC) command_away);
1314 command_unbind("key", (SIGNAL_FUNC) command_key);
1315 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
1317 silc_nicklist_deinit();