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"
35 #include "channels-setup.h"
37 #include "silc-servers.h"
38 #include "silc-channels.h"
39 #include "silc-queries.h"
40 #include "silc-nicklist.h"
41 #include "silc-cmdqueue.h"
42 #include "window-item-def.h"
44 #include "fe-common/core/printtext.h"
45 #include "fe-common/silc/module-formats.h"
47 #include "silc-commands.h"
49 void sig_mime(SILC_SERVER_REC *server, SILC_CHANNEL_REC *channel,
50 const char *blob, const char *nick, int verified)
52 unsigned char *message;
53 SilcUInt32 message_len;
56 if (!(IS_SILC_SERVER(server)))
59 message = silc_unescape_data(blob, &message_len);
61 mime = silc_mime_decode(NULL, message, message_len);
67 printformat_module("fe-common/silc", server,
68 channel == NULL ? NULL : channel->name,
69 MSGLEVEL_CRAP, SILCTXT_MESSAGE_DATA,
70 nick == NULL ? "[<unknown>]" : nick,
71 silc_mime_get_field(mime, "Content-Type"));
77 SILC_CHANNEL_REC *silc_channel_create(SILC_SERVER_REC *server,
79 const char *visible_name,
82 SILC_CHANNEL_REC *rec;
84 g_return_val_if_fail(server == NULL || IS_SILC_SERVER(server), NULL);
85 g_return_val_if_fail(name != NULL, NULL);
87 rec = g_new0(SILC_CHANNEL_REC, 1);
88 rec->chat_type = SILC_PROTOCOL;
89 channel_init((CHANNEL_REC *)rec, (SERVER_REC *)server, name, name,
94 static void sig_channel_destroyed(SILC_CHANNEL_REC *channel)
96 if (!IS_SILC_CHANNEL(channel))
98 if (channel->server && channel->server->disconnected)
101 if (channel->server != NULL && !channel->left && !channel->kicked) {
102 /* destroying channel record without actually
103 having left the channel yet */
104 silc_command_exec(channel->server, "LEAVE", channel->name);
105 /* enable queueing because we destroy the channel immedially */
106 silc_queue_enable(channel->server->conn);
110 static void silc_channels_join(SILC_SERVER_REC *server,
111 const char *channels, int automatic)
115 SILC_CHANNEL_REC *chanrec;
116 CHANNEL_SETUP_REC *schannel;
119 list = g_strsplit(channels, ",", -1);
120 for (tmp = list; *tmp != NULL; tmp++) {
121 chanrec = silc_channel_find(server, *tmp);
126 key = strchr(channel, ' ');
131 tmpstr = g_string_new(NULL);
133 schannel = channel_setup_find(channel, server->connrec->chatnet);
134 if (key && *key != '\0')
135 g_string_sprintfa(tmpstr, "%s %s", channel, key);
136 else if (schannel && schannel->password && schannel->password[0] != '\0')
137 g_string_sprintfa(tmpstr, "%s %s", channel, schannel->password);
139 g_string_sprintfa(tmpstr, "%s", channel);
142 silc_command_exec(server, "JOIN", tmpstr->str);
143 g_string_free(tmpstr, FALSE);
149 static void sig_connected(SILC_SERVER_REC *server)
151 if (IS_SILC_SERVER(server))
152 server->channels_join = (void *) silc_channels_join;
155 /* "server quit" signal from the core to indicate that QUIT command
158 static void sig_server_quit(SILC_SERVER_REC *server, const char *msg)
160 if (IS_SILC_SERVER(server) && server->conn)
161 silc_command_exec(server, "QUIT", msg);
164 /* Find Irssi channel entry by SILC channel entry */
166 SILC_CHANNEL_REC *silc_channel_find_entry(SILC_SERVER_REC *server,
167 SilcChannelEntry entry)
171 g_return_val_if_fail(IS_SILC_SERVER(server), NULL);
173 for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
174 SILC_CHANNEL_REC *rec = tmp->data;
176 if (rec->entry == entry)
183 /* PART (LEAVE) command. */
185 static void command_part(const char *data, SILC_SERVER_REC *server,
188 SILC_CHANNEL_REC *chanrec;
191 CMD_SILC_SERVER(server);
193 if (!IS_SILC_SERVER(server) || !server->connected)
194 cmd_return_error(CMDERR_NOT_CONNECTED);
196 if (!strcmp(data, "*") || *data == '\0') {
197 if (!IS_SILC_CHANNEL(item))
198 cmd_return_error(CMDERR_NOT_JOINED);
199 data = item->visible_name;
202 chanrec = silc_channel_find(server, data);
204 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
206 memset(userhost, 0, sizeof(userhost));
207 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
208 server->conn->local_entry->username,
209 server->conn->local_entry->hostname);
210 signal_emit("message part", 5, server, chanrec->name,
211 server->nick, userhost, "");
213 chanrec->left = TRUE;
214 silc_command_exec(server, "LEAVE", chanrec->name);
215 /* enable queueing because we destroy the channel immedially */
216 silc_queue_enable(server->conn);
219 channel_destroy(CHANNEL(chanrec));
223 /* ACTION local command. */
225 static void command_action(const char *data, SILC_SERVER_REC *server,
230 char *message = NULL;
233 SilcBool sign = FALSE;
235 CMD_SILC_SERVER(server);
236 if (!IS_SILC_SERVER(server) || !server->connected)
237 cmd_return_error(CMDERR_NOT_CONNECTED);
239 if ((item != NULL) && (!IS_SILC_CHANNEL(item) && !IS_SILC_QUERY(item)))
240 cmd_return_error(CMDERR_NOT_JOINED);
242 /* Now parse all arguments */
243 if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS |
245 "action", &optlist, &target, &msg))
248 if (*target == '\0' || *msg == '\0')
249 cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
251 if (strcmp(target, "*") == 0) {
252 /* send to active channel/query */
254 cmd_param_error(CMDERR_NOT_JOINED);
256 target_type = IS_SILC_CHANNEL(item) ?
257 SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
258 target = (char *)window_item_get_target(item);
259 } else if (g_hash_table_lookup(optlist, "channel") != NULL)
260 target_type = SEND_TARGET_CHANNEL;
262 target_type = SEND_TARGET_NICK;
265 if (!silc_term_utf8()) {
266 int len = silc_utf8_encoded_len(msg, strlen(msg),
268 message = silc_calloc(len + 1, sizeof(*message));
269 g_return_if_fail(message != NULL);
270 silc_utf8_encode(msg, strlen(msg), SILC_STRING_LOCALE,
274 if (target != NULL) {
275 if (target_type == SEND_TARGET_CHANNEL) {
276 sign = (g_hash_table_lookup(optlist, "sign") ? TRUE :
277 settings_get_bool("sign_channel_messages") ? TRUE : FALSE);
278 if (silc_send_channel(server, target, (message != NULL ? message : msg),
279 SILC_MESSAGE_FLAG_ACTION | SILC_MESSAGE_FLAG_UTF8 |
280 (sign ? SILC_MESSAGE_FLAG_SIGNED : 0))) {
281 if (g_hash_table_lookup(optlist, "sign"))
282 signal_emit("message silc signed_own_action", 3, server, msg, target);
284 signal_emit("message silc own_action", 3, server, msg, target);
287 sign = (g_hash_table_lookup(optlist, "sign") ? TRUE :
288 settings_get_bool("sign_private_messages") ? TRUE : FALSE);
289 if (silc_send_msg(server, target, (message != NULL ? message : msg),
290 (message != NULL ? strlen(message) : strlen(msg)),
291 SILC_MESSAGE_FLAG_ACTION | SILC_MESSAGE_FLAG_UTF8 |
292 (sign ? SILC_MESSAGE_FLAG_SIGNED : 0))) {
293 if (g_hash_table_lookup(optlist, "sign"))
294 signal_emit("message silc signed_own_private_action", 3,
295 server, msg, target);
297 signal_emit("message silc own_private_action", 3,
298 server, msg, target);
303 cmd_params_free(free_arg);
307 /* ME local command. */
309 static void command_me(const char *data, SILC_SERVER_REC *server,
314 CMD_SILC_SERVER(server);
315 if (!IS_SILC_SERVER(server) || !server->connected)
316 cmd_return_error(CMDERR_NOT_CONNECTED);
318 if (!IS_SILC_CHANNEL(item) && !IS_SILC_QUERY(item))
319 cmd_return_error(CMDERR_NOT_JOINED);
321 if (IS_SILC_CHANNEL(item))
322 tmpcmd = g_strdup_printf("-channel %s %s", item->visible_name, data);
324 tmpcmd = g_strdup_printf("%s %s", item->visible_name, data);
326 command_action(tmpcmd, server, item);
330 /* NOTICE local command. */
332 static void command_notice(const char *data, SILC_SERVER_REC *server,
337 char *message = NULL;
342 CMD_SILC_SERVER(server);
343 if (!IS_SILC_SERVER(server) || !server->connected)
344 cmd_return_error(CMDERR_NOT_CONNECTED);
346 if ((item != NULL) && (!IS_SILC_CHANNEL(item) && !IS_SILC_QUERY(item)))
347 cmd_return_error(CMDERR_NOT_JOINED);
349 /* Now parse all arguments */
350 if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS |
352 "notice", &optlist, &target, &msg))
355 if (*target == '\0' || *msg == '\0')
356 cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
358 if (strcmp(target, "*") == 0) {
359 /* send to active channel/query */
361 cmd_param_error(CMDERR_NOT_JOINED);
363 target_type = IS_SILC_CHANNEL(item) ?
364 SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
365 target = (char *)window_item_get_target(item);
366 } else if (g_hash_table_lookup(optlist, "channel") != NULL)
367 target_type = SEND_TARGET_CHANNEL;
369 target_type = SEND_TARGET_NICK;
372 if (!silc_term_utf8()) {
373 int len = silc_utf8_encoded_len(msg, strlen(msg),
375 message = silc_calloc(len + 1, sizeof(*message));
376 g_return_if_fail(message != NULL);
377 silc_utf8_encode(msg, strlen(msg), SILC_STRING_LOCALE,
381 if (target != NULL) {
382 if (target_type == SEND_TARGET_CHANNEL) {
383 sign = (g_hash_table_lookup(optlist, "sign") ? TRUE :
384 settings_get_bool("sign_channel_messages") ? TRUE : FALSE);
385 if (silc_send_channel(server, target, (message != NULL ? message : msg),
386 SILC_MESSAGE_FLAG_NOTICE | SILC_MESSAGE_FLAG_UTF8 |
387 (sign ? SILC_MESSAGE_FLAG_SIGNED : 0))) {
388 if (g_hash_table_lookup(optlist, "sign"))
389 signal_emit("message silc signed_own_notice", 3, server, msg, target);
391 signal_emit("message silc own_notice", 3, server, msg, target);
394 sign = (g_hash_table_lookup(optlist, "sign") ? TRUE :
395 settings_get_bool("sign_private_messages") ? TRUE : FALSE);
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 (sign ? SILC_MESSAGE_FLAG_SIGNED : 0))) {
400 if (g_hash_table_lookup(optlist, "sign"))
401 signal_emit("message silc signed_own_private_notice", 3,
402 server, msg, target);
404 signal_emit("message silc own_private_notice", 3,
405 server, msg, target);
410 cmd_params_free(free_arg);
414 /* AWAY local command. Sends UMODE command that sets the SILC_UMODE_GONE
417 bool silc_set_away(const char *reason, SILC_SERVER_REC *server)
421 if (!IS_SILC_SERVER(server) || !server->connected)
424 if (*reason == '\0') {
425 /* Remove any possible away message */
426 silc_client_set_away_message(silc_client, server->conn, NULL);
429 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
432 /* Set the away message */
433 silc_client_set_away_message(silc_client, server->conn, (char *)reason);
436 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
437 SILCTXT_SET_AWAY, reason);
440 server->usermode_away = set;
441 g_free_and_null(server->away_reason);
443 server->away_reason = g_strdup((char *)reason);
445 signal_emit("away mode changed", 1, server);
450 static void command_away(const char *data, SILC_SERVER_REC *server,
453 CMD_SILC_SERVER(server);
455 if (!IS_SILC_SERVER(server) || !server->connected)
456 cmd_return_error(CMDERR_NOT_CONNECTED);
458 g_free_and_null(server->away_reason);
459 if ((data) && (*data != '\0'))
460 server->away_reason = g_strdup(data);
462 silc_command_exec(server, "UMODE",
463 (server->away_reason != NULL) ? "+g" : "-g");
467 SILC_SERVER_REC *server;
468 int type; /* 1 = msg, 2 = channel */
472 /* Key agreement callback that is called after the key agreement protocol
473 has been performed. This is called also if error occured during the
474 key agreement protocol. The `key' is the allocated key material and
475 the caller is responsible of freeing it. The `key' is NULL if error
476 has occured. The application can freely use the `key' to whatever
477 purpose it needs. See lib/silcske/silcske.h for the definition of
478 the SilcSKEKeyMaterial structure. */
480 static void keyagr_completion(SilcClient client,
481 SilcClientConnection conn,
482 SilcClientEntry client_entry,
483 SilcKeyAgreementStatus status,
484 SilcSKEKeyMaterial key,
487 KeyInternal i = (KeyInternal)context;
490 case SILC_KEY_AGREEMENT_OK:
491 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
492 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
495 /* Set the private key for this client */
496 silc_client_del_private_message_key(client, conn, client_entry);
497 silc_client_add_private_message_key_ske(client, conn, client_entry,
499 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
500 SILCTXT_KEY_AGREEMENT_PRIVMSG,
501 client_entry->nickname);
502 silc_ske_free_key_material(key);
507 case SILC_KEY_AGREEMENT_ERROR:
508 case SILC_KEY_AGREEMENT_NO_MEMORY:
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,
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 client_entry = NULL;
596 SILC_CHANNEL_REC *chanrec = NULL;
597 SilcChannelEntry channel_entry = NULL;
598 char nickname[128 + 1], *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;
606 SilcChannelPrivateKey ch = NULL;
608 SilcBool udp = FALSE;
611 CMD_SILC_SERVER(server);
613 if (!server || !IS_SILC_SERVER(server) || !server->connected)
614 cmd_return_error(CMDERR_NOT_CONNECTED);
618 /* Now parse all arguments */
619 tmp = g_strconcat("KEY", " ", data, NULL);
620 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
624 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
627 if (!strcasecmp(argv[1], "msg"))
629 if (!strcasecmp(argv[1], "channel"))
633 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
636 if (argv[2][0] == '*') {
637 strcpy(nickname, "*");
639 /* Parse the typed nickname. */
640 if (!silc_parse_userfqdn(argv[2], nickname, sizeof(nickname), NULL, 0)) {
641 printformat_module("fe-common/silc", server, NULL,
642 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
646 /* Find client entry */
647 clients = silc_client_get_clients_local(silc_client, conn, nickname,
650 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
651 inter->server = server;
652 inter->data = strdup(data);
653 inter->nick = strdup(nickname);
655 silc_client_get_clients(silc_client, conn, nickname, argv[2],
656 silc_client_command_key_get_clients, inter);
660 client_entry = silc_dlist_get(clients);
661 silc_client_list_free(silc_client, conn, clients);
666 /* Get channel entry */
669 if (argv[2][0] == '*') {
670 if (!conn->current_channel) {
672 cmd_return_error(CMDERR_NOT_JOINED);
674 name = conn->current_channel->channel_name;
679 chanrec = silc_channel_find(server, name);
680 if (chanrec == NULL) {
682 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
684 channel_entry = chanrec->entry;
688 if (!strcasecmp(argv[3], "set")) {
692 char *cipher = NULL, *hmac = NULL;
699 if (type == 1 && client_entry) {
700 /* Set private message key */
701 silc_client_del_private_message_key(silc_client, conn, client_entry);
702 silc_client_add_private_message_key(silc_client, conn, client_entry,
704 argv[4], argv_lens[4]);
705 } else if (type == 2) {
706 /* Set private channel key */
707 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
708 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
709 SILCTXT_CH_PRIVATE_KEY_NOMODE,
710 channel_entry->channel_name);
714 if (!silc_client_add_channel_private_key(silc_client, conn,
718 argv_lens[4], NULL)) {
719 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
720 SILCTXT_CH_PRIVATE_KEY_ERROR,
721 channel_entry->channel_name);
725 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
726 SILCTXT_CH_PRIVATE_KEY_ADD,
727 channel_entry->channel_name);
735 if (!strcasecmp(argv[3], "unset")) {
738 if (type == 1 && client_entry) {
739 /* Unset private message key */
740 silc_client_del_private_message_key(silc_client, conn, client_entry);
741 } else if (type == 2) {
742 /* Unset channel key(s) */
746 silc_client_del_channel_private_keys(silc_client, conn,
750 number = atoi(argv[4]);
751 ckeys = silc_client_list_channel_private_keys(silc_client, conn,
756 if (!number || number > silc_dlist_count(ckeys)) {
757 silc_dlist_uninit(ckeys);
761 for (i = 0; i < number; i++)
762 ch = silc_dlist_get(ckeys);
766 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
768 silc_dlist_uninit(ckeys);
776 if (!strcasecmp(argv[3], "list")) {
780 SilcPrivateMessageKeys keys;
781 SilcUInt32 keys_count;
785 keys = silc_client_list_private_message_keys(silc_client, conn,
790 /* list the private message key(s) */
791 if (nickname[0] == '*') {
792 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
793 SILCTXT_PRIVATE_KEY_LIST);
794 for (k = 0; k < keys_count; k++) {
795 memset(buf, 0, sizeof(buf));
796 strncat(buf, " ", 2);
797 len = strlen(keys[k].client_entry->nickname);
798 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
800 for (i = 0; i < 30 - len; i++)
804 len = strlen(keys[k].cipher);
805 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
807 for (i = 0; i < 14 - len; i++)
812 strcat(buf, "<hidden>");
814 strcat(buf, "*generated*");
816 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
819 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
820 SILCTXT_PRIVATE_KEY_LIST_NICK,
821 client_entry->nickname);
822 for (k = 0; k < keys_count; k++) {
823 if (keys[k].client_entry != client_entry)
826 memset(buf, 0, sizeof(buf));
827 strncat(buf, " ", 2);
828 len = strlen(keys[k].client_entry->nickname);
829 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
831 for (i = 0; i < 30 - len; i++)
835 len = strlen(keys[k].cipher);
836 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
838 for (i = 0; i < 14 - len; i++)
843 strcat(buf, "<hidden>");
845 strcat(buf, "*generated*");
847 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
851 silc_client_free_private_message_keys(keys, keys_count);
853 } else if (type == 2) {
857 ckeys = silc_client_list_channel_private_keys(silc_client, conn,
860 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
861 SILCTXT_CH_PRIVATE_KEY_LIST,
862 channel_entry->channel_name);
867 while ((ch = silc_dlist_get(ckeys))) {
868 memset(buf, 0, sizeof(buf));
869 strncat(buf, " ", 2);
871 len = strlen(silc_cipher_get_name(ch->cipher));
872 strncat(buf, silc_cipher_get_name(ch->cipher),
873 len > 16 ? 16 : len);
875 for (i = 0; i < 16 - len; i++)
879 len = strlen(silc_hmac_get_name(ch->hmac));
880 strncat(buf, silc_hmac_get_name(ch->hmac), len > 16 ? 16 : len);
882 for (i = 0; i < 16 - len; i++)
886 strcat(buf, "<hidden>");
888 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
891 silc_dlist_uninit(ckeys);
897 /* Send command is used to send key agreement */
898 if (!strcasecmp(argv[3], "agreement")) {
904 if (!strcasecmp(argv[5], "UDP"))
907 port = atoi(argv[5]);
912 internal = silc_calloc(1, sizeof(*internal));
913 internal->type = type;
914 internal->server = server;
917 if (settings_get_bool("use_auto_addr")) {
918 hostname = (char *)settings_get_str("auto_public_ip");
920 /* If the hostname isn't set, treat this case as if auto_public_ip
922 if ((hostname) && (*hostname == '\0')) {
925 bindhost = (char *)settings_get_str("auto_bind_ip");
927 /* if the bind_ip isn't set, but the public_ip IS, then assume then
928 public_ip is the same value as the bind_ip. */
929 if ((bindhost) && (*bindhost == '\0'))
931 port = settings_get_int("auto_bind_port");
933 } /* if use_auto_addr */
937 /* Start command is used to start key agreement (after receiving the
938 key_agreement client operation). */
939 if (!strcasecmp(argv[3], "negotiate")) {
945 if (!strcasecmp(argv[5], "UDP"))
948 port = atoi(argv[5]);
953 internal = silc_calloc(1, sizeof(*internal));
954 internal->type = type;
955 internal->server = server;
958 /* Change current channel private key */
959 if (!strcasecmp(argv[3], "change")) {
962 /* Unset channel key(s) */
965 ckeys = silc_client_list_channel_private_keys(silc_client, conn,
972 if (chanrec->cur_key >= silc_dlist_count(ckeys))
973 chanrec->cur_key = 0;
977 number = atoi(argv[4]);
978 if (!number || number > silc_dlist_count(ckeys))
979 chanrec->cur_key = 0;
981 chanrec->cur_key = number - 1;
984 for (i = 0; i < chanrec->cur_key; i++)
985 ch = silc_dlist_get(ckeys);
989 /* Set the current channel private key */
990 silc_client_current_channel_private_key(silc_client, conn,
992 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
993 SILCTXT_CH_PRIVATE_KEY_CHANGE, i + 1,
994 channel_entry->channel_name);
996 silc_dlist_uninit(ckeys);
1002 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
1003 "Usage: /KEY msg|channel <nickname|channel> "
1004 "set|unset|agreement|negotiate [<arguments>]");
1008 if (command == 4 && client_entry) {
1009 SilcClientConnectionParams params;
1011 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1012 SILCTXT_KEY_AGREEMENT, argv[2]);
1013 internal->responder = TRUE;
1015 memset(¶ms, 0, sizeof(params));
1016 params.local_ip = hostname;
1017 params.bind_ip = bindhost;
1018 params.local_port = port;
1020 params.timeout_secs = settings_get_int("key_exchange_timeout_secs");
1022 silc_client_send_key_agreement(
1023 silc_client, conn, client_entry, ¶ms,
1024 irssi_pubkey, irssi_privkey,
1025 keyagr_completion, internal);
1027 silc_free(internal);
1031 if (command == 5 && client_entry && hostname) {
1032 SilcClientConnectionParams params;
1034 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1035 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
1036 internal->responder = FALSE;
1038 memset(¶ms, 0, sizeof(params));
1040 if (settings_get_bool("use_auto_addr")) {
1041 params.local_ip = (char *)settings_get_str("auto_public_ip");
1042 if ((params.local_ip) && (*params.local_ip == '\0')) {
1043 params.local_ip = silc_net_localip();
1045 params.bind_ip = (char *)settings_get_str("auto_bind_ip");
1046 if ((params.bind_ip) && (*params.bind_ip == '\0'))
1047 params.bind_ip = NULL;
1048 params.local_port = settings_get_int("auto_bind_port");
1051 if (!params.local_ip)
1052 params.local_ip = silc_net_localip();
1055 params.timeout_secs = settings_get_int("key_exchange_timeout_secs");
1057 silc_client_perform_key_agreement(silc_client, conn, client_entry, ¶ms,
1058 irssi_pubkey, irssi_privkey,
1059 hostname, port, keyagr_completion,
1068 void silc_list_key(const char *pub_filename, int verbose)
1070 SilcPublicKey public_key;
1071 SilcPublicKeyIdentifier ident;
1072 SilcSILCPublicKey silc_pubkey;
1073 char *fingerprint, *babbleprint;
1076 SilcUInt32 key_len = 0;
1077 int is_server_key = (strstr(pub_filename, "serverkeys") != NULL);
1079 if (!silc_pkcs_load_public_key((char *)pub_filename, &public_key)) {
1080 printformat_module("fe-common/silc", NULL, NULL,
1081 MSGLEVEL_CRAP, SILCTXT_LISTKEY_LOADPUB,
1086 /* Print only SILC public keys */
1087 if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
1088 printformat_module("fe-common/silc", NULL, NULL,
1089 MSGLEVEL_CRAP, SILCTXT_LISTKEY_LOADPUB,
1094 silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
1095 ident = &silc_pubkey->identifier;
1097 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1098 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1099 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1100 key_len = silc_pkcs_public_key_get_len(public_key);
1102 printformat_module("fe-common/silc", NULL, NULL,
1103 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_FILE,
1107 printformat_module("fe-common/silc", NULL, NULL,
1108 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_ALG,
1109 silc_pkcs_get_name(public_key));
1110 if (key_len && verbose)
1111 printformat_module("fe-common/silc", NULL, NULL,
1112 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_BITS,
1113 (unsigned int)key_len);
1114 if (ident->version && verbose)
1115 printformat_module("fe-common/silc", NULL, NULL,
1116 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_VER,
1118 if (ident->realname && (!is_server_key || verbose))
1119 printformat_module("fe-common/silc", NULL, NULL,
1120 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_RN,
1122 if (ident->username && verbose)
1123 printformat_module("fe-common/silc", NULL, NULL,
1124 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_UN,
1126 if (ident->host && (is_server_key || verbose))
1127 printformat_module("fe-common/silc", NULL, NULL,
1128 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_HN,
1130 if (ident->email && verbose)
1131 printformat_module("fe-common/silc", NULL, NULL,
1132 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_EMAIL,
1134 if (ident->org && verbose)
1135 printformat_module("fe-common/silc", NULL, NULL,
1136 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_ORG,
1138 if (ident->country && verbose)
1139 printformat_module("fe-common/silc", NULL, NULL,
1140 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_C,
1144 printformat_module("fe-common/silc", NULL, NULL,
1145 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_FINGER,
1147 printformat_module("fe-common/silc", NULL, NULL,
1148 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_BABL,
1152 silc_free(fingerprint);
1153 silc_free(babbleprint);
1155 silc_pkcs_public_key_free(public_key);
1158 void silc_list_keys_in_dir(const char *dirname, const char *where)
1161 struct dirent *entry;
1163 dir = opendir(dirname);
1166 cmd_return_error(CMDERR_ERRNO);
1168 printformat_module("fe-common/silc", NULL, NULL,
1169 MSGLEVEL_CRAP, SILCTXT_LISTKEY_LIST,
1174 while ((entry = readdir(dir)) != NULL) {
1175 /* try to open everything that isn't a directory */
1179 snprintf(filename, sizeof(filename) - 1, "%s/%s", dirname, entry->d_name);
1180 if (!stat(filename, &buf) && S_ISREG(buf.st_mode))
1181 silc_list_key(filename, FALSE);
1187 void silc_list_file(const char *filename)
1193 snprintf(path, sizeof(path) - 1, "%s", filename);
1194 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1197 snprintf(path, sizeof(path) - 1, "%s/%s", get_irssi_dir(), filename);
1198 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1201 snprintf(path,sizeof(path) - 1, "%s/clientkeys/%s", get_irssi_dir(),
1203 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1206 snprintf(path,sizeof(path) - 1, "%s/serverkeys/%s", get_irssi_dir(),
1208 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1215 silc_list_key(path, TRUE);
1218 /* Lists locally saved client and server public keys. */
1219 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
1222 GHashTable *optlist;
1227 if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS |
1228 PARAM_FLAG_GETREST, "listkeys", &optlist,
1232 if (*filename != '\0') {
1234 silc_list_file(filename);
1237 int clients, servers;
1239 clients = (g_hash_table_lookup(optlist, "clients") != NULL);
1240 servers = (g_hash_table_lookup(optlist, "servers") != NULL);
1242 if (!(clients || servers))
1243 clients = servers = 1;
1246 snprintf(dirname, sizeof(dirname) - 1, "%s/serverkeys", get_irssi_dir());
1247 silc_list_keys_in_dir(dirname, "server");
1251 snprintf(dirname, sizeof(dirname) - 1, "%s/clientkeys", get_irssi_dir());
1252 silc_list_keys_in_dir(dirname, "client");
1255 cmd_params_free(free_arg);
1258 void silc_channels_init(void)
1260 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1261 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1262 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1263 signal_add("mime", (SIGNAL_FUNC) sig_mime);
1265 command_bind_silc("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1266 command_bind_silc("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1267 command_bind_silc("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1268 command_bind_silc("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1269 command_bind_silc("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1270 command_bind_silc("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1271 command_bind("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
1273 command_set_options("listkeys", "clients servers");
1274 command_set_options("action", "sign channel");
1275 command_set_options("notice", "sign channel");
1277 silc_nicklist_init();
1280 void silc_channels_deinit(void)
1282 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1283 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1284 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1285 signal_remove("mime", (SIGNAL_FUNC) sig_mime);
1287 command_unbind("part", (SIGNAL_FUNC) command_part);
1288 command_unbind("me", (SIGNAL_FUNC) command_me);
1289 command_unbind("action", (SIGNAL_FUNC) command_action);
1290 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1291 command_unbind("away", (SIGNAL_FUNC) command_away);
1292 command_unbind("key", (SIGNAL_FUNC) command_key);
1293 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
1295 silc_nicklist_deinit();