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 = NULL, *tmp;
599 int command = 0, port = 0, type = 0;
600 char *hostname = NULL;
601 KeyInternal internal = NULL;
603 unsigned char **argv;
604 SilcUInt32 *argv_lens, *argv_types;
605 char *bindhost = NULL;
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 nickname = strdup("*");
639 /* Parse the typed nickname. */
640 silc_client_nickname_parse(silc_client, conn, argv[2], &nickname);
642 nickname = strdup(argv[2]);
644 /* Find client entry */
645 clients = silc_client_get_clients_local(silc_client, conn, argv[2],
648 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
649 inter->server = server;
650 inter->data = strdup(data);
651 inter->nick = strdup(nickname);
653 silc_client_get_clients(silc_client, conn, nickname, NULL,
654 silc_client_command_key_get_clients, inter);
658 client_entry = silc_dlist_get(clients);
659 silc_client_list_free(silc_client, conn, clients);
664 /* Get channel entry */
667 if (argv[2][0] == '*') {
668 if (!conn->current_channel)
669 cmd_return_error(CMDERR_NOT_JOINED);
670 name = conn->current_channel->channel_name;
675 chanrec = silc_channel_find(server, name);
677 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
678 channel_entry = chanrec->entry;
682 if (!strcasecmp(argv[3], "set")) {
686 char *cipher = NULL, *hmac = NULL;
693 if (type == 1 && client_entry) {
694 /* Set private message key */
695 silc_client_del_private_message_key(silc_client, conn, client_entry);
696 silc_client_add_private_message_key(silc_client, conn, client_entry,
698 argv[4], argv_lens[4]);
699 } else if (type == 2) {
700 /* Set private channel key */
701 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
702 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
703 SILCTXT_CH_PRIVATE_KEY_NOMODE,
704 channel_entry->channel_name);
708 if (!silc_client_add_channel_private_key(silc_client, conn,
712 argv_lens[4], NULL)) {
713 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
714 SILCTXT_CH_PRIVATE_KEY_ERROR,
715 channel_entry->channel_name);
719 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
720 SILCTXT_CH_PRIVATE_KEY_ADD,
721 channel_entry->channel_name);
729 if (!strcasecmp(argv[3], "unset")) {
732 if (type == 1 && client_entry) {
733 /* Unset private message key */
734 silc_client_del_private_message_key(silc_client, conn, client_entry);
735 } else if (type == 2) {
736 /* Unset channel key(s) */
740 silc_client_del_channel_private_keys(silc_client, conn,
744 number = atoi(argv[4]);
745 ckeys = silc_client_list_channel_private_keys(silc_client, conn,
750 if (!number || number > silc_dlist_count(ckeys)) {
751 silc_dlist_uninit(ckeys);
755 for (i = 0; i < number; i++)
756 ch = silc_dlist_get(ckeys);
760 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
762 silc_dlist_uninit(ckeys);
770 if (!strcasecmp(argv[3], "list")) {
774 SilcPrivateMessageKeys keys;
775 SilcUInt32 keys_count;
779 keys = silc_client_list_private_message_keys(silc_client, conn,
784 /* list the private message key(s) */
785 if (nickname[0] == '*') {
786 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
787 SILCTXT_PRIVATE_KEY_LIST);
788 for (k = 0; k < keys_count; k++) {
789 memset(buf, 0, sizeof(buf));
790 strncat(buf, " ", 2);
791 len = strlen(keys[k].client_entry->nickname);
792 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
794 for (i = 0; i < 30 - len; i++)
798 len = strlen(keys[k].cipher);
799 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
801 for (i = 0; i < 14 - len; i++)
806 strcat(buf, "<hidden>");
808 strcat(buf, "*generated*");
810 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
813 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
814 SILCTXT_PRIVATE_KEY_LIST_NICK,
815 client_entry->nickname);
816 for (k = 0; k < keys_count; k++) {
817 if (keys[k].client_entry != client_entry)
820 memset(buf, 0, sizeof(buf));
821 strncat(buf, " ", 2);
822 len = strlen(keys[k].client_entry->nickname);
823 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
825 for (i = 0; i < 30 - len; i++)
829 len = strlen(keys[k].cipher);
830 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
832 for (i = 0; i < 14 - len; i++)
837 strcat(buf, "<hidden>");
839 strcat(buf, "*generated*");
841 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
845 silc_client_free_private_message_keys(keys, keys_count);
847 } else if (type == 2) {
851 ckeys = silc_client_list_channel_private_keys(silc_client, conn,
854 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
855 SILCTXT_CH_PRIVATE_KEY_LIST,
856 channel_entry->channel_name);
861 while ((ch = silc_dlist_get(ckeys))) {
862 memset(buf, 0, sizeof(buf));
863 strncat(buf, " ", 2);
865 len = strlen(silc_cipher_get_name(ch->send_key));
866 strncat(buf, silc_cipher_get_name(ch->send_key),
867 len > 16 ? 16 : len);
869 for (i = 0; i < 16 - len; i++)
873 len = strlen(silc_hmac_get_name(ch->hmac));
874 strncat(buf, silc_hmac_get_name(ch->hmac), len > 16 ? 16 : len);
876 for (i = 0; i < 16 - len; i++)
880 strcat(buf, "<hidden>");
882 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
885 silc_dlist_uninit(ckeys);
891 /* Send command is used to send key agreement */
892 if (!strcasecmp(argv[3], "agreement")) {
898 if (!strcasecmp(argv[5], "UDP"))
901 port = atoi(argv[5]);
906 internal = silc_calloc(1, sizeof(*internal));
907 internal->type = type;
908 internal->server = server;
911 if (settings_get_bool("use_auto_addr")) {
912 hostname = (char *)settings_get_str("auto_public_ip");
914 /* If the hostname isn't set, treat this case as if auto_public_ip
916 if ((hostname) && (*hostname == '\0')) {
919 bindhost = (char *)settings_get_str("auto_bind_ip");
921 /* if the bind_ip isn't set, but the public_ip IS, then assume then
922 public_ip is the same value as the bind_ip. */
923 if ((bindhost) && (*bindhost == '\0'))
925 port = settings_get_int("auto_bind_port");
927 } /* if use_auto_addr */
931 /* Start command is used to start key agreement (after receiving the
932 key_agreement client operation). */
933 if (!strcasecmp(argv[3], "negotiate")) {
939 if (!strcasecmp(argv[5], "UDP"))
942 port = atoi(argv[5]);
947 internal = silc_calloc(1, sizeof(*internal));
948 internal->type = type;
949 internal->server = server;
952 /* Change current channel private key */
953 if (!strcasecmp(argv[3], "change")) {
956 /* Unset channel key(s) */
959 ckeys = silc_client_list_channel_private_keys(silc_client, conn,
966 if (chanrec->cur_key >= silc_dlist_count(ckeys))
967 chanrec->cur_key = 0;
971 number = atoi(argv[4]);
972 if (!number || number > silc_dlist_count(ckeys))
973 chanrec->cur_key = 0;
975 chanrec->cur_key = number - 1;
978 for (i = 0; i < chanrec->cur_key; i++)
979 ch = silc_dlist_get(ckeys);
983 /* Set the current channel private key */
984 silc_client_current_channel_private_key(silc_client, conn,
986 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
987 SILCTXT_CH_PRIVATE_KEY_CHANGE, i + 1,
988 channel_entry->channel_name);
990 silc_dlist_uninit(ckeys);
996 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
997 "Usage: /KEY msg|channel <nickname|channel> "
998 "set|unset|agreement|negotiate [<arguments>]");
1002 if (command == 4 && client_entry) {
1003 SilcClientConnectionParams params;
1005 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1006 SILCTXT_KEY_AGREEMENT, argv[2]);
1007 internal->responder = TRUE;
1009 memset(¶ms, 0, sizeof(params));
1010 params.local_ip = hostname;
1011 params.bind_ip = bindhost;
1012 params.local_port = port;
1014 params.timeout_secs = settings_get_int("key_exchange_timeout_secs");
1016 silc_client_send_key_agreement(
1017 silc_client, conn, client_entry, ¶ms,
1018 irssi_pubkey, irssi_privkey,
1019 keyagr_completion, internal);
1021 silc_free(internal);
1025 if (command == 5 && client_entry && hostname) {
1026 SilcClientConnectionParams params;
1028 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1029 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
1030 internal->responder = FALSE;
1032 memset(¶ms, 0, sizeof(params));
1034 if (settings_get_bool("use_auto_addr")) {
1035 params.local_ip = (char *)settings_get_str("auto_public_ip");
1036 if ((params.local_ip) && (*params.local_ip == '\0')) {
1037 params.local_ip = silc_net_localip();
1039 params.bind_ip = (char *)settings_get_str("auto_bind_ip");
1040 if ((params.bind_ip) && (*params.bind_ip == '\0'))
1041 params.bind_ip = NULL;
1042 params.local_port = settings_get_int("auto_bind_port");
1045 if (!params.local_ip)
1046 params.local_ip = silc_net_localip();
1049 params.timeout_secs = settings_get_int("key_exchange_timeout_secs");
1051 silc_client_perform_key_agreement(silc_client, conn, client_entry, ¶ms,
1052 irssi_pubkey, irssi_privkey,
1053 hostname, port, keyagr_completion,
1059 silc_free(nickname);
1063 void silc_list_key(const char *pub_filename, int verbose)
1065 SilcPublicKey public_key;
1066 SilcPublicKeyIdentifier ident;
1067 SilcSILCPublicKey silc_pubkey;
1068 char *fingerprint, *babbleprint;
1071 SilcUInt32 key_len = 0;
1072 int is_server_key = (strstr(pub_filename, "serverkeys") != NULL);
1074 if (!silc_pkcs_load_public_key((char *)pub_filename, &public_key)) {
1075 printformat_module("fe-common/silc", NULL, NULL,
1076 MSGLEVEL_CRAP, SILCTXT_LISTKEY_LOADPUB,
1081 /* Print only SILC public keys */
1082 if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
1083 printformat_module("fe-common/silc", NULL, NULL,
1084 MSGLEVEL_CRAP, SILCTXT_LISTKEY_LOADPUB,
1089 silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
1090 ident = &silc_pubkey->identifier;
1092 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1093 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1094 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1095 key_len = silc_pkcs_public_key_get_len(public_key);
1097 printformat_module("fe-common/silc", NULL, NULL,
1098 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_FILE,
1102 printformat_module("fe-common/silc", NULL, NULL,
1103 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_ALG,
1104 silc_pkcs_get_name(public_key));
1105 if (key_len && verbose)
1106 printformat_module("fe-common/silc", NULL, NULL,
1107 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_BITS,
1108 (unsigned int)key_len);
1109 if (ident->version && verbose)
1110 printformat_module("fe-common/silc", NULL, NULL,
1111 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_VER,
1113 if (ident->realname && (!is_server_key || verbose))
1114 printformat_module("fe-common/silc", NULL, NULL,
1115 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_RN,
1117 if (ident->username && verbose)
1118 printformat_module("fe-common/silc", NULL, NULL,
1119 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_UN,
1121 if (ident->host && (is_server_key || verbose))
1122 printformat_module("fe-common/silc", NULL, NULL,
1123 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_HN,
1125 if (ident->email && verbose)
1126 printformat_module("fe-common/silc", NULL, NULL,
1127 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_EMAIL,
1129 if (ident->org && verbose)
1130 printformat_module("fe-common/silc", NULL, NULL,
1131 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_ORG,
1133 if (ident->country && verbose)
1134 printformat_module("fe-common/silc", NULL, NULL,
1135 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_C,
1139 printformat_module("fe-common/silc", NULL, NULL,
1140 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_FINGER,
1142 printformat_module("fe-common/silc", NULL, NULL,
1143 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_BABL,
1147 silc_free(fingerprint);
1148 silc_free(babbleprint);
1150 silc_pkcs_public_key_free(public_key);
1153 void silc_list_keys_in_dir(const char *dirname, const char *where)
1156 struct dirent *entry;
1158 dir = opendir(dirname);
1161 cmd_return_error(CMDERR_ERRNO);
1163 printformat_module("fe-common/silc", NULL, NULL,
1164 MSGLEVEL_CRAP, SILCTXT_LISTKEY_LIST,
1169 while ((entry = readdir(dir)) != NULL) {
1170 /* try to open everything that isn't a directory */
1174 snprintf(filename, sizeof(filename) - 1, "%s/%s", dirname, entry->d_name);
1175 if (!stat(filename, &buf) && S_ISREG(buf.st_mode))
1176 silc_list_key(filename, FALSE);
1182 void silc_list_file(const char *filename)
1188 snprintf(path, sizeof(path) - 1, "%s", filename);
1189 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1192 snprintf(path, sizeof(path) - 1, "%s/%s", get_irssi_dir(), filename);
1193 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1196 snprintf(path,sizeof(path) - 1, "%s/clientkeys/%s", get_irssi_dir(),
1198 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1201 snprintf(path,sizeof(path) - 1, "%s/serverkeys/%s", get_irssi_dir(),
1203 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1210 silc_list_key(path, TRUE);
1213 /* Lists locally saved client and server public keys. */
1214 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
1217 GHashTable *optlist;
1222 if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS |
1223 PARAM_FLAG_GETREST, "listkeys", &optlist,
1227 if (*filename != '\0') {
1229 silc_list_file(filename);
1232 int clients, servers;
1234 clients = (g_hash_table_lookup(optlist, "clients") != NULL);
1235 servers = (g_hash_table_lookup(optlist, "servers") != NULL);
1237 if (!(clients || servers))
1238 clients = servers = 1;
1241 snprintf(dirname, sizeof(dirname) - 1, "%s/serverkeys", get_irssi_dir());
1242 silc_list_keys_in_dir(dirname, "server");
1246 snprintf(dirname, sizeof(dirname) - 1, "%s/clientkeys", get_irssi_dir());
1247 silc_list_keys_in_dir(dirname, "client");
1250 cmd_params_free(free_arg);
1253 void silc_channels_init(void)
1255 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1256 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1257 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1258 signal_add("mime", (SIGNAL_FUNC) sig_mime);
1260 command_bind_silc("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1261 command_bind_silc("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1262 command_bind_silc("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1263 command_bind_silc("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1264 command_bind_silc("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1265 command_bind_silc("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1266 command_bind("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
1268 command_set_options("listkeys", "clients servers");
1269 command_set_options("action", "sign channel");
1270 command_set_options("notice", "sign channel");
1272 silc_nicklist_init();
1275 void silc_channels_deinit(void)
1277 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1278 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1279 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1280 signal_remove("mime", (SIGNAL_FUNC) sig_mime);
1282 command_unbind("part", (SIGNAL_FUNC) command_part);
1283 command_unbind("me", (SIGNAL_FUNC) command_me);
1284 command_unbind("action", (SIGNAL_FUNC) command_action);
1285 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1286 command_unbind("away", (SIGNAL_FUNC) command_away);
1287 command_unbind("key", (SIGNAL_FUNC) command_key);
1288 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
1290 silc_nicklist_deinit();