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;
218 CMD_SILC_SERVER(server);
219 if (!IS_SILC_SERVER(server) || !server->connected)
220 cmd_return_error(CMDERR_NOT_CONNECTED);
222 if ((item != NULL) && (!IS_SILC_CHANNEL(item) && !IS_SILC_QUERY(item)))
223 cmd_return_error(CMDERR_NOT_JOINED);
225 /* Now parse all arguments */
226 if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS |
228 "action", &optlist, &target, &msg))
231 if (*target == '\0' || *msg == '\0')
232 cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
234 if (strcmp(target, "*") == 0) {
235 /* send to active channel/query */
237 cmd_param_error(CMDERR_NOT_JOINED);
239 target_type = IS_SILC_CHANNEL(item) ?
240 SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
241 target = (char *)window_item_get_target(item);
242 } else if (g_hash_table_lookup(optlist, "channel") != NULL)
243 target_type = SEND_TARGET_CHANNEL;
245 target_type = SEND_TARGET_NICK;
248 if (!silc_term_utf8()) {
249 int len = silc_utf8_encoded_len(msg, strlen(msg),
251 message = silc_calloc(len + 1, sizeof(*message));
252 g_return_if_fail(message != NULL);
253 silc_utf8_encode(msg, strlen(msg), SILC_STRING_LOCALE,
257 if (target != NULL) {
258 if (target_type == SEND_TARGET_CHANNEL) {
259 if (silc_send_channel(server, target, (message != NULL ? message : msg),
260 SILC_MESSAGE_FLAG_ACTION | SILC_MESSAGE_FLAG_UTF8 |
261 (g_hash_table_lookup(optlist, "sign") != NULL ?
262 SILC_MESSAGE_FLAG_SIGNED : 0))) {
263 if (g_hash_table_lookup(optlist, "sign"))
264 signal_emit("message silc signed_own_action", 3, server, msg, target);
266 signal_emit("message silc own_action", 3, server, msg, target);
269 if (silc_send_msg(server, target, (message != NULL ? message : msg),
270 (message != NULL ? strlen(message) : strlen(msg)),
271 SILC_MESSAGE_FLAG_ACTION | SILC_MESSAGE_FLAG_UTF8 |
272 (g_hash_table_lookup(optlist, "sign") != NULL ?
273 SILC_MESSAGE_FLAG_SIGNED : 0))) {
274 if (g_hash_table_lookup(optlist, "sign"))
275 signal_emit("message silc signed_own_private_action", 3,
276 server, msg, target);
278 signal_emit("message silc own_private_action", 3,
279 server, msg, target);
284 cmd_params_free(free_arg);
288 /* ME local command. */
290 static void command_me(const char *data, SILC_SERVER_REC *server,
295 CMD_SILC_SERVER(server);
296 if (!IS_SILC_SERVER(server) || !server->connected)
297 cmd_return_error(CMDERR_NOT_CONNECTED);
299 if (!IS_SILC_CHANNEL(item) && !IS_SILC_QUERY(item))
300 cmd_return_error(CMDERR_NOT_JOINED);
302 if (IS_SILC_CHANNEL(item))
303 tmpcmd = g_strdup_printf("-channel %s %s", item->visible_name, data);
305 tmpcmd = g_strdup_printf("%s %s", item->visible_name, data);
307 command_action(tmpcmd, server, item);
311 /* NOTICE local command. */
313 static void command_notice(const char *data, SILC_SERVER_REC *server,
318 char *message = NULL;
322 CMD_SILC_SERVER(server);
323 if (!IS_SILC_SERVER(server) || !server->connected)
324 cmd_return_error(CMDERR_NOT_CONNECTED);
326 if ((item != NULL) && (!IS_SILC_CHANNEL(item) && !IS_SILC_QUERY(item)))
327 cmd_return_error(CMDERR_NOT_JOINED);
329 /* Now parse all arguments */
330 if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS |
332 "notice", &optlist, &target, &msg))
335 if (*target == '\0' || *msg == '\0')
336 cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
338 if (strcmp(target, "*") == 0) {
339 /* send to active channel/query */
341 cmd_param_error(CMDERR_NOT_JOINED);
343 target_type = IS_SILC_CHANNEL(item) ?
344 SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
345 target = (char *)window_item_get_target(item);
346 } else if (g_hash_table_lookup(optlist, "channel") != NULL)
347 target_type = SEND_TARGET_CHANNEL;
349 target_type = SEND_TARGET_NICK;
352 if (!silc_term_utf8()) {
353 int len = silc_utf8_encoded_len(msg, strlen(msg),
355 message = silc_calloc(len + 1, sizeof(*message));
356 g_return_if_fail(message != NULL);
357 silc_utf8_encode(msg, strlen(msg), SILC_STRING_LOCALE,
361 if (target != NULL) {
362 if (target_type == SEND_TARGET_CHANNEL) {
363 if (silc_send_channel(server, target, (message != NULL ? message : msg),
364 SILC_MESSAGE_FLAG_NOTICE | SILC_MESSAGE_FLAG_UTF8 |
365 (g_hash_table_lookup(optlist, "sign") != NULL ?
366 SILC_MESSAGE_FLAG_SIGNED : 0))) {
367 if (g_hash_table_lookup(optlist, "sign"))
368 signal_emit("message silc signed_own_notice", 3, server, msg, target);
370 signal_emit("message silc own_notice", 3, server, msg, target);
373 if (silc_send_msg(server, target, (message != NULL ? message : msg),
374 (message != NULL ? strlen(message) : strlen(msg)),
375 SILC_MESSAGE_FLAG_NOTICE | SILC_MESSAGE_FLAG_UTF8 |
376 (g_hash_table_lookup(optlist, "sign") != NULL ?
377 SILC_MESSAGE_FLAG_SIGNED : 0))) {
378 if (g_hash_table_lookup(optlist, "sign"))
379 signal_emit("message silc signed_own_private_notice", 3,
380 server, msg, target);
382 signal_emit("message silc own_private_notice", 3,
383 server, msg, target);
388 cmd_params_free(free_arg);
392 /* AWAY local command. Sends UMODE command that sets the SILC_UMODE_GONE
395 bool silc_set_away(const char *reason, SILC_SERVER_REC *server)
399 if (!IS_SILC_SERVER(server) || !server->connected)
402 if (*reason == '\0') {
403 /* Remove any possible away message */
404 silc_client_set_away_message(silc_client, server->conn, NULL);
407 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
410 /* Set the away message */
411 silc_client_set_away_message(silc_client, server->conn, (char *)reason);
414 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
415 SILCTXT_SET_AWAY, reason);
418 server->usermode_away = set;
419 g_free_and_null(server->away_reason);
421 server->away_reason = g_strdup((char *)reason);
423 signal_emit("away mode changed", 1, server);
428 static void command_away(const char *data, SILC_SERVER_REC *server,
431 CMD_SILC_SERVER(server);
433 if (!IS_SILC_SERVER(server) || !server->connected)
434 cmd_return_error(CMDERR_NOT_CONNECTED);
436 g_free_and_null(server->away_reason);
437 if ((data) && (*data != '\0'))
438 server->away_reason = g_strdup(data);
440 silc_command_exec(server, "UMODE",
441 (server->away_reason != NULL) ? "+g" : "-g");
445 SILC_SERVER_REC *server;
446 int type; /* 1 = msg, 2 = channel */
450 /* Key agreement callback that is called after the key agreement protocol
451 has been performed. This is called also if error occured during the
452 key agreement protocol. The `key' is the allocated key material and
453 the caller is responsible of freeing it. The `key' is NULL if error
454 has occured. The application can freely use the `key' to whatever
455 purpose it needs. See lib/silcske/silcske.h for the definition of
456 the SilcSKEKeyMaterial structure. */
458 static void keyagr_completion(SilcClient client,
459 SilcClientConnection conn,
460 SilcClientEntry client_entry,
461 SilcKeyAgreementStatus status,
462 SilcSKEKeyMaterial key,
465 KeyInternal i = (KeyInternal)context;
468 case SILC_KEY_AGREEMENT_OK:
469 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
470 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
473 /* Set the private key for this client */
474 silc_client_del_private_message_key(client, conn, client_entry);
475 silc_client_add_private_message_key_ske(client, conn, client_entry,
477 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
478 SILCTXT_KEY_AGREEMENT_PRIVMSG,
479 client_entry->nickname);
480 silc_ske_free_key_material(key);
485 case SILC_KEY_AGREEMENT_ERROR:
486 case SILC_KEY_AGREEMENT_NO_MEMORY:
487 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
488 SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
491 case SILC_KEY_AGREEMENT_FAILURE:
492 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
493 SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
496 case SILC_KEY_AGREEMENT_TIMEOUT:
497 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
498 SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
501 case SILC_KEY_AGREEMENT_ABORTED:
502 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
503 SILCTXT_KEY_AGREEMENT_ABORTED, client_entry->nickname);
506 case SILC_KEY_AGREEMENT_ALREADY_STARTED:
507 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
508 SILCTXT_KEY_AGREEMENT_ALREADY_STARTED,
509 client_entry->nickname);
512 case SILC_KEY_AGREEMENT_SELF_DENIED:
513 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
514 SILCTXT_KEY_AGREEMENT_SELF_DENIED);
525 /* Local command KEY. This command is used to set and unset private
526 keys for channels, set and unset private keys for private messages
527 with remote clients and to send key agreement requests and
528 negotiate the key agreement protocol with remote client. The
529 key agreement is supported only to negotiate private message keys,
530 it currently cannot be used to negotiate private keys for channels,
531 as it is not convenient for that purpose. */
534 SILC_SERVER_REC *server;
540 /* Callback to be called after client information is resolved from the
543 static void silc_client_command_key_get_clients(SilcClient client,
544 SilcClientConnection conn,
549 KeyGetClients internal = (KeyGetClients)context;
552 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s",
554 silc_free(internal->data);
555 silc_free(internal->nick);
560 signal_emit("command key", 3, internal->data, internal->server,
563 silc_free(internal->data);
564 silc_free(internal->nick);
568 static void command_key(const char *data, SILC_SERVER_REC *server,
571 SilcClientConnection conn;
572 SilcClientEntry client_entry = NULL;
574 SILC_CHANNEL_REC *chanrec = NULL;
575 SilcChannelEntry channel_entry = NULL;
576 char nickname[128 + 1], *tmp;
577 int command = 0, port = 0, type = 0;
578 char *hostname = NULL;
579 KeyInternal internal = NULL;
581 unsigned char **argv;
582 SilcUInt32 *argv_lens, *argv_types;
583 char *bindhost = NULL;
584 SilcChannelEntry ch = NULL;
586 SilcBool udp = FALSE;
589 CMD_SILC_SERVER(server);
591 if (!server || !IS_SILC_SERVER(server) || !server->connected)
592 cmd_return_error(CMDERR_NOT_CONNECTED);
596 /* Now parse all arguments */
597 tmp = g_strconcat("KEY", " ", data, NULL);
598 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
602 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
605 if (!strcasecmp(argv[1], "msg"))
607 if (!strcasecmp(argv[1], "channel"))
611 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
614 if (argv[2][0] == '*') {
615 strcpy(nickname, "*");
617 /* Parse the typed nickname. */
618 if (!silc_parse_userfqdn(argv[2], nickname, sizeof(nickname), NULL, 0)) {
619 printformat_module("fe-common/silc", server, NULL,
620 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
624 /* Find client entry */
625 clients = silc_client_get_clients_local(silc_client, conn, nickname,
628 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
629 inter->server = server;
630 inter->data = strdup(data);
631 inter->nick = strdup(nickname);
633 silc_client_get_clients(silc_client, conn, nickname, argv[2],
634 silc_client_command_key_get_clients, inter);
638 client_entry = silc_dlist_get(clients);
639 silc_client_list_free(silc_client, conn, clients);
644 /* Get channel entry */
647 if (argv[2][0] == '*') {
648 if (!conn->current_channel) {
650 cmd_return_error(CMDERR_NOT_JOINED);
652 name = conn->current_channel->channel_name;
657 chanrec = silc_channel_find(server, name);
658 if (chanrec == NULL) {
660 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
662 channel_entry = chanrec->entry;
666 if (!strcasecmp(argv[3], "set")) {
670 char *cipher = NULL, *hmac = NULL;
677 if (type == 1 && client_entry) {
678 /* Set private message key */
679 silc_client_del_private_message_key(silc_client, conn, client_entry);
680 silc_client_add_private_message_key(silc_client, conn, client_entry,
682 argv[4], argv_lens[4]);
683 } else if (type == 2) {
684 /* Set private channel key */
685 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
686 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
687 SILCTXT_CH_PRIVATE_KEY_NOMODE,
688 channel_entry->channel_name);
692 if (!silc_client_add_channel_private_key(silc_client, conn,
696 argv_lens[4], NULL)) {
697 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
698 SILCTXT_CH_PRIVATE_KEY_ERROR,
699 channel_entry->channel_name);
703 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
704 SILCTXT_CH_PRIVATE_KEY_ADD,
705 channel_entry->channel_name);
713 if (!strcasecmp(argv[3], "unset")) {
716 if (type == 1 && client_entry) {
717 /* Unset private message key */
718 silc_client_del_private_message_key(silc_client, conn, client_entry);
719 } else if (type == 2) {
720 /* Unset channel key(s) */
724 silc_client_del_channel_private_keys(silc_client, conn,
728 number = atoi(argv[4]);
729 ckeys = silc_client_list_channel_private_keys(silc_client, conn,
734 if (!number || number > silc_dlist_count(ckeys)) {
735 silc_dlist_uninit(ckeys);
739 for (i = 0; i < number; i++)
740 ch = silc_dlist_get(ckeys);
744 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
746 silc_dlist_uninit(ckeys);
755 if (!strcasecmp(argv[3], "list")) {
759 SilcPrivateMessageKeys keys;
760 SilcUInt32 keys_count;
764 keys = silc_client_list_private_message_keys(silc_client, conn,
769 /* list the private message key(s) */
770 if (nickname[0] == '*') {
771 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
772 SILCTXT_PRIVATE_KEY_LIST);
773 for (k = 0; k < keys_count; k++) {
774 memset(buf, 0, sizeof(buf));
775 strncat(buf, " ", 2);
776 len = strlen(keys[k].client_entry->nickname);
777 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
779 for (i = 0; i < 30 - len; i++)
783 len = strlen(keys[k].cipher);
784 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
786 for (i = 0; i < 14 - len; i++)
791 strcat(buf, "<hidden>");
793 strcat(buf, "*generated*");
795 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
798 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
799 SILCTXT_PRIVATE_KEY_LIST_NICK,
800 client_entry->nickname);
801 for (k = 0; k < keys_count; k++) {
802 if (keys[k].client_entry != client_entry)
805 memset(buf, 0, sizeof(buf));
806 strncat(buf, " ", 2);
807 len = strlen(keys[k].client_entry->nickname);
808 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
810 for (i = 0; i < 30 - len; i++)
814 len = strlen(keys[k].cipher);
815 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
817 for (i = 0; i < 14 - len; i++)
822 strcat(buf, "<hidden>");
824 strcat(buf, "*generated*");
826 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
830 silc_client_free_private_message_keys(keys, keys_count);
832 } else if (type == 2) {
836 ckeys = silc_client_list_channel_private_keys(silc_client, conn,
839 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
840 SILCTXT_CH_PRIVATE_KEY_LIST,
841 channel_entry->channel_name);
846 for (k = 0; k < keys_count; k++) {
847 memset(buf, 0, sizeof(buf));
848 strncat(buf, " ", 2);
850 len = strlen(silc_cipher_get_name(keys[k]->cipher));
851 strncat(buf, silc_cipher_get_name(keys[k]->cipher),
852 len > 16 ? 16 : len);
854 for (i = 0; i < 16 - len; i++)
858 len = strlen(silc_hmac_get_name(keys[k]->hmac));
859 strncat(buf, silc_hmac_get_name(keys[k]->hmac), len > 16 ? 16 : len);
861 for (i = 0; i < 16 - len; i++)
865 strcat(buf, "<hidden>");
867 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
870 silc_client_free_channel_private_keys(keys, keys_count);
877 /* Send command is used to send key agreement */
878 if (!strcasecmp(argv[3], "agreement")) {
884 if (!strcasecmp(argv[5], "UDP"))
887 port = atoi(argv[5]);
892 internal = silc_calloc(1, sizeof(*internal));
893 internal->type = type;
894 internal->server = server;
897 if (settings_get_bool("use_auto_addr")) {
898 hostname = (char *)settings_get_str("auto_public_ip");
900 /* If the hostname isn't set, treat this case as if auto_public_ip
902 if ((hostname) && (*hostname == '\0')) {
905 bindhost = (char *)settings_get_str("auto_bind_ip");
907 /* if the bind_ip isn't set, but the public_ip IS, then assume then
908 public_ip is the same value as the bind_ip. */
909 if ((bindhost) && (*bindhost == '\0'))
911 port = settings_get_int("auto_bind_port");
913 } /* if use_auto_addr */
917 /* Start command is used to start key agreement (after receiving the
918 key_agreement client operation). */
919 if (!strcasecmp(argv[3], "negotiate")) {
925 if (!strcasecmp(argv[5], "UDP"))
928 port = atoi(argv[5]);
933 internal = silc_calloc(1, sizeof(*internal));
934 internal->type = type;
935 internal->server = server;
938 /* Change current channel private key */
939 if (!strcasecmp(argv[3], "change")) {
942 /* Unset channel key(s) */
945 ckeys = silc_client_list_channel_private_keys(silc_client, conn,
952 if (chanrec->cur_key >= silc_dlist_count(ckeys))
953 chanrec->cur_key = 0;
957 number = atoi(argv[4]);
958 if (!number || number > silc_dlist_count(ckeys))
959 chanrec->cur_key = 0;
961 chanrec->cur_key = number - 1;
964 for (i = 0; i < chanrec->cur_key; i++)
965 ch = silc_dlist_get(ckeys);
969 /* Set the current channel private key */
970 silc_client_current_channel_private_key(silc_client, conn,
972 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
973 SILCTXT_CH_PRIVATE_KEY_CHANGE, i + 1,
974 channel_entry->channel_name);
976 silc_dlist_uninit(ckeys);
982 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
983 "Usage: /KEY msg|channel <nickname|channel> "
984 "set|unset|agreement|negotiate [<arguments>]");
988 if (command == 4 && client_entry) {
989 SilcClientConnectionParams params;
991 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
992 SILCTXT_KEY_AGREEMENT, argv[2]);
993 internal->responder = TRUE;
995 memset(¶ms, 0, sizeof(params));
996 params.local_ip = hostname;
997 params.bind_ip = bindhost;
998 params.local_port = port;
1000 params.timeout_secs = settings_get_int("key_exchange_timeout_secs");
1002 silc_client_send_key_agreement(
1003 silc_client, conn, client_entry, ¶ms,
1004 irssi_pubkey, irssi_privkey,
1005 keyagr_completion, internal);
1007 silc_free(internal);
1011 if (command == 5 && client_entry && hostname) {
1012 SilcClientConnectionParams params;
1014 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1015 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
1016 internal->responder = FALSE;
1018 memset(¶ms, 0, sizeof(params));
1020 if (settings_get_bool("use_auto_addr")) {
1021 params.local_ip = (char *)settings_get_str("auto_public_ip");
1022 if ((params.local_ip) && (*params.local_ip == '\0')) {
1023 params.local_ip = silc_net_localip();
1025 params.bind_ip = (char *)settings_get_str("auto_bind_ip");
1026 if ((params.bind_ip) && (*params.bind_ip == '\0'))
1027 params.bind_ip = NULL;
1028 params.local_port = settings_get_int("auto_bind_port");
1031 if (!params.local_ip)
1032 params.local_ip = silc_net_localip();
1035 params.timeout_secs = settings_get_int("key_exchange_timeout_secs");
1037 silc_client_perform_key_agreement(silc_client, conn, client_entry, ¶ms,
1038 irssi_pubkey, irssi_privkey,
1039 hostname, port, keyagr_completion,
1049 void silc_list_key(const char *pub_filename, int verbose)
1051 SilcPublicKey public_key;
1052 SilcPublicKeyIdentifier ident;
1053 char *fingerprint, *babbleprint;
1057 SilcUInt32 key_len = 0;
1058 int is_server_key = (strstr(pub_filename, "serverkeys") != NULL);
1060 if (silc_pkcs_load_public_key((char *)pub_filename, &public_key,
1061 SILC_PKCS_FILE_PEM) == FALSE)
1062 if (silc_pkcs_load_public_key((char *)pub_filename, &public_key,
1063 SILC_PKCS_FILE_BIN) == FALSE) {
1064 printformat_module("fe-common/silc", NULL, NULL,
1065 MSGLEVEL_CRAP, SILCTXT_LISTKEY_LOADPUB,
1070 ident = silc_pkcs_decode_identifier(public_key->identifier);
1072 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1073 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1074 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1076 if (silc_pkcs_alloc(public_key->name, &pkcs)) {
1077 key_len = silc_pkcs_public_key_set(pkcs, public_key);
1078 silc_pkcs_free(pkcs);
1081 printformat_module("fe-common/silc", NULL, NULL,
1082 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_FILE,
1086 printformat_module("fe-common/silc", NULL, NULL,
1087 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_ALG,
1089 if (key_len && verbose)
1090 printformat_module("fe-common/silc", NULL, NULL,
1091 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_BITS,
1092 (unsigned int)key_len);
1093 if (ident->realname && (!is_server_key || verbose))
1094 printformat_module("fe-common/silc", NULL, NULL,
1095 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_RN,
1097 if (ident->username && verbose)
1098 printformat_module("fe-common/silc", NULL, NULL,
1099 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_UN,
1101 if (ident->host && (is_server_key || verbose))
1102 printformat_module("fe-common/silc", NULL, NULL,
1103 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_HN,
1105 if (ident->email && verbose)
1106 printformat_module("fe-common/silc", NULL, NULL,
1107 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_EMAIL,
1109 if (ident->org && verbose)
1110 printformat_module("fe-common/silc", NULL, NULL,
1111 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_ORG,
1113 if (ident->country && verbose)
1114 printformat_module("fe-common/silc", NULL, NULL,
1115 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_C,
1119 printformat_module("fe-common/silc", NULL, NULL,
1120 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_FINGER,
1122 printformat_module("fe-common/silc", NULL, NULL,
1123 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_BABL,
1127 silc_free(fingerprint);
1128 silc_free(babbleprint);
1130 silc_pkcs_public_key_free(public_key);
1131 silc_pkcs_free_identifier(ident);
1135 void silc_list_keys_in_dir(const char *dirname, const char *where)
1138 struct dirent *entry;
1140 dir = opendir(dirname);
1143 cmd_return_error(CMDERR_ERRNO);
1145 printformat_module("fe-common/silc", NULL, NULL,
1146 MSGLEVEL_CRAP, SILCTXT_LISTKEY_LIST,
1151 while ((entry = readdir(dir)) != NULL) {
1152 /* try to open everything that isn't a directory */
1156 snprintf(filename, sizeof(filename) - 1, "%s/%s", dirname, entry->d_name);
1157 if (!stat(filename, &buf) && S_ISREG(buf.st_mode))
1158 silc_list_key(filename, FALSE);
1164 void silc_list_file(const char *filename)
1170 snprintf(path, sizeof(path) - 1, "%s", filename);
1171 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1174 snprintf(path, sizeof(path) - 1, "%s/%s", get_irssi_dir(), filename);
1175 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1178 snprintf(path,sizeof(path) - 1, "%s/clientkeys/%s", get_irssi_dir(),
1180 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1183 snprintf(path,sizeof(path) - 1, "%s/serverkeys/%s", get_irssi_dir(),
1185 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1192 silc_list_key(path, TRUE);
1197 /* Lists locally saved client and server public keys. */
1198 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
1201 GHashTable *optlist;
1206 if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS |
1207 PARAM_FLAG_GETREST, "listkeys", &optlist,
1211 if (*filename != '\0') {
1213 silc_list_file(filename);
1216 int clients, servers;
1218 clients = (g_hash_table_lookup(optlist, "clients") != NULL);
1219 servers = (g_hash_table_lookup(optlist, "servers") != NULL);
1221 if (!(clients || servers))
1222 clients = servers = 1;
1225 snprintf(dirname, sizeof(dirname) - 1, "%s/serverkeys", get_irssi_dir());
1226 silc_list_keys_in_dir(dirname, "server");
1230 snprintf(dirname, sizeof(dirname) - 1, "%s/clientkeys", get_irssi_dir());
1231 silc_list_keys_in_dir(dirname, "client");
1234 cmd_params_free(free_arg);
1237 void silc_channels_init(void)
1239 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1240 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1241 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1242 signal_add("gui exit", (SIGNAL_FUNC) sig_gui_quit);
1243 signal_add("mime", (SIGNAL_FUNC) sig_mime);
1245 command_bind_silc("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1246 command_bind_silc("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1247 command_bind_silc("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1248 command_bind_silc("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1249 command_bind_silc("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1250 command_bind_silc("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1251 // command_bind("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
1253 //command_set_options("listkeys", "clients servers");
1254 command_set_options("action", "sign channel");
1255 command_set_options("notice", "sign channel");
1257 silc_nicklist_init();
1260 void silc_channels_deinit(void)
1262 signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1263 signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
1264 signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
1265 signal_remove("gui exit", (SIGNAL_FUNC) sig_gui_quit);
1266 signal_remove("mime", (SIGNAL_FUNC) sig_mime);
1268 command_unbind("part", (SIGNAL_FUNC) command_part);
1269 command_unbind("me", (SIGNAL_FUNC) command_me);
1270 command_unbind("action", (SIGNAL_FUNC) command_action);
1271 command_unbind("notice", (SIGNAL_FUNC) command_notice);
1272 command_unbind("away", (SIGNAL_FUNC) command_away);
1273 command_unbind("key", (SIGNAL_FUNC) command_key);
1274 // command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
1276 silc_nicklist_deinit();