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 silc_dlist_start(ckeys);
751 if (!number || number > silc_dlist_count(ckeys)) {
752 silc_dlist_uninit(ckeys);
756 for (i = 0; i < number; i++)
757 ch = silc_dlist_get(ckeys);
761 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
763 silc_dlist_uninit(ckeys);
771 if (!strcasecmp(argv[3], "list")) {
775 SilcPrivateMessageKeys keys;
776 SilcUInt32 keys_count;
780 keys = silc_client_list_private_message_keys(silc_client, conn,
785 /* list the private message key(s) */
786 if (nickname[0] == '*') {
787 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
788 SILCTXT_PRIVATE_KEY_LIST);
789 for (k = 0; k < keys_count; k++) {
790 memset(buf, 0, sizeof(buf));
791 strncat(buf, " ", 2);
792 len = strlen(keys[k].client_entry->nickname);
793 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
795 for (i = 0; i < 30 - len; i++)
799 len = strlen(keys[k].cipher);
800 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
802 for (i = 0; i < 14 - len; i++)
807 strcat(buf, "<hidden>");
809 strcat(buf, "*generated*");
811 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
814 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
815 SILCTXT_PRIVATE_KEY_LIST_NICK,
816 client_entry->nickname);
817 for (k = 0; k < keys_count; k++) {
818 if (keys[k].client_entry != client_entry)
821 memset(buf, 0, sizeof(buf));
822 strncat(buf, " ", 2);
823 len = strlen(keys[k].client_entry->nickname);
824 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
826 for (i = 0; i < 30 - len; i++)
830 len = strlen(keys[k].cipher);
831 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
833 for (i = 0; i < 14 - len; i++)
838 strcat(buf, "<hidden>");
840 strcat(buf, "*generated*");
842 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
846 silc_client_free_private_message_keys(keys, keys_count);
848 } else if (type == 2) {
852 ckeys = silc_client_list_channel_private_keys(silc_client, conn,
855 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
856 SILCTXT_CH_PRIVATE_KEY_LIST,
857 channel_entry->channel_name);
862 silc_dlist_start(ckeys);
863 while ((ch = silc_dlist_get(ckeys))) {
864 memset(buf, 0, sizeof(buf));
865 strncat(buf, " ", 2);
867 len = strlen(silc_cipher_get_name(ch->send_key));
868 strncat(buf, silc_cipher_get_name(ch->send_key),
869 len > 16 ? 16 : len);
871 for (i = 0; i < 16 - len; i++)
875 len = strlen(silc_hmac_get_name(ch->hmac));
876 strncat(buf, silc_hmac_get_name(ch->hmac), len > 16 ? 16 : len);
878 for (i = 0; i < 16 - len; i++)
882 strcat(buf, "<hidden>");
884 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
887 silc_dlist_uninit(ckeys);
893 /* Send command is used to send key agreement */
894 if (!strcasecmp(argv[3], "agreement")) {
900 if (!strcasecmp(argv[5], "UDP"))
903 port = atoi(argv[5]);
908 internal = silc_calloc(1, sizeof(*internal));
909 internal->type = type;
910 internal->server = server;
913 if (settings_get_bool("use_auto_addr")) {
914 hostname = (char *)settings_get_str("auto_public_ip");
916 /* If the hostname isn't set, treat this case as if auto_public_ip
918 if ((hostname) && (*hostname == '\0')) {
921 bindhost = (char *)settings_get_str("auto_bind_ip");
923 /* if the bind_ip isn't set, but the public_ip IS, then assume then
924 public_ip is the same value as the bind_ip. */
925 if ((bindhost) && (*bindhost == '\0'))
927 port = settings_get_int("auto_bind_port");
929 } /* if use_auto_addr */
933 /* Start command is used to start key agreement (after receiving the
934 key_agreement client operation). */
935 if (!strcasecmp(argv[3], "negotiate")) {
941 if (!strcasecmp(argv[5], "UDP"))
944 port = atoi(argv[5]);
949 internal = silc_calloc(1, sizeof(*internal));
950 internal->type = type;
951 internal->server = server;
954 /* Change current channel private key */
955 if (!strcasecmp(argv[3], "change")) {
958 /* Unset channel key(s) */
961 ckeys = silc_client_list_channel_private_keys(silc_client, conn,
966 silc_dlist_start(ckeys);
969 if (chanrec->cur_key >= silc_dlist_count(ckeys))
970 chanrec->cur_key = 0;
974 number = atoi(argv[4]);
975 if (!number || number > silc_dlist_count(ckeys))
976 chanrec->cur_key = 0;
978 chanrec->cur_key = number - 1;
981 for (i = 0; i < chanrec->cur_key; i++)
982 ch = silc_dlist_get(ckeys);
986 /* Set the current channel private key */
987 silc_client_current_channel_private_key(silc_client, conn,
989 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
990 SILCTXT_CH_PRIVATE_KEY_CHANGE, i + 1,
991 channel_entry->channel_name);
993 silc_dlist_uninit(ckeys);
999 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
1000 "Usage: /KEY msg|channel <nickname|channel> "
1001 "set|unset|agreement|negotiate [<arguments>]");
1005 if (command == 4 && client_entry) {
1006 SilcClientConnectionParams params;
1008 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1009 SILCTXT_KEY_AGREEMENT, argv[2]);
1010 internal->responder = TRUE;
1012 memset(¶ms, 0, sizeof(params));
1013 params.local_ip = hostname;
1014 params.bind_ip = bindhost;
1015 params.local_port = port;
1017 params.timeout_secs = settings_get_int("key_exchange_timeout_secs");
1019 silc_client_send_key_agreement(
1020 silc_client, conn, client_entry, ¶ms,
1021 irssi_pubkey, irssi_privkey,
1022 keyagr_completion, internal);
1024 silc_free(internal);
1028 if (command == 5 && client_entry && hostname) {
1029 SilcClientConnectionParams params;
1031 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1032 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
1033 internal->responder = FALSE;
1035 memset(¶ms, 0, sizeof(params));
1037 if (settings_get_bool("use_auto_addr")) {
1038 params.local_ip = (char *)settings_get_str("auto_public_ip");
1039 if ((params.local_ip) && (*params.local_ip == '\0')) {
1040 params.local_ip = silc_net_localip();
1042 params.bind_ip = (char *)settings_get_str("auto_bind_ip");
1043 if ((params.bind_ip) && (*params.bind_ip == '\0'))
1044 params.bind_ip = NULL;
1045 params.local_port = settings_get_int("auto_bind_port");
1048 if (!params.local_ip)
1049 params.local_ip = silc_net_localip();
1052 params.timeout_secs = settings_get_int("key_exchange_timeout_secs");
1054 silc_client_perform_key_agreement(silc_client, conn, client_entry, ¶ms,
1055 irssi_pubkey, irssi_privkey,
1056 hostname, port, keyagr_completion,
1062 silc_free(nickname);
1066 void silc_list_key(const char *pub_filename, int verbose)
1068 SilcPublicKey public_key;
1069 SilcPublicKeyIdentifier ident;
1070 SilcSILCPublicKey silc_pubkey;
1071 char *fingerprint, *babbleprint;
1074 SilcUInt32 key_len = 0;
1075 int is_server_key = (strstr(pub_filename, "serverkeys") != NULL);
1077 if (!silc_pkcs_load_public_key((char *)pub_filename, SILC_PKCS_ANY,
1079 printformat_module("fe-common/silc", NULL, NULL,
1080 MSGLEVEL_CRAP, SILCTXT_LISTKEY_LOADPUB,
1085 /* Print only SILC public keys */
1086 if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
1087 printformat_module("fe-common/silc", NULL, NULL,
1088 MSGLEVEL_CRAP, SILCTXT_LISTKEY_LOADPUB,
1093 silc_pubkey = silc_pkcs_public_key_get_pkcs(SILC_PKCS_SILC, public_key);
1094 ident = &silc_pubkey->identifier;
1096 pk = silc_pkcs_public_key_encode(NULL, public_key, &pk_len);
1099 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1100 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1101 key_len = silc_pkcs_public_key_get_len(public_key);
1103 printformat_module("fe-common/silc", NULL, NULL,
1104 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_FILE,
1108 printformat_module("fe-common/silc", NULL, NULL,
1109 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_ALG,
1110 silc_pkcs_get_name(public_key));
1111 if (key_len && verbose)
1112 printformat_module("fe-common/silc", NULL, NULL,
1113 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_BITS,
1114 (unsigned int)key_len);
1115 if (ident->version && verbose)
1116 printformat_module("fe-common/silc", NULL, NULL,
1117 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_VER,
1119 if (ident->realname && (!is_server_key || verbose))
1120 printformat_module("fe-common/silc", NULL, NULL,
1121 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_RN,
1123 if (ident->username && verbose)
1124 printformat_module("fe-common/silc", NULL, NULL,
1125 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_UN,
1127 if (ident->host && (is_server_key || verbose))
1128 printformat_module("fe-common/silc", NULL, NULL,
1129 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_HN,
1131 if (ident->email && verbose)
1132 printformat_module("fe-common/silc", NULL, NULL,
1133 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_EMAIL,
1135 if (ident->org && verbose)
1136 printformat_module("fe-common/silc", NULL, NULL,
1137 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_ORG,
1139 if (ident->country && verbose)
1140 printformat_module("fe-common/silc", NULL, NULL,
1141 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_C,
1145 printformat_module("fe-common/silc", NULL, NULL,
1146 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_FINGER,
1148 printformat_module("fe-common/silc", NULL, NULL,
1149 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_BABL,
1153 silc_free(fingerprint);
1154 silc_free(babbleprint);
1156 silc_pkcs_public_key_free(public_key);
1159 void silc_list_keys_in_dir(const char *dirname, const char *where)
1162 struct dirent *entry;
1164 dir = opendir(dirname);
1167 cmd_return_error(CMDERR_ERRNO);
1169 printformat_module("fe-common/silc", NULL, NULL,
1170 MSGLEVEL_CRAP, SILCTXT_LISTKEY_LIST,
1175 while ((entry = readdir(dir)) != NULL) {
1176 /* try to open everything that isn't a directory */
1180 snprintf(filename, sizeof(filename) - 1, "%s/%s", dirname, entry->d_name);
1181 if (!stat(filename, &buf) && S_ISREG(buf.st_mode))
1182 silc_list_key(filename, FALSE);
1188 void silc_list_file(const char *filename)
1194 snprintf(path, sizeof(path) - 1, "%s", filename);
1195 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1198 snprintf(path, sizeof(path) - 1, "%s/%s", get_irssi_dir(), filename);
1199 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1202 snprintf(path,sizeof(path) - 1, "%s/clientkeys/%s", get_irssi_dir(),
1204 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1207 snprintf(path,sizeof(path) - 1, "%s/serverkeys/%s", get_irssi_dir(),
1209 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1216 silc_list_key(path, TRUE);
1219 /* Lists locally saved client and server public keys. */
1220 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
1223 GHashTable *optlist;
1228 if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS |
1229 PARAM_FLAG_GETREST, "listkeys", &optlist,
1233 if (*filename != '\0') {
1235 silc_list_file(filename);
1238 int clients, servers;
1240 clients = (g_hash_table_lookup(optlist, "clients") != NULL);
1241 servers = (g_hash_table_lookup(optlist, "servers") != NULL);
1243 if (!(clients || servers))
1244 clients = servers = 1;
1247 snprintf(dirname, sizeof(dirname) - 1, "%s/serverkeys", get_irssi_dir());
1248 silc_list_keys_in_dir(dirname, "server");
1252 snprintf(dirname, sizeof(dirname) - 1, "%s/clientkeys", get_irssi_dir());
1253 silc_list_keys_in_dir(dirname, "client");
1256 cmd_params_free(free_arg);
1259 void silc_channels_init(void)
1261 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1262 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1263 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1264 signal_add("mime", (SIGNAL_FUNC) sig_mime);
1266 command_bind_silc("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1267 command_bind_silc("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1268 command_bind_silc("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1269 command_bind_silc("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1270 command_bind_silc("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1271 command_bind_silc("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1272 command_bind("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
1274 command_set_options("listkeys", "clients servers");
1275 command_set_options("action", "sign channel");
1276 command_set_options("notice", "sign channel");
1278 silc_nicklist_init();
1281 void silc_channels_deinit(void)
1283 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1284 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1285 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1286 signal_remove("mime", (SIGNAL_FUNC) sig_mime);
1288 command_unbind("part", (SIGNAL_FUNC) command_part);
1289 command_unbind("me", (SIGNAL_FUNC) command_me);
1290 command_unbind("action", (SIGNAL_FUNC) command_action);
1291 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1292 command_unbind("away", (SIGNAL_FUNC) command_away);
1293 command_unbind("key", (SIGNAL_FUNC) command_key);
1294 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
1296 silc_nicklist_deinit();