2 silc-channels.c : irssi
4 Copyright (C) 2000 - 2001 Timo Sirainen
5 Pekka Riikonen <priikone@poseidon.pspt.fi>
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 "window-item-def.h"
43 #include "fe-common/core/printtext.h"
44 #include "fe-common/silc/module-formats.h"
46 #include "silc-commands.h"
48 void sig_mime(SILC_SERVER_REC *server, SILC_CHANNEL_REC *channel,
49 const char *blob, const char *nick, int verified)
51 char type[128], enc[128];
52 unsigned char *data, *message;
53 SilcUInt32 data_len, message_len;
55 if (!(IS_SILC_SERVER(server)))
58 message = silc_unescape_data(blob, &message_len);
60 memset(type, 0, sizeof(type));
61 memset(enc, 0, sizeof(enc));
63 if (!silc_mime_parse(message, message_len, NULL, 0, type, sizeof(type) - 1,
64 enc, sizeof(enc) - 1, &data, &data_len)) {
69 printformat_module("fe-common/silc", server,
70 channel == NULL ? NULL : channel->name,
71 MSGLEVEL_CRAP, SILCTXT_MESSAGE_DATA,
72 nick == NULL ? "[<unknown>]" : nick, type);
78 SILC_CHANNEL_REC *silc_channel_create(SILC_SERVER_REC *server,
80 const char *visible_name,
83 SILC_CHANNEL_REC *rec;
85 g_return_val_if_fail(server == NULL || IS_SILC_SERVER(server), NULL);
86 g_return_val_if_fail(name != NULL, NULL);
88 rec = g_new0(SILC_CHANNEL_REC, 1);
89 rec->chat_type = SILC_PROTOCOL;
90 channel_init((CHANNEL_REC *)rec, (SERVER_REC *)server, name, name,
95 static void sig_channel_destroyed(SILC_CHANNEL_REC *channel)
97 if (!IS_SILC_CHANNEL(channel))
99 if (channel->server && channel->server->disconnected)
102 if (channel->server != NULL && !channel->left && !channel->kicked) {
103 /* destroying channel record without actually
104 having left the channel yet */
105 silc_command_exec(channel->server, "LEAVE", channel->name);
109 static void silc_channels_join(SILC_SERVER_REC *server,
110 const char *channels, int automatic)
113 SILC_CHANNEL_REC *chanrec;
115 list = g_strsplit(channels, ",", -1);
116 for (tmp = list; *tmp != NULL; tmp++) {
117 chanrec = silc_channel_find(server, *tmp);
121 silc_command_exec(server, "JOIN", *tmp);
127 static void sig_connected(SILC_SERVER_REC *server)
129 if (IS_SILC_SERVER(server))
130 server->channels_join = (void *) silc_channels_join;
133 /* "server quit" signal from the core to indicate that QUIT command
136 static void sig_server_quit(SILC_SERVER_REC *server, const char *msg)
138 if (IS_SILC_SERVER(server) && server->conn && server->conn->sock)
139 silc_command_exec(server, "QUIT", msg);
142 static void sig_gui_quit(SILC_SERVER_REC *server, const char *msg)
144 silc_client_stop(silc_client);
147 /* Find Irssi channel entry by SILC channel entry */
149 SILC_CHANNEL_REC *silc_channel_find_entry(SILC_SERVER_REC *server,
150 SilcChannelEntry entry)
154 g_return_val_if_fail(IS_SILC_SERVER(server), NULL);
156 for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
157 SILC_CHANNEL_REC *rec = tmp->data;
159 if (rec->entry == entry)
166 /* PART (LEAVE) command. */
168 static void command_part(const char *data, SILC_SERVER_REC *server,
171 SILC_CHANNEL_REC *chanrec;
174 CMD_SILC_SERVER(server);
176 if (!IS_SILC_SERVER(server) || !server->connected)
177 cmd_return_error(CMDERR_NOT_CONNECTED);
179 if (!strcmp(data, "*") || *data == '\0') {
180 if (!IS_SILC_CHANNEL(item))
181 cmd_return_error(CMDERR_NOT_JOINED);
182 data = item->visible_name;
185 chanrec = silc_channel_find(server, data);
187 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
189 memset(userhost, 0, sizeof(userhost));
190 snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
191 server->conn->local_entry->username,
192 server->conn->local_entry->hostname);
193 signal_emit("message part", 5, server, chanrec->name,
194 server->nick, userhost, "");
196 chanrec->left = TRUE;
197 silc_command_exec(server, "LEAVE", chanrec->name);
200 channel_destroy(CHANNEL(chanrec));
204 /* ACTION local command. */
206 static void command_action(const char *data, SILC_SERVER_REC *server,
211 char *message = NULL;
215 CMD_SILC_SERVER(server);
216 if (!IS_SILC_SERVER(server) || !server->connected)
217 cmd_return_error(CMDERR_NOT_CONNECTED);
219 if ((item != NULL) && (!IS_SILC_CHANNEL(item) && !IS_SILC_QUERY(item)))
220 cmd_return_error(CMDERR_NOT_JOINED);
222 /* Now parse all arguments */
223 if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS |
225 "action", &optlist, &target, &msg))
228 if (*target == '\0' || *msg == '\0')
229 cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
231 if (strcmp(target, "*") == 0) {
232 /* send to active channel/query */
234 cmd_param_error(CMDERR_NOT_JOINED);
236 target_type = IS_SILC_CHANNEL(item) ?
237 SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
238 target = (char *)window_item_get_target(item);
239 } else if (g_hash_table_lookup(optlist, "channel") != NULL)
240 target_type = SEND_TARGET_CHANNEL;
242 target_type = SEND_TARGET_NICK;
245 if (!silc_term_utf8()) {
246 int len = silc_utf8_encoded_len(msg, strlen(msg),
247 SILC_STRING_LANGUAGE);
248 message = silc_calloc(len + 1, sizeof(*message));
249 g_return_if_fail(message != NULL);
250 silc_utf8_encode(msg, strlen(msg), SILC_STRING_LANGUAGE,
254 if (target != NULL) {
255 if (target_type == SEND_TARGET_CHANNEL) {
256 if (silc_send_channel(server, target, (message != NULL ? message : msg),
257 SILC_MESSAGE_FLAG_ACTION | SILC_MESSAGE_FLAG_UTF8 |
258 (g_hash_table_lookup(optlist, "sign") != NULL ?
259 SILC_MESSAGE_FLAG_SIGNED : 0))) {
260 if (g_hash_table_lookup(optlist, "sign"))
261 signal_emit("message silc signed_own_action", 3, server, msg, target);
263 signal_emit("message silc own_action", 3, server, msg, target);
266 if (silc_send_msg(server, target, (message != NULL ? message : msg),
267 (message != NULL ? strlen(message) : strlen(msg)),
268 SILC_MESSAGE_FLAG_ACTION | SILC_MESSAGE_FLAG_UTF8 |
269 (g_hash_table_lookup(optlist, "sign") != NULL ?
270 SILC_MESSAGE_FLAG_SIGNED : 0))) {
271 if (g_hash_table_lookup(optlist, "sign"))
272 signal_emit("message silc signed_own_private_action", 3,
273 server, msg, target);
275 signal_emit("message silc own_private_action", 3,
276 server, msg, target);
281 cmd_params_free(free_arg);
285 /* ME local command. */
287 static void command_me(const char *data, SILC_SERVER_REC *server,
292 CMD_SILC_SERVER(server);
293 if (!IS_SILC_SERVER(server) || !server->connected)
294 cmd_return_error(CMDERR_NOT_CONNECTED);
296 if (!IS_SILC_CHANNEL(item) && !IS_SILC_QUERY(item))
297 cmd_return_error(CMDERR_NOT_JOINED);
299 if (IS_SILC_CHANNEL(item))
300 tmpcmd = g_strdup_printf("-channel %s %s", item->visible_name, data);
302 tmpcmd = g_strdup_printf("%s %s", item->visible_name, data);
304 command_action(tmpcmd, server, item);
308 /* NOTICE local command. */
310 static void command_notice(const char *data, SILC_SERVER_REC *server,
315 char *message = NULL;
319 CMD_SILC_SERVER(server);
320 if (!IS_SILC_SERVER(server) || !server->connected)
321 cmd_return_error(CMDERR_NOT_CONNECTED);
323 if ((item != NULL) && (!IS_SILC_CHANNEL(item) && !IS_SILC_QUERY(item)))
324 cmd_return_error(CMDERR_NOT_JOINED);
326 /* Now parse all arguments */
327 if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS |
329 "notice", &optlist, &target, &msg))
332 if (*target == '\0' || *msg == '\0')
333 cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
335 if (strcmp(target, "*") == 0) {
336 /* send to active channel/query */
338 cmd_param_error(CMDERR_NOT_JOINED);
340 target_type = IS_SILC_CHANNEL(item) ?
341 SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
342 target = (char *)window_item_get_target(item);
343 } else if (g_hash_table_lookup(optlist, "channel") != NULL)
344 target_type = SEND_TARGET_CHANNEL;
346 target_type = SEND_TARGET_NICK;
349 if (!silc_term_utf8()) {
350 int len = silc_utf8_encoded_len(msg, strlen(msg),
351 SILC_STRING_LANGUAGE);
352 message = silc_calloc(len + 1, sizeof(*message));
353 g_return_if_fail(message != NULL);
354 silc_utf8_encode(msg, strlen(msg), SILC_STRING_LANGUAGE,
358 if (target != NULL) {
359 if (target_type == SEND_TARGET_CHANNEL) {
360 if (silc_send_channel(server, target, (message != NULL ? message : msg),
361 SILC_MESSAGE_FLAG_NOTICE | SILC_MESSAGE_FLAG_UTF8 |
362 (g_hash_table_lookup(optlist, "sign") != NULL ?
363 SILC_MESSAGE_FLAG_SIGNED : 0))) {
364 if (g_hash_table_lookup(optlist, "sign"))
365 signal_emit("message silc signed_own_notice", 3, server, msg, target);
367 signal_emit("message silc own_notice", 3, server, msg, target);
370 if (silc_send_msg(server, target, (message != NULL ? message : msg),
371 (message != NULL ? strlen(message) : strlen(msg)),
372 SILC_MESSAGE_FLAG_NOTICE | SILC_MESSAGE_FLAG_UTF8 |
373 (g_hash_table_lookup(optlist, "sign") != NULL ?
374 SILC_MESSAGE_FLAG_SIGNED : 0))) {
375 if (g_hash_table_lookup(optlist, "sign"))
376 signal_emit("message silc signed_own_private_notice", 3,
377 server, msg, target);
379 signal_emit("message silc own_private_notice", 3,
380 server, msg, target);
385 cmd_params_free(free_arg);
389 /* AWAY local command. Sends UMODE command that sets the SILC_UMODE_GONE
392 bool silc_set_away(const char *reason, SILC_SERVER_REC *server)
396 if (!IS_SILC_SERVER(server) || !server->connected)
399 if (*reason == '\0') {
400 /* Remove any possible away message */
401 silc_client_set_away_message(silc_client, server->conn, NULL);
404 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
407 /* Set the away message */
408 silc_client_set_away_message(silc_client, server->conn, (char *)reason);
411 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
412 SILCTXT_SET_AWAY, reason);
415 server->usermode_away = set;
416 g_free_and_null(server->away_reason);
418 server->away_reason = g_strdup((char *)reason);
420 signal_emit("away mode changed", 1, server);
425 static void command_away(const char *data, SILC_SERVER_REC *server,
428 CMD_SILC_SERVER(server);
430 if (!IS_SILC_SERVER(server) || !server->connected)
431 cmd_return_error(CMDERR_NOT_CONNECTED);
433 g_free_and_null(server->away_reason);
434 if ((data) && (*data != '\0'))
435 server->away_reason = g_strdup(data);
437 silc_command_exec(server, "UMODE",
438 (server->away_reason != NULL) ? "+g" : "-g");
442 int type; /* 1 = msg, 2 = channel */
444 SILC_SERVER_REC *server;
447 /* Key agreement callback that is called after the key agreement protocol
448 has been performed. This is called also if error occured during the
449 key agreement protocol. The `key' is the allocated key material and
450 the caller is responsible of freeing it. The `key' is NULL if error
451 has occured. The application can freely use the `key' to whatever
452 purpose it needs. See lib/silcske/silcske.h for the definition of
453 the SilcSKEKeyMaterial structure. */
455 static void keyagr_completion(SilcClient client,
456 SilcClientConnection conn,
457 SilcClientEntry client_entry,
458 SilcKeyAgreementStatus status,
459 SilcSKEKeyMaterial *key,
462 KeyInternal i = (KeyInternal)context;
465 case SILC_KEY_AGREEMENT_OK:
466 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
467 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
470 /* Set the private key for this client */
471 silc_client_del_private_message_key(client, conn, client_entry);
472 silc_client_add_private_message_key_ske(client, conn, client_entry,
473 NULL, NULL, key, i->responder);
474 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
475 SILCTXT_KEY_AGREEMENT_PRIVMSG,
476 client_entry->nickname);
477 silc_ske_free_key_material(key);
482 case SILC_KEY_AGREEMENT_ERROR:
483 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
484 SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
487 case SILC_KEY_AGREEMENT_FAILURE:
488 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
489 SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
492 case SILC_KEY_AGREEMENT_TIMEOUT:
493 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
494 SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
497 case SILC_KEY_AGREEMENT_ABORTED:
498 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
499 SILCTXT_KEY_AGREEMENT_ABORTED, client_entry->nickname);
502 case SILC_KEY_AGREEMENT_ALREADY_STARTED:
503 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
504 SILCTXT_KEY_AGREEMENT_ALREADY_STARTED,
505 client_entry->nickname);
508 case SILC_KEY_AGREEMENT_SELF_DENIED:
509 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
510 SILCTXT_KEY_AGREEMENT_SELF_DENIED);
521 /* Local command KEY. This command is used to set and unset private
522 keys for channels, set and unset private keys for private messages
523 with remote clients and to send key agreement requests and
524 negotiate the key agreement protocol with remote client. The
525 key agreement is supported only to negotiate private message keys,
526 it currently cannot be used to negotiate private keys for channels,
527 as it is not convenient for that purpose. */
530 SILC_SERVER_REC *server;
536 /* Callback to be called after client information is resolved from the
539 static void silc_client_command_key_get_clients(SilcClient client,
540 SilcClientConnection conn,
541 SilcClientEntry *clients,
542 SilcUInt32 clients_count,
545 KeyGetClients internal = (KeyGetClients)context;
548 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s",
550 silc_free(internal->data);
551 silc_free(internal->nick);
556 signal_emit("command key", 3, internal->data, internal->server,
559 silc_free(internal->data);
560 silc_free(internal->nick);
564 static void command_key(const char *data, SILC_SERVER_REC *server,
567 SilcClientConnection conn;
568 SilcClientEntry *entrys, client_entry = NULL;
569 SilcUInt32 entry_count;
570 SILC_CHANNEL_REC *chanrec = NULL;
571 SilcChannelEntry channel_entry = NULL;
572 char *nickname = NULL, *tmp;
573 int command = 0, port = 0, type = 0;
574 char *hostname = NULL;
575 KeyInternal internal = NULL;
577 unsigned char **argv;
578 SilcUInt32 *argv_lens, *argv_types;
579 char *bindhost = NULL;
581 CMD_SILC_SERVER(server);
583 if (!server || !IS_SILC_SERVER(server) || !server->connected)
584 cmd_return_error(CMDERR_NOT_CONNECTED);
588 /* Now parse all arguments */
589 tmp = g_strconcat("KEY", " ", data, NULL);
590 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
594 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
597 if (!strcasecmp(argv[1], "msg"))
599 if (!strcasecmp(argv[1], "channel"))
603 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
606 if (argv[2][0] == '*') {
607 nickname = strdup("*");
609 /* Parse the typed nickname. */
610 if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
611 printformat_module("fe-common/silc", server, NULL,
612 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
616 /* Find client entry */
617 entrys = silc_client_get_clients_local(silc_client, conn, nickname,
618 argv[2], &entry_count);
620 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
621 inter->server = server;
622 inter->data = strdup(data);
623 inter->nick = strdup(nickname);
625 silc_client_get_clients(silc_client, conn, nickname, argv[2],
626 silc_client_command_key_get_clients, inter);
629 client_entry = entrys[0];
635 /* Get channel entry */
638 if (argv[2][0] == '*') {
639 if (!conn->current_channel) {
641 cmd_return_error(CMDERR_NOT_JOINED);
643 name = conn->current_channel->channel_name;
648 chanrec = silc_channel_find(server, name);
649 if (chanrec == NULL) {
651 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
653 channel_entry = chanrec->entry;
657 if (!strcasecmp(argv[3], "set")) {
661 char *cipher = NULL, *hmac = NULL;
663 if (type == 1 && client_entry) {
664 /* Set private message key */
665 bool responder = FALSE;
667 silc_client_del_private_message_key(silc_client, conn, client_entry);
670 if (!strcasecmp(argv[5], "-responder"))
676 if (!strcasecmp(argv[6], "-responder"))
682 if (!strcasecmp(argv[7], "-responder"))
686 silc_client_add_private_message_key(silc_client, conn, client_entry,
688 argv[4], argv_lens[4],
690 TRUE : FALSE), responder);
692 /* Send the key to the remote client so that it starts using it
694 /* XXX for now we don't do this. This feature is pretty stupid
695 and should perhaps be removed altogether from SILC.
696 silc_client_send_private_message_key(silc_client, conn,
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);
713 if (!silc_client_add_channel_private_key(silc_client, conn,
718 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
719 SILCTXT_CH_PRIVATE_KEY_ERROR,
720 channel_entry->channel_name);
724 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
725 SILCTXT_CH_PRIVATE_KEY_ADD,
726 channel_entry->channel_name);
734 if (!strcasecmp(argv[3], "unset")) {
737 if (type == 1 && client_entry) {
738 /* Unset private message key */
739 silc_client_del_private_message_key(silc_client, conn, client_entry);
740 } else if (type == 2) {
741 /* Unset channel key(s) */
742 SilcChannelPrivateKey *keys;
743 SilcUInt32 keys_count;
747 silc_client_del_channel_private_keys(silc_client, conn,
751 number = atoi(argv[4]);
752 keys = silc_client_list_channel_private_keys(silc_client, conn,
758 if (!number || number > keys_count) {
759 silc_client_free_channel_private_keys(keys, keys_count);
763 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
765 silc_client_free_channel_private_keys(keys, keys_count);
773 if (!strcasecmp(argv[3], "list")) {
777 SilcPrivateMessageKeys keys;
778 SilcUInt32 keys_count;
782 keys = silc_client_list_private_message_keys(silc_client, conn,
787 /* list the private message key(s) */
788 if (nickname[0] == '*') {
789 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
790 SILCTXT_PRIVATE_KEY_LIST);
791 for (k = 0; k < keys_count; k++) {
792 memset(buf, 0, sizeof(buf));
793 strncat(buf, " ", 2);
794 len = strlen(keys[k].client_entry->nickname);
795 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
797 for (i = 0; i < 30 - len; i++)
801 len = strlen(keys[k].cipher);
802 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
804 for (i = 0; i < 14 - len; i++)
809 strcat(buf, "<hidden>");
811 strcat(buf, "*generated*");
813 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
816 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
817 SILCTXT_PRIVATE_KEY_LIST_NICK,
818 client_entry->nickname);
819 for (k = 0; k < keys_count; k++) {
820 if (keys[k].client_entry != client_entry)
823 memset(buf, 0, sizeof(buf));
824 strncat(buf, " ", 2);
825 len = strlen(keys[k].client_entry->nickname);
826 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
828 for (i = 0; i < 30 - len; i++)
832 len = strlen(keys[k].cipher);
833 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
835 for (i = 0; i < 14 - len; i++)
840 strcat(buf, "<hidden>");
842 strcat(buf, "*generated*");
844 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
848 silc_client_free_private_message_keys(keys, keys_count);
850 } else if (type == 2) {
851 SilcChannelPrivateKey *keys;
852 SilcUInt32 keys_count;
856 keys = silc_client_list_channel_private_keys(silc_client, conn,
860 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
861 SILCTXT_CH_PRIVATE_KEY_LIST,
862 channel_entry->channel_name);
867 for (k = 0; k < keys_count; k++) {
868 memset(buf, 0, sizeof(buf));
869 strncat(buf, " ", 2);
871 len = strlen(silc_cipher_get_name(keys[k]->cipher));
872 strncat(buf, silc_cipher_get_name(keys[k]->cipher),
873 len > 16 ? 16 : len);
875 for (i = 0; i < 16 - len; i++)
879 len = strlen(silc_hmac_get_name(keys[k]->hmac));
880 strncat(buf, silc_hmac_get_name(keys[k]->hmac), len > 16 ? 16 : len);
882 for (i = 0; i < 16 - len; i++)
886 strcat(buf, "<hidden>");
888 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
891 silc_client_free_channel_private_keys(keys, keys_count);
897 /* Send command is used to send key agreement */
898 if (!strcasecmp(argv[3], "agreement")) {
904 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")) {
913 hostname = (char *)settings_get_str("auto_public_ip");
915 /* If the hostname isn't set, treat this case as if auto_public_ip
917 if ((hostname) && (*hostname == '\0')) {
920 bindhost = (char *)settings_get_str("auto_bind_ip");
922 /* if the bind_ip isn't set, but the public_ip IS, then assume then
923 public_ip is the same value as the bind_ip. */
924 if ((bindhost) && (*bindhost == '\0'))
926 port = settings_get_int("auto_bind_port");
928 } /* if use_auto_addr */
932 /* Start command is used to start key agreement (after receiving the
933 key_agreement client operation). */
934 if (!strcasecmp(argv[3], "negotiate")) {
940 port = atoi(argv[5]);
942 internal = silc_calloc(1, sizeof(*internal));
943 internal->type = type;
944 internal->server = server;
947 /* Change current channel private key */
948 if (!strcasecmp(argv[3], "change")) {
951 /* Unset channel key(s) */
952 SilcChannelPrivateKey *keys;
953 SilcUInt32 keys_count;
956 keys = silc_client_list_channel_private_keys(silc_client, conn,
964 if (chanrec->cur_key >= keys_count)
965 chanrec->cur_key = 0;
969 number = atoi(argv[4]);
970 if (!number || number > keys_count)
971 chanrec->cur_key = 0;
973 chanrec->cur_key = number - 1;
976 /* Set the current channel private key */
977 silc_client_current_channel_private_key(silc_client, conn,
979 keys[chanrec->cur_key]);
980 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
981 SILCTXT_CH_PRIVATE_KEY_CHANGE, chanrec->cur_key + 1,
982 channel_entry->channel_name);
984 silc_client_free_channel_private_keys(keys, keys_count);
990 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
991 "Usage: /KEY msg|channel <nickname|channel> "
992 "set|unset|agreement|negotiate [<arguments>]");
996 if (command == 4 && client_entry) {
997 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
998 SILCTXT_KEY_AGREEMENT, argv[2]);
999 internal->responder = TRUE;
1000 silc_client_send_key_agreement(
1001 silc_client, conn, client_entry, hostname,
1003 settings_get_int("key_exchange_timeout_secs"),
1004 keyagr_completion, internal);
1006 silc_free(internal);
1010 if (command == 5 && client_entry && hostname) {
1011 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1012 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
1013 internal->responder = FALSE;
1014 silc_client_perform_key_agreement(silc_client, conn, client_entry,
1015 hostname, port, keyagr_completion,
1021 silc_free(nickname);
1024 void silc_list_key(const char *pub_filename, int verbose)
1026 SilcPublicKey public_key;
1027 SilcPublicKeyIdentifier ident;
1028 char *fingerprint, *babbleprint;
1032 SilcUInt32 key_len = 0;
1033 int is_server_key = (strstr(pub_filename, "serverkeys") != NULL);
1035 if (silc_pkcs_load_public_key((char *)pub_filename, &public_key,
1036 SILC_PKCS_FILE_PEM) == FALSE)
1037 if (silc_pkcs_load_public_key((char *)pub_filename, &public_key,
1038 SILC_PKCS_FILE_BIN) == FALSE) {
1039 printformat_module("fe-common/silc", NULL, NULL,
1040 MSGLEVEL_CRAP, SILCTXT_LISTKEY_LOADPUB,
1045 ident = silc_pkcs_decode_identifier(public_key->identifier);
1047 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1048 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1049 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1051 if (silc_pkcs_alloc(public_key->name, &pkcs)) {
1052 key_len = silc_pkcs_public_key_set(pkcs, public_key);
1053 silc_pkcs_free(pkcs);
1056 printformat_module("fe-common/silc", NULL, NULL,
1057 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_FILE,
1061 printformat_module("fe-common/silc", NULL, NULL,
1062 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_ALG,
1064 if (key_len && verbose)
1065 printformat_module("fe-common/silc", NULL, NULL,
1066 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_BITS,
1067 (unsigned int)key_len);
1068 if (ident->realname && (!is_server_key || verbose))
1069 printformat_module("fe-common/silc", NULL, NULL,
1070 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_RN,
1072 if (ident->username && verbose)
1073 printformat_module("fe-common/silc", NULL, NULL,
1074 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_UN,
1076 if (ident->host && (is_server_key || verbose))
1077 printformat_module("fe-common/silc", NULL, NULL,
1078 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_HN,
1080 if (ident->email && verbose)
1081 printformat_module("fe-common/silc", NULL, NULL,
1082 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_EMAIL,
1084 if (ident->org && verbose)
1085 printformat_module("fe-common/silc", NULL, NULL,
1086 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_ORG,
1088 if (ident->country && verbose)
1089 printformat_module("fe-common/silc", NULL, NULL,
1090 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_C,
1094 printformat_module("fe-common/silc", NULL, NULL,
1095 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_FINGER,
1097 printformat_module("fe-common/silc", NULL, NULL,
1098 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_BABL,
1102 silc_free(fingerprint);
1103 silc_free(babbleprint);
1105 silc_pkcs_public_key_free(public_key);
1106 silc_pkcs_free_identifier(ident);
1111 void silc_list_keys_in_dir(const char *dirname, const char *where)
1114 struct dirent *entry;
1116 dir = opendir(dirname);
1119 cmd_return_error(CMDERR_ERRNO);
1121 printformat_module("fe-common/silc", NULL, NULL,
1122 MSGLEVEL_CRAP, SILCTXT_LISTKEY_LIST,
1127 while ((entry = readdir(dir)) != NULL) {
1128 /* try to open everything that isn't a directory */
1132 snprintf(filename, sizeof(filename) - 1, "%s/%s", dirname, entry->d_name);
1133 if (!stat(filename, &buf) && S_ISREG(buf.st_mode))
1134 silc_list_key(filename, FALSE);
1140 void silc_list_file(const char *filename)
1146 snprintf(path, sizeof(path) - 1, "%s", filename);
1147 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1150 snprintf(path, sizeof(path) - 1, "%s/%s", get_irssi_dir(), filename);
1151 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1154 snprintf(path,sizeof(path) - 1, "%s/clientkeys/%s", get_irssi_dir(),
1156 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1159 snprintf(path,sizeof(path) - 1, "%s/serverkeys/%s", get_irssi_dir(),
1161 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1168 silc_list_key(path, TRUE);
1172 /* Lists locally saved client and server public keys. */
1173 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
1176 GHashTable *optlist;
1181 if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS |
1182 PARAM_FLAG_GETREST, "listkeys", &optlist,
1186 if (*filename != '\0') {
1188 silc_list_file(filename);
1191 int clients, servers;
1193 clients = (g_hash_table_lookup(optlist, "clients") != NULL);
1194 servers = (g_hash_table_lookup(optlist, "servers") != NULL);
1196 if (!(clients || servers))
1197 clients = servers = 1;
1200 snprintf(dirname, sizeof(dirname) - 1, "%s/serverkeys", get_irssi_dir());
1201 silc_list_keys_in_dir(dirname, "server");
1205 snprintf(dirname, sizeof(dirname) - 1, "%s/clientkeys", get_irssi_dir());
1206 silc_list_keys_in_dir(dirname, "client");
1209 cmd_params_free(free_arg);
1212 void silc_channels_init(void)
1214 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1215 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1216 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1217 signal_add("gui exit", (SIGNAL_FUNC) sig_gui_quit);
1218 signal_add("mime", (SIGNAL_FUNC) sig_mime);
1220 command_bind_silc("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1221 command_bind_silc("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1222 command_bind_silc("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1223 command_bind_silc("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1224 command_bind_silc("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1225 command_bind_silc("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1226 command_bind("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
1228 command_set_options("listkeys", "clients servers");
1229 command_set_options("action", "sign channel");
1230 command_set_options("notice", "sign channel");
1232 silc_nicklist_init();
1235 void silc_channels_deinit(void)
1237 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1238 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1239 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1240 signal_remove("gui exit", (SIGNAL_FUNC) sig_gui_quit);
1241 signal_remove("mime", (SIGNAL_FUNC) sig_mime);
1243 command_unbind("part", (SIGNAL_FUNC) command_part);
1244 command_unbind("me", (SIGNAL_FUNC) command_me);
1245 command_unbind("action", (SIGNAL_FUNC) command_action);
1246 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1247 command_unbind("away", (SIGNAL_FUNC) command_away);
1248 command_unbind("key", (SIGNAL_FUNC) command_key);
1249 command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
1251 silc_nicklist_deinit();