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));
203 /* ME local command. */
205 static void command_me(const char *data, SILC_SERVER_REC *server,
208 SILC_CHANNEL_REC *chanrec;
209 char *tmpcmd = "ME", *tmp;
211 unsigned char *message = NULL;
212 unsigned char **argv;
213 SilcUInt32 *argv_lens, *argv_types;
216 CMD_SILC_SERVER(server);
218 if (!IS_SILC_SERVER(server) || !server->connected)
219 cmd_return_error(CMDERR_NOT_CONNECTED);
221 if (!IS_SILC_CHANNEL(item))
222 cmd_return_error(CMDERR_NOT_JOINED);
224 /* Now parse all arguments */
225 tmp = g_strconcat(tmpcmd, " ", data, NULL);
226 silc_parse_command_line(tmp, &argv, &argv_lens,
227 &argv_types, &argc, 2);
231 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
233 chanrec = silc_channel_find(server, item->visible_name);
235 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
237 if (!silc_term_utf8()) {
238 int len = silc_utf8_encoded_len(argv[1], argv_lens[1],
239 SILC_STRING_LANGUAGE);
240 message = silc_calloc(len + 1, sizeof(*message));
241 g_return_if_fail(message != NULL);
242 silc_utf8_encode(argv[1], argv_lens[1], SILC_STRING_LANGUAGE,
246 /* Send the action message */
247 silc_client_send_channel_message(silc_client, server->conn,
248 chanrec->entry, NULL,
249 SILC_MESSAGE_FLAG_ACTION |
250 SILC_MESSAGE_FLAG_UTF8,
251 message ? message : argv[1],
252 message ? strlen(message) : argv_lens[1],
255 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
256 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
257 server->conn->local_entry->nickname, argv[1]);
259 for (i = 0; i < argc; i++)
261 silc_free(argv_lens);
262 silc_free(argv_types);
266 /* ACTION local command. Same as ME but takes the channel as mandatory
269 static void command_action(const char *data, SILC_SERVER_REC *server,
272 SILC_CHANNEL_REC *chanrec;
273 char *tmpcmd = "ME", *tmp;
275 unsigned char *message = NULL;
276 unsigned char **argv;
277 SilcUInt32 *argv_lens, *argv_types;
280 CMD_SILC_SERVER(server);
281 if (!IS_SILC_SERVER(server) || !server->connected)
282 cmd_return_error(CMDERR_NOT_CONNECTED);
284 if (!IS_SILC_CHANNEL(item))
285 cmd_return_error(CMDERR_NOT_JOINED);
287 /* Now parse all arguments */
288 tmp = g_strconcat(tmpcmd, " ", data, NULL);
289 silc_parse_command_line(tmp, &argv, &argv_lens,
290 &argv_types, &argc, 3);
294 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
296 chanrec = silc_channel_find(server, argv[1]);
298 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
300 if (!silc_term_utf8()) {
301 int len = silc_utf8_encoded_len(argv[2], argv_lens[2],
302 SILC_STRING_LANGUAGE);
303 message = silc_calloc(len + 1, sizeof(*message));
304 g_return_if_fail(message != NULL);
305 silc_utf8_encode(argv[2], argv_lens[2], SILC_STRING_LANGUAGE,
309 /* Send the action message */
310 silc_client_send_channel_message(silc_client, server->conn,
311 chanrec->entry, NULL,
312 SILC_MESSAGE_FLAG_ACTION |
313 SILC_MESSAGE_FLAG_UTF8,
314 message ? message : argv[2],
315 message ? strlen(message) : argv_lens[2],
318 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
319 MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_OWNACTION,
320 server->conn->local_entry->nickname, argv[2]);
322 for (i = 0; i < argc; i++)
324 silc_free(argv_lens);
325 silc_free(argv_types);
329 /* NOTICE local command. */
331 static void command_notice(const char *data, SILC_SERVER_REC *server,
334 SILC_CHANNEL_REC *chanrec;
335 char *tmpcmd = "ME", *tmp;
337 unsigned char *message = NULL;
338 unsigned char **argv;
339 SilcUInt32 *argv_lens, *argv_types;
342 CMD_SILC_SERVER(server);
343 if (!IS_SILC_SERVER(server) || !server->connected)
344 cmd_return_error(CMDERR_NOT_CONNECTED);
346 if (!IS_SILC_CHANNEL(item))
347 cmd_return_error(CMDERR_NOT_JOINED);
349 /* Now parse all arguments */
350 tmp = g_strconcat(tmpcmd, " ", data, NULL);
351 silc_parse_command_line(tmp, &argv, &argv_lens,
352 &argv_types, &argc, 2);
356 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
358 chanrec = silc_channel_find(server, item->visible_name);
360 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
362 if (!silc_term_utf8()) {
363 int len = silc_utf8_encoded_len(argv[1], argv_lens[1],
364 SILC_STRING_LANGUAGE);
365 message = silc_calloc(len + 1, sizeof(*message));
366 g_return_if_fail(message != NULL);
367 silc_utf8_encode(argv[1], argv_lens[1], SILC_STRING_LANGUAGE,
371 /* Send the action message */
372 silc_client_send_channel_message(silc_client, server->conn,
373 chanrec->entry, NULL,
374 SILC_MESSAGE_FLAG_NOTICE |
375 SILC_MESSAGE_FLAG_UTF8,
376 message ? message : argv[1],
377 message ? strlen(message) : argv_lens[1],
380 printformat_module("fe-common/silc", server, chanrec->entry->channel_name,
381 MSGLEVEL_NOTICES, SILCTXT_CHANNEL_OWNNOTICE,
382 server->conn->local_entry->nickname, argv[1]);
384 for (i = 0; i < argc; i++)
386 silc_free(argv_lens);
387 silc_free(argv_types);
391 /* AWAY local command. Sends UMODE command that sets the SILC_UMODE_GONE
394 bool silc_set_away(const char *reason, SILC_SERVER_REC *server)
398 if (!IS_SILC_SERVER(server) || !server->connected)
401 if (*reason == '\0') {
402 /* Remove any possible away message */
403 silc_client_set_away_message(silc_client, server->conn, NULL);
406 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
409 /* Set the away message */
410 silc_client_set_away_message(silc_client, server->conn, (char *)reason);
413 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
414 SILCTXT_SET_AWAY, reason);
417 server->usermode_away = set;
418 g_free_and_null(server->away_reason);
420 server->away_reason = g_strdup((char *)reason);
422 signal_emit("away mode changed", 1, server);
427 static void command_away(const char *data, SILC_SERVER_REC *server,
430 CMD_SILC_SERVER(server);
432 if (!IS_SILC_SERVER(server) || !server->connected)
433 cmd_return_error(CMDERR_NOT_CONNECTED);
435 g_free_and_null(server->away_reason);
436 if ((data) && (*data != '\0'))
437 server->away_reason = g_strdup(data);
439 silc_command_exec(server, "UMODE",
440 (server->away_reason != NULL) ? "+g" : "-g");
444 int type; /* 1 = msg, 2 = channel */
446 SILC_SERVER_REC *server;
449 /* Key agreement callback that is called after the key agreement protocol
450 has been performed. This is called also if error occured during the
451 key agreement protocol. The `key' is the allocated key material and
452 the caller is responsible of freeing it. The `key' is NULL if error
453 has occured. The application can freely use the `key' to whatever
454 purpose it needs. See lib/silcske/silcske.h for the definition of
455 the SilcSKEKeyMaterial structure. */
457 static void keyagr_completion(SilcClient client,
458 SilcClientConnection conn,
459 SilcClientEntry client_entry,
460 SilcKeyAgreementStatus status,
461 SilcSKEKeyMaterial *key,
464 KeyInternal i = (KeyInternal)context;
467 case SILC_KEY_AGREEMENT_OK:
468 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
469 SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname);
472 /* Set the private key for this client */
473 silc_client_del_private_message_key(client, conn, client_entry);
474 silc_client_add_private_message_key_ske(client, conn, client_entry,
475 NULL, NULL, key, i->responder);
476 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
477 SILCTXT_KEY_AGREEMENT_PRIVMSG,
478 client_entry->nickname);
479 silc_ske_free_key_material(key);
484 case SILC_KEY_AGREEMENT_ERROR:
485 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
486 SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
489 case SILC_KEY_AGREEMENT_FAILURE:
490 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
491 SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname);
494 case SILC_KEY_AGREEMENT_TIMEOUT:
495 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
496 SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname);
499 case SILC_KEY_AGREEMENT_ABORTED:
500 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
501 SILCTXT_KEY_AGREEMENT_ABORTED, client_entry->nickname);
504 case SILC_KEY_AGREEMENT_ALREADY_STARTED:
505 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
506 SILCTXT_KEY_AGREEMENT_ALREADY_STARTED,
507 client_entry->nickname);
510 case SILC_KEY_AGREEMENT_SELF_DENIED:
511 printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
512 SILCTXT_KEY_AGREEMENT_SELF_DENIED);
523 /* Local command KEY. This command is used to set and unset private
524 keys for channels, set and unset private keys for private messages
525 with remote clients and to send key agreement requests and
526 negotiate the key agreement protocol with remote client. The
527 key agreement is supported only to negotiate private message keys,
528 it currently cannot be used to negotiate private keys for channels,
529 as it is not convenient for that purpose. */
532 SILC_SERVER_REC *server;
538 /* Callback to be called after client information is resolved from the
541 static void silc_client_command_key_get_clients(SilcClient client,
542 SilcClientConnection conn,
543 SilcClientEntry *clients,
544 SilcUInt32 clients_count,
547 KeyGetClients internal = (KeyGetClients)context;
550 printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s",
552 silc_free(internal->data);
553 silc_free(internal->nick);
558 signal_emit("command key", 3, internal->data, internal->server,
561 silc_free(internal->data);
562 silc_free(internal->nick);
566 static void command_key(const char *data, SILC_SERVER_REC *server,
569 SilcClientConnection conn;
570 SilcClientEntry *entrys, client_entry = NULL;
571 SilcUInt32 entry_count;
572 SILC_CHANNEL_REC *chanrec = NULL;
573 SilcChannelEntry channel_entry = NULL;
574 char *nickname = NULL, *tmp;
575 int command = 0, port = 0, type = 0;
576 char *hostname = NULL;
577 KeyInternal internal = NULL;
579 unsigned char **argv;
580 SilcUInt32 *argv_lens, *argv_types;
581 char *bindhost = NULL;
583 CMD_SILC_SERVER(server);
585 if (!server || !IS_SILC_SERVER(server) || !server->connected)
586 cmd_return_error(CMDERR_NOT_CONNECTED);
590 /* Now parse all arguments */
591 tmp = g_strconcat("KEY", " ", data, NULL);
592 silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7);
596 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
599 if (!strcasecmp(argv[1], "msg"))
601 if (!strcasecmp(argv[1], "channel"))
605 cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
608 if (argv[2][0] == '*') {
609 nickname = strdup("*");
611 /* Parse the typed nickname. */
612 if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
613 printformat_module("fe-common/silc", server, NULL,
614 MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
618 /* Find client entry */
619 entrys = silc_client_get_clients_local(silc_client, conn, nickname,
620 argv[2], &entry_count);
622 KeyGetClients inter = silc_calloc(1, sizeof(*inter));
623 inter->server = server;
624 inter->data = strdup(data);
625 inter->nick = strdup(nickname);
627 silc_client_get_clients(silc_client, conn, nickname, argv[2],
628 silc_client_command_key_get_clients, inter);
631 client_entry = entrys[0];
637 /* Get channel entry */
640 if (argv[2][0] == '*') {
641 if (!conn->current_channel) {
643 cmd_return_error(CMDERR_NOT_JOINED);
645 name = conn->current_channel->channel_name;
650 chanrec = silc_channel_find(server, name);
651 if (chanrec == NULL) {
653 cmd_return_error(CMDERR_CHAN_NOT_FOUND);
655 channel_entry = chanrec->entry;
659 if (!strcasecmp(argv[3], "set")) {
663 char *cipher = NULL, *hmac = NULL;
665 if (type == 1 && client_entry) {
666 /* Set private message key */
667 bool responder = FALSE;
669 silc_client_del_private_message_key(silc_client, conn, client_entry);
672 if (!strcasecmp(argv[5], "-responder"))
678 if (!strcasecmp(argv[6], "-responder"))
684 if (!strcasecmp(argv[7], "-responder"))
688 silc_client_add_private_message_key(silc_client, conn, client_entry,
690 argv[4], argv_lens[4],
692 TRUE : FALSE), responder);
694 /* Send the key to the remote client so that it starts using it
696 /* XXX for now we don't do this. This feature is pretty stupid
697 and should perhaps be removed altogether from SILC.
698 silc_client_send_private_message_key(silc_client, conn,
701 } else if (type == 2) {
702 /* Set private channel key */
703 if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
704 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
705 SILCTXT_CH_PRIVATE_KEY_NOMODE,
706 channel_entry->channel_name);
715 if (!silc_client_add_channel_private_key(silc_client, conn,
720 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
721 SILCTXT_CH_PRIVATE_KEY_ERROR,
722 channel_entry->channel_name);
726 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
727 SILCTXT_CH_PRIVATE_KEY_ADD,
728 channel_entry->channel_name);
736 if (!strcasecmp(argv[3], "unset")) {
739 if (type == 1 && client_entry) {
740 /* Unset private message key */
741 silc_client_del_private_message_key(silc_client, conn, client_entry);
742 } else if (type == 2) {
743 /* Unset channel key(s) */
744 SilcChannelPrivateKey *keys;
745 SilcUInt32 keys_count;
749 silc_client_del_channel_private_keys(silc_client, conn,
753 number = atoi(argv[4]);
754 keys = silc_client_list_channel_private_keys(silc_client, conn,
760 if (!number || number > keys_count) {
761 silc_client_free_channel_private_keys(keys, keys_count);
765 silc_client_del_channel_private_key(silc_client, conn, channel_entry,
767 silc_client_free_channel_private_keys(keys, keys_count);
775 if (!strcasecmp(argv[3], "list")) {
779 SilcPrivateMessageKeys keys;
780 SilcUInt32 keys_count;
784 keys = silc_client_list_private_message_keys(silc_client, conn,
789 /* list the private message key(s) */
790 if (nickname[0] == '*') {
791 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
792 SILCTXT_PRIVATE_KEY_LIST);
793 for (k = 0; k < keys_count; k++) {
794 memset(buf, 0, sizeof(buf));
795 strncat(buf, " ", 2);
796 len = strlen(keys[k].client_entry->nickname);
797 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
799 for (i = 0; i < 30 - len; i++)
803 len = strlen(keys[k].cipher);
804 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
806 for (i = 0; i < 14 - len; i++)
811 strcat(buf, "<hidden>");
813 strcat(buf, "*generated*");
815 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
818 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
819 SILCTXT_PRIVATE_KEY_LIST_NICK,
820 client_entry->nickname);
821 for (k = 0; k < keys_count; k++) {
822 if (keys[k].client_entry != client_entry)
825 memset(buf, 0, sizeof(buf));
826 strncat(buf, " ", 2);
827 len = strlen(keys[k].client_entry->nickname);
828 strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len);
830 for (i = 0; i < 30 - len; i++)
834 len = strlen(keys[k].cipher);
835 strncat(buf, keys[k].cipher, len > 14 ? 14 : len);
837 for (i = 0; i < 14 - len; i++)
842 strcat(buf, "<hidden>");
844 strcat(buf, "*generated*");
846 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
850 silc_client_free_private_message_keys(keys, keys_count);
852 } else if (type == 2) {
853 SilcChannelPrivateKey *keys;
854 SilcUInt32 keys_count;
858 keys = silc_client_list_channel_private_keys(silc_client, conn,
862 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
863 SILCTXT_CH_PRIVATE_KEY_LIST,
864 channel_entry->channel_name);
869 for (k = 0; k < keys_count; k++) {
870 memset(buf, 0, sizeof(buf));
871 strncat(buf, " ", 2);
873 len = strlen(silc_cipher_get_name(keys[k]->cipher));
874 strncat(buf, silc_cipher_get_name(keys[k]->cipher),
875 len > 16 ? 16 : len);
877 for (i = 0; i < 16 - len; i++)
881 len = strlen(silc_hmac_get_name(keys[k]->hmac));
882 strncat(buf, silc_hmac_get_name(keys[k]->hmac), len > 16 ? 16 : len);
884 for (i = 0; i < 16 - len; i++)
888 strcat(buf, "<hidden>");
890 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
893 silc_client_free_channel_private_keys(keys, keys_count);
899 /* Send command is used to send key agreement */
900 if (!strcasecmp(argv[3], "agreement")) {
906 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")) {
915 hostname = (char *)settings_get_str("auto_public_ip");
917 /* If the hostname isn't set, treat this case as if auto_public_ip
919 if ((hostname) && (*hostname == '\0')) {
922 bindhost = (char *)settings_get_str("auto_bind_ip");
924 /* if the bind_ip isn't set, but the public_ip IS, then assume then
925 public_ip is the same value as the bind_ip. */
926 if ((bindhost) && (*bindhost == '\0'))
928 port = settings_get_int("auto_bind_port");
930 } /* if use_auto_addr */
934 /* Start command is used to start key agreement (after receiving the
935 key_agreement client operation). */
936 if (!strcasecmp(argv[3], "negotiate")) {
942 port = atoi(argv[5]);
944 internal = silc_calloc(1, sizeof(*internal));
945 internal->type = type;
946 internal->server = server;
949 /* Change current channel private key */
950 if (!strcasecmp(argv[3], "change")) {
953 /* Unset channel key(s) */
954 SilcChannelPrivateKey *keys;
955 SilcUInt32 keys_count;
958 keys = silc_client_list_channel_private_keys(silc_client, conn,
966 if (chanrec->cur_key >= keys_count)
967 chanrec->cur_key = 0;
971 number = atoi(argv[4]);
972 if (!number || number > keys_count)
973 chanrec->cur_key = 0;
975 chanrec->cur_key = number - 1;
978 /* Set the current channel private key */
979 silc_client_current_channel_private_key(silc_client, conn,
981 keys[chanrec->cur_key]);
982 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
983 SILCTXT_CH_PRIVATE_KEY_CHANGE, chanrec->cur_key + 1,
984 channel_entry->channel_name);
986 silc_client_free_channel_private_keys(keys, keys_count);
992 silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO,
993 "Usage: /KEY msg|channel <nickname|channel> "
994 "set|unset|agreement|negotiate [<arguments>]");
998 if (command == 4 && client_entry) {
999 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1000 SILCTXT_KEY_AGREEMENT, argv[2]);
1001 internal->responder = TRUE;
1002 silc_client_send_key_agreement(
1003 silc_client, conn, client_entry, hostname,
1005 settings_get_int("key_exchange_timeout_secs"),
1006 keyagr_completion, internal);
1008 silc_free(internal);
1012 if (command == 5 && client_entry && hostname) {
1013 printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
1014 SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
1015 internal->responder = FALSE;
1016 silc_client_perform_key_agreement(silc_client, conn, client_entry,
1017 hostname, port, keyagr_completion,
1023 silc_free(nickname);
1026 void silc_list_key(const char *pub_filename, int verbose)
1028 SilcPublicKey public_key;
1029 SilcPublicKeyIdentifier ident;
1030 char *fingerprint, *babbleprint;
1034 SilcUInt32 key_len = 0;
1035 int is_server_key = (strstr(pub_filename, "serverkeys") != NULL);
1037 if (silc_pkcs_load_public_key((char *)pub_filename, &public_key,
1038 SILC_PKCS_FILE_PEM) == FALSE)
1039 if (silc_pkcs_load_public_key((char *)pub_filename, &public_key,
1040 SILC_PKCS_FILE_BIN) == FALSE) {
1041 printformat_module("fe-common/silc", NULL, NULL,
1042 MSGLEVEL_CRAP, SILCTXT_LISTKEY_LOADPUB,
1047 ident = silc_pkcs_decode_identifier(public_key->identifier);
1049 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1050 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1051 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1053 if (silc_pkcs_alloc(public_key->name, &pkcs)) {
1054 key_len = silc_pkcs_public_key_set(pkcs, public_key);
1055 silc_pkcs_free(pkcs);
1058 printformat_module("fe-common/silc", NULL, NULL,
1059 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_FILE,
1063 printformat_module("fe-common/silc", NULL, NULL,
1064 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_ALG,
1066 if (key_len && verbose)
1067 printformat_module("fe-common/silc", NULL, NULL,
1068 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_BITS,
1069 (unsigned int)key_len);
1070 if (ident->realname && (!is_server_key || verbose))
1071 printformat_module("fe-common/silc", NULL, NULL,
1072 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_RN,
1074 if (ident->username && verbose)
1075 printformat_module("fe-common/silc", NULL, NULL,
1076 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_UN,
1078 if (ident->host && (is_server_key || verbose))
1079 printformat_module("fe-common/silc", NULL, NULL,
1080 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_HN,
1082 if (ident->email && verbose)
1083 printformat_module("fe-common/silc", NULL, NULL,
1084 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_EMAIL,
1086 if (ident->org && verbose)
1087 printformat_module("fe-common/silc", NULL, NULL,
1088 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_ORG,
1090 if (ident->country && verbose)
1091 printformat_module("fe-common/silc", NULL, NULL,
1092 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_C,
1096 printformat_module("fe-common/silc", NULL, NULL,
1097 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_FINGER,
1099 printformat_module("fe-common/silc", NULL, NULL,
1100 MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_BABL,
1104 silc_free(fingerprint);
1105 silc_free(babbleprint);
1107 silc_pkcs_public_key_free(public_key);
1108 silc_pkcs_free_identifier(ident);
1113 void silc_list_keys_in_dir(const char *dirname, const char *where)
1116 struct dirent *entry;
1118 dir = opendir(dirname);
1121 cmd_return_error(CMDERR_ERRNO);
1123 printformat_module("fe-common/silc", NULL, NULL,
1124 MSGLEVEL_CRAP, SILCTXT_LISTKEY_LIST,
1129 while ((entry = readdir(dir)) != NULL) {
1130 /* try to open everything that isn't a directory */
1134 snprintf(filename, sizeof(filename) - 1, "%s/%s", dirname, entry->d_name);
1135 if (!stat(filename, &buf) && S_ISREG(buf.st_mode))
1136 silc_list_key(filename, FALSE);
1142 void silc_list_file(const char *filename)
1148 snprintf(path, sizeof(path) - 1, "%s", filename);
1149 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1152 snprintf(path, sizeof(path) - 1, "%s/%s", get_irssi_dir(), filename);
1153 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1156 snprintf(path,sizeof(path) - 1, "%s/clientkeys/%s", get_irssi_dir(),
1158 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1161 snprintf(path,sizeof(path) - 1, "%s/serverkeys/%s", get_irssi_dir(),
1163 if (!stat(path, &buf) && S_ISREG(buf.st_mode))
1170 silc_list_key(path, TRUE);
1174 /* Lists locally saved client and server public keys. */
1175 static void command_listkeys(const char *data, SILC_SERVER_REC *server,
1178 GHashTable *optlist;
1183 if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS |
1184 PARAM_FLAG_GETREST, "listkeys", &optlist,
1188 if (*filename != '\0') {
1190 silc_list_file(filename);
1193 int clients, servers;
1195 clients = (g_hash_table_lookup(optlist, "clients") != NULL);
1196 servers = (g_hash_table_lookup(optlist, "servers") != NULL);
1198 if (!(clients || servers))
1199 clients = servers = 1;
1202 snprintf(dirname, sizeof(dirname) - 1, "%s/serverkeys", get_irssi_dir());
1203 silc_list_keys_in_dir(dirname, "server");
1207 snprintf(dirname, sizeof(dirname) - 1, "%s/clientkeys", get_irssi_dir());
1208 silc_list_keys_in_dir(dirname, "client");
1211 cmd_params_free(free_arg);
1214 void silc_channels_init(void)
1216 signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
1217 signal_add("server connected", (SIGNAL_FUNC) sig_connected);
1218 signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
1219 signal_add("gui exit", (SIGNAL_FUNC) sig_gui_quit);
1220 signal_add("mime", (SIGNAL_FUNC) sig_mime);
1222 command_bind_silc("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
1223 command_bind_silc("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
1224 command_bind_silc("action", MODULE_NAME, (SIGNAL_FUNC) command_action);
1225 command_bind_silc("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
1226 command_bind_silc("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
1227 command_bind_silc("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
1228 command_bind("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
1230 command_set_options("listkeys", "clients servers");
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();