2 silc-channels.c : irssi
4 Copyright (C) 2000 - 2001, 2004, 2006 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)
114 SILC_CHANNEL_REC *chanrec;
116 list = g_strsplit(channels, ",", -1);
117 for (tmp = list; *tmp != NULL; tmp++) {
118 chanrec = silc_channel_find(server, *tmp);
122 silc_command_exec(server, "JOIN", *tmp);
128 static void sig_connected(SILC_SERVER_REC *server)
130 if (IS_SILC_SERVER(server))
131 server->channels_join = (void *) silc_channels_join;
134 /* "server quit" signal from the core to indicate that QUIT command
137 static void sig_server_quit(SILC_SERVER_REC *server, const char *msg)
139 if (IS_SILC_SERVER(server) && server->conn)
140 silc_command_exec(server, "QUIT", msg);
143 static void sig_gui_quit(SILC_SERVER_REC *server, const char *msg)
145 silc_client_stop(silc_client);
148 /* Find Irssi channel entry by SILC channel entry */
150 SILC_CHANNEL_REC *silc_channel_find_entry(SILC_SERVER_REC *server,
151 SilcChannelEntry entry)
155 g_return_val_if_fail(IS_SILC_SERVER(server), NULL);
157 for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
158 SILC_CHANNEL_REC *rec = tmp->data;
160 if (rec->entry == entry)
167 /* PART (LEAVE) command. */
169 static void command_part(const char *data, SILC_SERVER_REC *server,
172 SILC_CHANNEL_REC *chanrec;
175 CMD_SILC_SERVER(server);
177 if (!IS_SILC_SERVER(server) || !server->connected)
178 cmd_return_error(CMDERR_NOT_CONNECTED);
180 if (!strcmp(data, "*") || *data == '\0') {
181 if (!IS_SILC_CHANNEL(item))
182 cmd_return_error(CMDERR_NOT_JOINED);
183 data = item->visible_name;
186 chanrec = silc_channel_find(server, data);
188 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
190 memset(userhost, 0, sizeof(userhost));
191 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
192 server->conn->local_entry->username,
193 server->conn->local_entry->hostname);
194 signal_emit("message part", 5, server, chanrec->name,
195 server->nick, userhost, "");
197 chanrec->left = TRUE;
198 silc_command_exec(server, "LEAVE", chanrec->name);
199 /* enable queueing because we destroy the channel immedially */
200 silc_queue_enable(server->conn);
203 channel_destroy(CHANNEL(chanrec));
207 /* ACTION local command. */
209 static void command_action(const char *data, SILC_SERVER_REC *server,
214 char *message = NULL;
217 SilcBool sign = FALSE;
219 CMD_SILC_SERVER(server);
220 if (!IS_SILC_SERVER(server) || !server->connected)
221 cmd_return_error(CMDERR_NOT_CONNECTED);
223 if ((item != NULL) && (!IS_SILC_CHANNEL(item) && !IS_SILC_QUERY(item)))
224 cmd_return_error(CMDERR_NOT_JOINED);
226 /* Now parse all arguments */
227 if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS |
229 "action", &optlist, &target, &msg))
232 if (*target == '\0' || *msg == '\0')
233 cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
235 if (strcmp(target, "*") == 0) {
236 /* send to active channel/query */
238 cmd_param_error(CMDERR_NOT_JOINED);
240 target_type = IS_SILC_CHANNEL(item) ?
241 SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
242 target = (char *)window_item_get_target(item);
243 } else if (g_hash_table_lookup(optlist, "channel") != NULL)
244 target_type = SEND_TARGET_CHANNEL;
246 target_type = SEND_TARGET_NICK;
249 if (!silc_term_utf8()) {
250 int len = silc_utf8_encoded_len(msg, strlen(msg),
252 message = silc_calloc(len + 1, sizeof(*message));
253 g_return_if_fail(message != NULL);
254 silc_utf8_encode(msg, strlen(msg), SILC_STRING_LOCALE,
258 sign = (g_hash_table_lookup(optlist, "sign") ? TRUE :
259 settings_get_bool("sign_channel_messages") ? TRUE : FALSE);
261 if (target != NULL) {
262 if (target_type == SEND_TARGET_CHANNEL) {
263 if (silc_send_channel(server, target, (message != NULL ? message : msg),
264 SILC_MESSAGE_FLAG_ACTION | SILC_MESSAGE_FLAG_UTF8 |
265 (sign ? SILC_MESSAGE_FLAG_SIGNED : 0))) {
266 if (g_hash_table_lookup(optlist, "sign"))
267 signal_emit("message silc signed_own_action", 3, server, msg, target);
269 signal_emit("message silc own_action", 3, server, msg, target);
272 if (silc_send_msg(server, target, (message != NULL ? message : msg),
273 (message != NULL ? strlen(message) : strlen(msg)),
274 SILC_MESSAGE_FLAG_ACTION | SILC_MESSAGE_FLAG_UTF8 |
275 (sign ? SILC_MESSAGE_FLAG_SIGNED : 0))) {
276 if (g_hash_table_lookup(optlist, "sign"))
277 signal_emit("message silc signed_own_private_action", 3,
278 server, msg, target);
280 signal_emit("message silc own_private_action", 3,
281 server, msg, target);
286 cmd_params_free(free_arg);
290 /* ME local command. */
292 static void command_me(const char *data, SILC_SERVER_REC *server,
297 CMD_SILC_SERVER(server);
298 if (!IS_SILC_SERVER(server) || !server->connected)
299 cmd_return_error(CMDERR_NOT_CONNECTED);
301 if (!IS_SILC_CHANNEL(item) && !IS_SILC_QUERY(item))
302 cmd_return_error(CMDERR_NOT_JOINED);
304 if (IS_SILC_CHANNEL(item))
305 tmpcmd = g_strdup_printf("-channel %s %s", item->visible_name, data);
307 tmpcmd = g_strdup_printf("%s %s", item->visible_name, data);
309 command_action(tmpcmd, server, item);
313 /* NOTICE local command. */
315 static void command_notice(const char *data, SILC_SERVER_REC *server,
320 char *message = NULL;
325 CMD_SILC_SERVER(server);
326 if (!IS_SILC_SERVER(server) || !server->connected)
327 cmd_return_error(CMDERR_NOT_CONNECTED);
329 if ((item != NULL) && (!IS_SILC_CHANNEL(item) && !IS_SILC_QUERY(item)))
330 cmd_return_error(CMDERR_NOT_JOINED);
332 /* Now parse all arguments */
333 if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS |
335 "notice", &optlist, &target, &msg))
338 if (*target == '\0' || *msg == '\0')
339 cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
341 if (strcmp(target, "*") == 0) {
342 /* send to active channel/query */
344 cmd_param_error(CMDERR_NOT_JOINED);
346 target_type = IS_SILC_CHANNEL(item) ?
347 SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
348 target = (char *)window_item_get_target(item);
349 } else if (g_hash_table_lookup(optlist, "channel") != NULL)
350 target_type = SEND_TARGET_CHANNEL;
352 target_type = SEND_TARGET_NICK;
355 if (!silc_term_utf8()) {
356 int len = silc_utf8_encoded_len(msg, strlen(msg),
358 message = silc_calloc(len + 1, sizeof(*message));
359 g_return_if_fail(message != NULL);
360 silc_utf8_encode(msg, strlen(msg), SILC_STRING_LOCALE,
364 sign = (g_hash_table_lookup(optlist, "sign") ? TRUE :
365 settings_get_bool("sign_channel_messages") ? TRUE : FALSE);
367 if (target != NULL) {
368 if (target_type == SEND_TARGET_CHANNEL) {
369 if (silc_send_channel(server, target, (message != NULL ? message : msg),
370 SILC_MESSAGE_FLAG_NOTICE | SILC_MESSAGE_FLAG_UTF8 |
371 (sign ? SILC_MESSAGE_FLAG_SIGNED : 0))) {
372 if (g_hash_table_lookup(optlist, "sign"))
373 signal_emit("message silc signed_own_notice", 3, server, msg, target);
375 signal_emit("message silc own_notice", 3, server, msg, target);
378 if (silc_send_msg(server, target, (message != NULL ? message : msg),
379 (message != NULL ? strlen(message) : strlen(msg)),
380 SILC_MESSAGE_FLAG_NOTICE | SILC_MESSAGE_FLAG_UTF8 |
381 (sign ? SILC_MESSAGE_FLAG_SIGNED : 0))) {
382 if (g_hash_table_lookup(optlist, "sign"))
383 signal_emit("message silc signed_own_private_notice", 3,
384 server, msg, target);
386 signal_emit("message silc own_private_notice", 3,
387 server, msg, target);
392 cmd_params_free(free_arg);
396 /* AWAY local command. Sends UMODE command that sets the SILC_UMODE_GONE
399 bool silc_set_away(const char *reason, SILC_SERVER_REC *server)
403 if (!IS_SILC_SERVER(server) || !server->connected)
406 if (*reason == '\0') {
407 /* Remove any possible away message */
408 silc_client_set_away_message(silc_client, server->conn, NULL);
411 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
414 /* Set the away message */
415 silc_client_set_away_message(silc_client, server->conn, (char *)reason);
418 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
419 SILCTXT_SET_AWAY, reason);
422 server->usermode_away = set;
423 g_free_and_null(server->away_reason);
425 server->away_reason = g_strdup((char *)reason);
427 signal_emit("away mode changed", 1, server);
432 static void command_away(const char *data, SILC_SERVER_REC *server,
435 CMD_SILC_SERVER(server);
437 if (!IS_SILC_SERVER(server) || !server->connected)
438 cmd_return_error(CMDERR_NOT_CONNECTED);
440 g_free_and_null(server->away_reason);
441 if ((data) && (*data != '\0'))
442 server->away_reason = g_strdup(data);
444 silc_command_exec(server, "UMODE",
445 (server->away_reason != NULL) ? "+g" : "-g");
449 SILC_SERVER_REC *server;
450 int type; /* 1 = msg, 2 = channel */
454 /* Key agreement callback that is called after the key agreement protocol
455 has been performed. This is called also if error occured during the
456 key agreement protocol. The `key' is the allocated key material and
457 the caller is responsible of freeing it. The `key' is NULL if error
458 has occured. The application can freely use the `key' to whatever
459 purpose it needs. See lib/silcske/silcske.h for the definition of
460 the SilcSKEKeyMaterial structure. */
462 static void keyagr_completion(SilcClient client,
463 SilcClientConnection conn,
464 SilcClientEntry client_entry,
465 SilcKeyAgreementStatus status,
466 SilcSKEKeyMaterial key,
469 KeyInternal i = (KeyInternal)context;
472 case SILC_KEY_AGREEMENT_OK:
473 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
474 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
477 /* Set the private key for this client */
478 silc_client_del_private_message_key(client, conn, client_entry);
479 silc_client_add_private_message_key_ske(client, conn, client_entry,
481 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
482 SILCTXT_KEY_AGREEMENT_PRIVMSG,
483 client_entry->nickname);
484 silc_ske_free_key_material(key);
489 case SILC_KEY_AGREEMENT_ERROR:
490 case SILC_KEY_AGREEMENT_NO_MEMORY:
491 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
492 SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
495 case SILC_KEY_AGREEMENT_FAILURE:
496 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
497 SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
500 case SILC_KEY_AGREEMENT_TIMEOUT:
501 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
502 SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
505 case SILC_KEY_AGREEMENT_ABORTED:
506 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
507 SILCTXT_KEY_AGREEMENT_ABORTED, client_entry->nickname);
510 case SILC_KEY_AGREEMENT_ALREADY_STARTED:
511 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
512 SILCTXT_KEY_AGREEMENT_ALREADY_STARTED,
513 client_entry->nickname);
516 case SILC_KEY_AGREEMENT_SELF_DENIED:
517 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
518 SILCTXT_KEY_AGREEMENT_SELF_DENIED);
529 /* Local command KEY. This command is used to set and unset private
530 keys for channels, set and unset private keys for private messages
531 with remote clients and to send key agreement requests and
532 negotiate the key agreement protocol with remote client. The
533 key agreement is supported only to negotiate private message keys,
534 it currently cannot be used to negotiate private keys for channels,
535 as it is not convenient for that purpose. */
538 SILC_SERVER_REC *server;
544 /* Callback to be called after client information is resolved from the
547 static void silc_client_command_key_get_clients(SilcClient client,
548 SilcClientConnection conn,
553 KeyGetClients internal = (KeyGetClients)context;
556 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s",
558 silc_free(internal->data);
559 silc_free(internal->nick);
564 signal_emit("command key", 3, internal->data, internal->server,
567 silc_free(internal->data);
568 silc_free(internal->nick);
572 static void command_key(const char *data, SILC_SERVER_REC *server,
575 SilcClientConnection conn;
576 SilcClientEntry client_entry = NULL;
578 SILC_CHANNEL_REC *chanrec = NULL;
579 SilcChannelEntry channel_entry = NULL;
580 char nickname[128 + 1], *tmp;
581 int command = 0, port = 0, type = 0;
582 char *hostname = NULL;
583 KeyInternal internal = NULL;
585 unsigned char **argv;
586 SilcUInt32 *argv_lens, *argv_types;
587 char *bindhost = NULL;
588 SilcChannelEntry ch = NULL;
590 SilcBool udp = FALSE;
593 CMD_SILC_SERVER(server);
595 if (!server || !IS_SILC_SERVER(server) || !server->connected)
596 cmd_return_error(CMDERR_NOT_CONNECTED);
600 /* Now parse all arguments */
601 tmp = g_strconcat("KEY", " ", data, NULL);
602 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
606 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
609 if (!strcasecmp(argv[1], "msg"))
611 if (!strcasecmp(argv[1], "channel"))
615 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
618 if (argv[2][0] == '*') {
619 strcpy(nickname, "*");
621 /* Parse the typed nickname. */
622 if (!silc_parse_userfqdn(argv[2], nickname, sizeof(nickname), NULL, 0)) {
623 printformat_module("fe-common/silc", server, NULL,
624 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
628 /* Find client entry */
629 clients = silc_client_get_clients_local(silc_client, conn, nickname,
632 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
633 inter->server = server;
634 inter->data = strdup(data);
635 inter->nick = strdup(nickname);
637 silc_client_get_clients(silc_client, conn, nickname, argv[2],
638 silc_client_command_key_get_clients, inter);
642 client_entry = silc_dlist_get(clients);
643 silc_client_list_free(silc_client, conn, clients);
648 /* Get channel entry */
651 if (argv[2][0] == '*') {
652 if (!conn->current_channel) {
654 cmd_return_error(CMDERR_NOT_JOINED);
656 name = conn->current_channel->channel_name;
661 chanrec = silc_channel_find(server, name);
662 if (chanrec == NULL) {
664 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
666 channel_entry = chanrec->entry;
670 if (!strcasecmp(argv[3], "set")) {
674 char *cipher = NULL, *hmac = NULL;
681 if (type == 1 && client_entry) {
682 /* Set private message key */
683 silc_client_del_private_message_key(silc_client, conn, client_entry);
684 silc_client_add_private_message_key(silc_client, conn, client_entry,
686 argv[4], argv_lens[4]);
687 } else if (type == 2) {
688 /* Set private channel key */
689 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
690 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
691 SILCTXT_CH_PRIVATE_KEY_NOMODE,
692 channel_entry->channel_name);
696 if (!silc_client_add_channel_private_key(silc_client, conn,
700 argv_lens[4], NULL)) {
701 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
702 SILCTXT_CH_PRIVATE_KEY_ERROR,
703 channel_entry->channel_name);
707 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
708 SILCTXT_CH_PRIVATE_KEY_ADD,
709 channel_entry->channel_name);
717 if (!strcasecmp(argv[3], "unset")) {
720 if (type == 1 && client_entry) {
721 /* Unset private message key */
722 silc_client_del_private_message_key(silc_client, conn, client_entry);
723 } else if (type == 2) {
724 /* Unset channel key(s) */
728 silc_client_del_channel_private_keys(silc_client, conn,
732 number = atoi(argv[4]);
733 ckeys = silc_client_list_channel_private_keys(silc_client, conn,
738 if (!number || number > silc_dlist_count(ckeys)) {
739 silc_dlist_uninit(ckeys);
743 for (i = 0; i < number; i++)
744 ch = silc_dlist_get(ckeys);
748 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
750 silc_dlist_uninit(ckeys);
759 if (!strcasecmp(argv[3], "list")) {
763 SilcPrivateMessageKeys keys;
764 SilcUInt32 keys_count;
768 keys = silc_client_list_private_message_keys(silc_client, conn,
773 /* list the private message key(s) */
774 if (nickname[0] == '*') {
775 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
776 SILCTXT_PRIVATE_KEY_LIST);
777 for (k = 0; k < keys_count; k++) {
778 memset(buf, 0, sizeof(buf));
779 strncat(buf, " ", 2);
780 len = strlen(keys[k].client_entry->nickname);
781 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
783 for (i = 0; i < 30 - len; i++)
787 len = strlen(keys[k].cipher);
788 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
790 for (i = 0; i < 14 - len; i++)
795 strcat(buf, "<hidden>");
797 strcat(buf, "*generated*");
799 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
802 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
803 SILCTXT_PRIVATE_KEY_LIST_NICK,
804 client_entry->nickname);
805 for (k = 0; k < keys_count; k++) {
806 if (keys[k].client_entry != client_entry)
809 memset(buf, 0, sizeof(buf));
810 strncat(buf, " ", 2);
811 len = strlen(keys[k].client_entry->nickname);
812 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
814 for (i = 0; i < 30 - len; i++)
818 len = strlen(keys[k].cipher);
819 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
821 for (i = 0; i < 14 - len; i++)
826 strcat(buf, "<hidden>");
828 strcat(buf, "*generated*");
830 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
834 silc_client_free_private_message_keys(keys, keys_count);
836 } else if (type == 2) {
840 ckeys = silc_client_list_channel_private_keys(silc_client, conn,
843 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
844 SILCTXT_CH_PRIVATE_KEY_LIST,
845 channel_entry->channel_name);
850 for (k = 0; k < keys_count; k++) {
851 memset(buf, 0, sizeof(buf));
852 strncat(buf, " ", 2);
854 len = strlen(silc_cipher_get_name(keys[k]->cipher));
855 strncat(buf, silc_cipher_get_name(keys[k]->cipher),
856 len > 16 ? 16 : len);
858 for (i = 0; i < 16 - len; i++)
862 len = strlen(silc_hmac_get_name(keys[k]->hmac));
863 strncat(buf, silc_hmac_get_name(keys[k]->hmac), len > 16 ? 16 : len);
865 for (i = 0; i < 16 - len; i++)
869 strcat(buf, "<hidden>");
871 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
874 silc_client_free_channel_private_keys(keys, keys_count);
881 /* Send command is used to send key agreement */
882 if (!strcasecmp(argv[3], "agreement")) {
888 if (!strcasecmp(argv[5], "UDP"))
891 port = atoi(argv[5]);
896 internal = silc_calloc(1, sizeof(*internal));
897 internal->type = type;
898 internal->server = server;
901 if (settings_get_bool("use_auto_addr")) {
902 hostname = (char *)settings_get_str("auto_public_ip");
904 /* If the hostname isn't set, treat this case as if auto_public_ip
906 if ((hostname) && (*hostname == '\0')) {
909 bindhost = (char *)settings_get_str("auto_bind_ip");
911 /* if the bind_ip isn't set, but the public_ip IS, then assume then
912 public_ip is the same value as the bind_ip. */
913 if ((bindhost) && (*bindhost == '\0'))
915 port = settings_get_int("auto_bind_port");
917 } /* if use_auto_addr */
921 /* Start command is used to start key agreement (after receiving the
922 key_agreement client operation). */
923 if (!strcasecmp(argv[3], "negotiate")) {
929 if (!strcasecmp(argv[5], "UDP"))
932 port = atoi(argv[5]);
937 internal = silc_calloc(1, sizeof(*internal));
938 internal->type = type;
939 internal->server = server;
942 /* Change current channel private key */
943 if (!strcasecmp(argv[3], "change")) {
946 /* Unset channel key(s) */
949 ckeys = silc_client_list_channel_private_keys(silc_client, conn,
956 if (chanrec->cur_key >= silc_dlist_count(ckeys))
957 chanrec->cur_key = 0;
961 number = atoi(argv[4]);
962 if (!number || number > silc_dlist_count(ckeys))
963 chanrec->cur_key = 0;
965 chanrec->cur_key = number - 1;
968 for (i = 0; i < chanrec->cur_key; i++)
969 ch = silc_dlist_get(ckeys);
973 /* Set the current channel private key */
974 silc_client_current_channel_private_key(silc_client, conn,
976 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
977 SILCTXT_CH_PRIVATE_KEY_CHANGE, i + 1,
978 channel_entry->channel_name);
980 silc_dlist_uninit(ckeys);
986 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
987 "Usage: /KEY msg|channel <nickname|channel> "
988 "set|unset|agreement|negotiate [<arguments>]");
992 if (command == 4 && client_entry) {
993 SilcClientConnectionParams params;
995 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
996 SILCTXT_KEY_AGREEMENT, argv[2]);
997 internal->responder = TRUE;
999 memset(¶ms, 0, sizeof(params));
1000 params.local_ip = hostname;
1001 params.bind_ip = bindhost;
1002 params.local_port = port;
1004 params.timeout_secs = settings_get_int("key_exchange_timeout_secs");
1006 silc_client_send_key_agreement(
1007 silc_client, conn, client_entry, ¶ms,
1008 irssi_pubkey, irssi_privkey,
1009 keyagr_completion, internal);
1011 silc_free(internal);
1015 if (command == 5 && client_entry && hostname) {
1016 SilcClientConnectionParams params;
1018 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1019 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
1020 internal->responder = FALSE;
1022 memset(¶ms, 0, sizeof(params));
1024 if (settings_get_bool("use_auto_addr")) {
1025 params.local_ip = (char *)settings_get_str("auto_public_ip");
1026 if ((params.local_ip) && (*params.local_ip == '\0')) {
1027 params.local_ip = silc_net_localip();
1029 params.bind_ip = (char *)settings_get_str("auto_bind_ip");
1030 if ((params.bind_ip) && (*params.bind_ip == '\0'))
1031 params.bind_ip = NULL;
1032 params.local_port = settings_get_int("auto_bind_port");
1035 if (!params.local_ip)
1036 params.local_ip = silc_net_localip();
1039 params.timeout_secs = settings_get_int("key_exchange_timeout_secs");
1041 silc_client_perform_key_agreement(silc_client, conn, client_entry, ¶ms,
1042 irssi_pubkey, irssi_privkey,
1043 hostname, port, keyagr_completion,
1053 void silc_list_key(const char *pub_filename, int verbose)
1055 SilcPublicKey public_key;
1056 SilcPublicKeyIdentifier ident;
1057 char *fingerprint, *babbleprint;
1061 SilcUInt32 key_len = 0;
1062 int is_server_key = (strstr(pub_filename, "serverkeys") != NULL);
1064 if (silc_pkcs_load_public_key((char *)pub_filename, &public_key,
1065 SILC_PKCS_FILE_PEM) == FALSE)
1066 if (silc_pkcs_load_public_key((char *)pub_filename, &public_key,
1067 SILC_PKCS_FILE_BIN) == FALSE) {
1068 printformat_module("fe-common/silc", NULL, NULL,
1069 MSGLEVEL_CRAP, SILCTXT_LISTKEY_LOADPUB,
1074 ident = silc_pkcs_decode_identifier(public_key->identifier);
1076 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1077 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1078 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1080 if (silc_pkcs_alloc(public_key->name, &pkcs)) {
1081 key_len = silc_pkcs_public_key_set(pkcs, public_key);
1082 silc_pkcs_free(pkcs);
1085 printformat_module("fe-common/silc", NULL, NULL,
1086 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_FILE,
1090 printformat_module("fe-common/silc", NULL, NULL,
1091 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_ALG,
1093 if (key_len && verbose)
1094 printformat_module("fe-common/silc", NULL, NULL,
1095 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_BITS,
1096 (unsigned int)key_len);
1097 if (ident->realname && (!is_server_key || verbose))
1098 printformat_module("fe-common/silc", NULL, NULL,
1099 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_RN,
1101 if (ident->username && verbose)
1102 printformat_module("fe-common/silc", NULL, NULL,
1103 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_UN,
1105 if (ident->host && (is_server_key || verbose))
1106 printformat_module("fe-common/silc", NULL, NULL,
1107 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_HN,
1109 if (ident->email && verbose)
1110 printformat_module("fe-common/silc", NULL, NULL,
1111 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_EMAIL,
1113 if (ident->org && verbose)
1114 printformat_module("fe-common/silc", NULL, NULL,
1115 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_ORG,
1117 if (ident->country && verbose)
1118 printformat_module("fe-common/silc", NULL, NULL,
1119 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_C,
1123 printformat_module("fe-common/silc", NULL, NULL,
1124 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_FINGER,
1126 printformat_module("fe-common/silc", NULL, NULL,
1127 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_BABL,
1131 silc_free(fingerprint);
1132 silc_free(babbleprint);
1134 silc_pkcs_public_key_free(public_key);
1135 silc_pkcs_free_identifier(ident);
1139 void silc_list_keys_in_dir(const char *dirname, const char *where)
1142 struct dirent *entry;
1144 dir = opendir(dirname);
1147 cmd_return_error(CMDERR_ERRNO);
1149 printformat_module("fe-common/silc", NULL, NULL,
1150 MSGLEVEL_CRAP, SILCTXT_LISTKEY_LIST,
1155 while ((entry = readdir(dir)) != NULL) {
1156 /* try to open everything that isn't a directory */
1160 snprintf(filename, sizeof(filename) - 1, "%s/%s", dirname, entry->d_name);
1161 if (!stat(filename, &buf) && S_ISREG(buf.st_mode))
1162 silc_list_key(filename, FALSE);
1168 void silc_list_file(const char *filename)
1174 snprintf(path, sizeof(path) - 1, "%s", filename);
1175 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1178 snprintf(path, sizeof(path) - 1, "%s/%s", get_irssi_dir(), filename);
1179 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1182 snprintf(path,sizeof(path) - 1, "%s/clientkeys/%s", get_irssi_dir(),
1184 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1187 snprintf(path,sizeof(path) - 1, "%s/serverkeys/%s", get_irssi_dir(),
1189 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1196 silc_list_key(path, TRUE);
1201 /* Lists locally saved client and server public keys. */
1202 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
1205 GHashTable *optlist;
1210 if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS |
1211 PARAM_FLAG_GETREST, "listkeys", &optlist,
1215 if (*filename != '\0') {
1217 silc_list_file(filename);
1220 int clients, servers;
1222 clients = (g_hash_table_lookup(optlist, "clients") != NULL);
1223 servers = (g_hash_table_lookup(optlist, "servers") != NULL);
1225 if (!(clients || servers))
1226 clients = servers = 1;
1229 snprintf(dirname, sizeof(dirname) - 1, "%s/serverkeys", get_irssi_dir());
1230 silc_list_keys_in_dir(dirname, "server");
1234 snprintf(dirname, sizeof(dirname) - 1, "%s/clientkeys", get_irssi_dir());
1235 silc_list_keys_in_dir(dirname, "client");
1238 cmd_params_free(free_arg);
1241 void silc_channels_init(void)
1243 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1244 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1245 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1246 signal_add("gui exit", (SIGNAL_FUNC) sig_gui_quit);
1247 signal_add("mime", (SIGNAL_FUNC) sig_mime);
1249 command_bind_silc("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1250 command_bind_silc("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1251 command_bind_silc("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1252 command_bind_silc("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1253 command_bind_silc("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1254 command_bind_silc("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1255 // command_bind("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
1257 //command_set_options("listkeys", "clients servers");
1258 command_set_options("action", "sign channel");
1259 command_set_options("notice", "sign channel");
1261 silc_nicklist_init();
1264 void silc_channels_deinit(void)
1266 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1267 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1268 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1269 signal_remove("gui exit", (SIGNAL_FUNC) sig_gui_quit);
1270 signal_remove("mime", (SIGNAL_FUNC) sig_mime);
1272 command_unbind("part", (SIGNAL_FUNC) command_part);
1273 command_unbind("me", (SIGNAL_FUNC) command_me);
1274 command_unbind("action", (SIGNAL_FUNC) command_action);
1275 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1276 command_unbind("away", (SIGNAL_FUNC) command_away);
1277 command_unbind("key", (SIGNAL_FUNC) command_key);
1278 // command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
1280 silc_nicklist_deinit();