From fc93c69a223d6cd374c4cb808e156b6e19294305 Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Sun, 27 May 2001 11:04:55 +0000 Subject: [PATCH] updates. --- CHANGES | 8 + TODO | 8 + apps/irssi/config | 1 + apps/irssi/default.theme | 8 +- .../irssi/src/fe-common/silc/module-formats.c | 12 +- .../irssi/src/fe-common/silc/module-formats.h | 9 + apps/irssi/src/silc/core/Makefile.am | 4 + apps/irssi/src/silc/core/client_ops.c | 123 +- apps/irssi/src/silc/core/client_ops.h | 61 + apps/irssi/src/silc/core/clientutil.c | 8 - apps/irssi/src/silc/core/clientutil.h | 1 - apps/irssi/src/silc/core/module.h | 1 + apps/irssi/src/silc/core/silc-channels.c | 484 ++++++++ apps/irssi/src/silc/core/silc-core.c | 1092 ----------------- apps/irssi/src/silc/core/silc-queries.c | 5 +- apps/irssi/src/silc/core/silc-queries.h | 2 +- apps/irssi/src/silc/core/silc-servers.c | 2 + 17 files changed, 626 insertions(+), 1203 deletions(-) create mode 100644 apps/irssi/src/silc/core/client_ops.h diff --git a/CHANGES b/CHANGES index cf2daaaa..67d656c8 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,11 @@ +Sun May 27 12:39:48 EEST 2001 Pekka Riikonen + + * Fixed the private message sending in the Irssi SILC client, + added local command KEY to the Irssi SILC client. + + Added key management and key agreement message formats to the + irssi/src/fe-common/silc/module-formats.[ch]. + Sat May 26 17:43:42 EEST 2001 Pekka Riikonen * Fixed channel joining notify handling, cumode notify handling diff --git a/TODO b/TODO index 04e9e8d0..60920cda 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,14 @@ TODO/bugs In SILC Client Library ================================ + o The client library must manage somehow when receiving client that has + same nickname, same server, same username but different Client ID than + what we have in the cache. It is now assumed that they are different + client but it might not be. It should at least number the clients + using the client->num so that they can be accessed from the user + interface separately or it could just remove the old client unless + it is on some channels. + o Add local commands to list the current server and client public keys that the user has. And a local command to dump the contents of the public key to the screen. diff --git a/apps/irssi/config b/apps/irssi/config index 0d21cd5d..38dc7478 100644 --- a/apps/irssi/config +++ b/apps/irssi/config @@ -55,6 +55,7 @@ settings = { autoclose_windows = "no"; use_msgs_window = "no"; autocreate_windows = "no"; + autocreate_query_level = "none"; }; "fe-text" = { topicbar = "no"; mail_counter = "yes"; indent = "8"; }; }; diff --git a/apps/irssi/default.theme b/apps/irssi/default.theme index 45570475..321f3bb5 100644 --- a/apps/irssi/default.theme +++ b/apps/irssi/default.theme @@ -183,13 +183,13 @@ abstracts = { # private message from you, $0 = "msg", $1 = target nick ownprivmsg = "->*%c$1-%n* %g"; + # private message in query + privmsgnick = "*%c$0%n* "; + # own private message in query - ownprivmsgnick = "{msgnick $0-}%g"; + ownprivmsgnick = "->*%c$0%n* %g$1-"; ownprivnick = "$0-"; - # private message in query - privmsgnick = "{msgnick $0-%n}"; - ## ## other IRC events diff --git a/apps/irssi/src/fe-common/silc/module-formats.c b/apps/irssi/src/fe-common/silc/module-formats.c index 4e591058..70d61a60 100644 --- a/apps/irssi/src/fe-common/silc/module-formats.c +++ b/apps/irssi/src/fe-common/silc/module-formats.c @@ -38,7 +38,7 @@ FORMAT_REC fecommon_silc_formats[] = { { "ownaction", "{ownaction $0}", 1, { 0 } }, { "ownnotice", "{ownnotice $0}", 1, { 0 } }, - /* WHOIS and WHOWAS messages */ + /* WHOIS, WHOWAS and USERS (alias WHO) messages */ { NULL, "Who Queries", 0 }, { "whois", "{nick $0} {nickhost $1}%: realname : $2", 3, { 0, 0, 0 } }, @@ -46,6 +46,8 @@ FORMAT_REC fecommon_silc_formats[] = { { "whois_modes", " modes : $0", 1, { 0 } }, { "whois_idle", " idle : $0", 1, { 0 } }, { "whowas", "{nick $0} was {nickhost $1} ($2)", 3, { 0, 0, 0 } }, + { "users_header", "Users on {channelhilight $0}", 1, { 0 } }, + { "users", " %|{nick $[!20]0} $[!5]1 $2 {comment {hilight $3}}", 4, { 0, 0, 0, 0 } }, /* Key management and key agreement */ { NULL, "Key Management And Key Agreement", 0 }, @@ -66,5 +68,13 @@ FORMAT_REC fecommon_silc_formats[] = { { "key_agreement_failure", "Key agreement failed with {nick $0}", 1, { 0 } }, { "key_agreement_timeout", "Timeout during key agreement. The key agreement was not performed with {nick $0}", 1, { 0 } }, + /* Key management and key agreement */ + { NULL, "Misc", 0 }, + + { "server_oper", "You are now {hilight server operator}", 0, { 0 } }, + { "router_oper", "You are now {hilight SILC operator}", 0, { 0 } }, + { "list_header", " Channel Users Topic", 0, { 0 } }, + { "list", " %|{channelhilight $[36]0} {hilight $[7]1} $2", 3, { 0, 0, 0 } }, + { NULL, NULL, 0 } }; diff --git a/apps/irssi/src/fe-common/silc/module-formats.h b/apps/irssi/src/fe-common/silc/module-formats.h index c0e9e86c..640e3e73 100644 --- a/apps/irssi/src/fe-common/silc/module-formats.h +++ b/apps/irssi/src/fe-common/silc/module-formats.h @@ -42,6 +42,8 @@ enum { SILCTXT_WHOIS_MODES, SILCTXT_WHOIS_IDLE, SILCTXT_WHOWAS_USERINFO, + SILCTXT_USERS_HEADER, + SILCTXT_USERS, SILCTXT_FILL_3, @@ -61,6 +63,13 @@ enum { SILCTXT_KEY_AGREEMENT_FAILURE, SILCTXT_KEY_AGREEMENT_TIMEOUT, + SILCTXT_FILL_4, + + SILCTXT_SERVER_OPER, + SILCTXT_ROUTER_OPER, + SILCTXT_LIST_HEADER, + SILCTXT_LIST, + }; extern FORMAT_REC fecommon_silc_formats[]; diff --git a/apps/irssi/src/silc/core/Makefile.am b/apps/irssi/src/silc/core/Makefile.am index 387d87fe..039d4057 100644 --- a/apps/irssi/src/silc/core/Makefile.am +++ b/apps/irssi/src/silc/core/Makefile.am @@ -24,6 +24,7 @@ INCLUDES = \ noinst_LIBRARIES=libsilc_core.a libsilc_core_a_SOURCES = \ + client_ops.c \ clientutil.c \ clientconfig.c \ silc-channels.c \ @@ -35,6 +36,9 @@ libsilc_core_a_SOURCES = \ noinst_HEADERS = \ module.h \ + client_ops.h \ + clientutil.h \ + clientconfig.h \ silc-channels.h \ silc-core.h \ silc-nicklist.h \ diff --git a/apps/irssi/src/silc/core/client_ops.c b/apps/irssi/src/silc/core/client_ops.c index ca4f6431..f609dcee 100644 --- a/apps/irssi/src/silc/core/client_ops.c +++ b/apps/irssi/src/silc/core/client_ops.c @@ -519,14 +519,11 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, { char *topic, *name; int usercount; - unsigned char buf[256], tmp[16]; - int i, len; + char users[20]; if (!success) return; - /* XXX should use irssi routines */ - (void)va_arg(vp, SilcChannelEntry); name = va_arg(vp, char *); topic = va_arg(vp, char *); @@ -534,35 +531,13 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, if (status == SILC_STATUS_LIST_START || status == SILC_STATUS_OK) - silc_say(client, conn, - " Channel Users Topic"); - - memset(buf, 0, sizeof(buf)); - strncat(buf, " ", 2); - len = strlen(name); - strncat(buf, name, len > 40 ? 40 : len); - if (len < 40) - for (i = 0; i < 40 - len; i++) - strcat(buf, " "); - strcat(buf, " "); - - memset(tmp, 0, sizeof(tmp)); - if (usercount) { - snprintf(tmp, sizeof(tmp), "%d", usercount); - strcat(buf, tmp); - } - len = strlen(tmp); - if (len < 10) - for (i = 0; i < 10 - len; i++) - strcat(buf, " "); - strcat(buf, " "); - - if (topic) { - len = strlen(topic); - strncat(buf, topic, len); - } - - silc_say(client, conn, "%s", buf); + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_LIST_HEADER); + + snprintf(users, sizeof(users) - 1, "%d", usercount); + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_LIST, + name, users, topic ? topic : ""); } break; @@ -580,88 +555,50 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, break; case SILC_COMMAND_OPER: - silc_say(client, conn, "You are now server operator"); + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_SERVER_OPER); break; case SILC_COMMAND_SILCOPER: - silc_say(client, conn, "You are now SILC operator"); + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER); break; case SILC_COMMAND_USERS: { SilcChannelEntry channel; SilcChannelUser chu; - int line_len; - char *line; if (!success) return; channel = va_arg(vp, SilcChannelEntry); - /* There are two ways to do this, either parse the list (that - the command_reply sends (just take it with va_arg()) or just - traverse the channel's client list. I'll do the latter. See - JOIN command reply for example for the list. */ - - silc_say(client, conn, "Users on %s", channel->channel_name); - - line = silc_calloc(1024, sizeof(*line)); - line_len = 1024; + printformat_module("fe-common/silc", server, channel->channel_name, + MSGLEVEL_CRAP, SILCTXT_USERS_HEADER, + channel->channel_name); + silc_list_start(channel->clients); while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) { SilcClientEntry e = chu->client; - int i, len1; - char *m, tmp[80]; - - memset(line, 0, line_len); - - if (strlen(e->nickname) + strlen(e->server) + 100 > line_len) { - silc_free(line); - line_len += strlen(e->nickname) + strlen(e->server) + 100; - line = silc_calloc(line_len, sizeof(*line)); - } - - memset(tmp, 0, sizeof(tmp)); - m = silc_client_chumode_char(chu->mode); - - strncat(line, " ", 1); - strncat(line, e->nickname, strlen(e->nickname)); - strncat(line, e->server ? "@" : "", 1); - - len1 = 0; - if (e->server) - len1 = strlen(e->server); - strncat(line, e->server ? e->server : "", len1 > 30 ? 30 : len1); - - len1 = strlen(line); - if (len1 >= 30) { - memset(&line[29], 0, len1 - 29); - } else { - for (i = 0; i < 30 - len1 - 1; i++) - strcat(line, " "); - } + char stat[5], *mode; + memset(stat, 0, sizeof(stat)); + mode = silc_client_chumode_char(chu->mode); if (e->mode & SILC_UMODE_GONE) - strcat(line, " G"); + strcat(stat, "G"); else - strcat(line, " H"); - strcat(tmp, m ? m : ""); - strncat(line, tmp, strlen(tmp)); - - if (strlen(tmp) < 5) - for (i = 0; i < 5 - strlen(tmp); i++) - strcat(line, " "); - - strcat(line, e->username ? e->username : ""); - - silc_say(client, conn, "%s", line); - - if (m) - silc_free(m); + strcat(stat, "H"); + if (mode) + strcat(stat, mode); + + printformat_module("fe-common/silc", server, channel->channel_name, + MSGLEVEL_CRAP, SILCTXT_USERS, + e->nickname, stat, e->username, + e->realname ? e->realname : ""); + if (mode) + silc_free(mode); } - - silc_free(line); } break; diff --git a/apps/irssi/src/silc/core/client_ops.h b/apps/irssi/src/silc/core/client_ops.h new file mode 100644 index 00000000..c92ed024 --- /dev/null +++ b/apps/irssi/src/silc/core/client_ops.h @@ -0,0 +1,61 @@ +/* + + client_ops.h + + Author: Pekka Riikonen + + Copyright (C) 2001 Pekka Riikonen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*/ + +#ifndef CLIENT_OPS_H +#define CLIENT_OPS_H + +void silc_say(SilcClient client, SilcClientConnection conn, char *msg, ...); +void silc_say_error(char *msg, ...); +void silc_channel_message(SilcClient client, SilcClientConnection conn, + SilcClientEntry sender, + SilcChannelEntry channel, + SilcMessageFlags flags, char *msg); +void silc_private_message(SilcClient client, SilcClientConnection conn, + SilcClientEntry sender, + SilcMessageFlags flags, char *msg); +void silc_notify(SilcClient client, SilcClientConnection conn, + SilcNotifyType type, ...); +void silc_command(SilcClient client, SilcClientConnection conn, + SilcClientCommandContext cmd_context, int success, + SilcCommand command); +void silc_command_reply(SilcClient client, SilcClientConnection conn, + SilcCommandPayload cmd_payload, int success, + SilcCommand command, SilcCommandStatus status, ...); +void silc_connect(SilcClient client, SilcClientConnection conn, int success); +void silc_disconnect(SilcClient client, SilcClientConnection conn); +void silc_ask_passphrase(SilcClient client, SilcClientConnection conn, + SilcAskPassphrase completion, void *context); +void silc_verify_public_key(SilcClient client, SilcClientConnection conn, + SilcSocketType conn_type, unsigned char *pk, + uint32 pk_len, SilcSKEPKType pk_type, + SilcVerifyPublicKey completion, void *context); +int silc_get_auth_method(SilcClient client, SilcClientConnection conn, + char *hostname, uint16 port, + SilcProtocolAuthMeth *auth_meth, + unsigned char **auth_data, + uint32 *auth_data_len); +void silc_failure(SilcClient client, SilcClientConnection conn, + SilcProtocol protocol, void *failure); +int silc_key_agreement(SilcClient client, SilcClientConnection conn, + SilcClientEntry client_entry, char *hostname, + int port, + SilcKeyAgreementCallback *completion, + void **context); +#endif diff --git a/apps/irssi/src/silc/core/clientutil.c b/apps/irssi/src/silc/core/clientutil.c index 77607adc..cbd0c184 100644 --- a/apps/irssi/src/silc/core/clientutil.c +++ b/apps/irssi/src/silc/core/clientutil.c @@ -43,14 +43,6 @@ #include "fe-common/core/printtext.h" #include "fe-common/core/keyboard.h" -/* Asks yes/no from user on the input line. Returns TRUE on "yes" and - FALSE on "no". */ - -void silc_client_ask_yes_no(char *prompt, SIGNAL_FUNC func) -{ - keyboard_entry_redirect(func, prompt, 0, NULL); -} - /* Lists supported (builtin) ciphers */ void silc_client_list_ciphers() diff --git a/apps/irssi/src/silc/core/clientutil.h b/apps/irssi/src/silc/core/clientutil.h index 7a3b946d..ab7c0208 100644 --- a/apps/irssi/src/silc/core/clientutil.h +++ b/apps/irssi/src/silc/core/clientutil.h @@ -24,7 +24,6 @@ #include "signals.h" /* Prototypes */ -void silc_client_ask_yes_no(char *prompt, SIGNAL_FUNC func); char *silc_client_get_input(const char *prompt); void silc_client_list_ciphers(); void silc_client_list_hash_funcs(); diff --git a/apps/irssi/src/silc/core/module.h b/apps/irssi/src/silc/core/module.h index aadd8161..b3c19a49 100644 --- a/apps/irssi/src/silc/core/module.h +++ b/apps/irssi/src/silc/core/module.h @@ -6,6 +6,7 @@ #undef VERSION #include "silcincludes.h" #include "clientlibincludes.h" +#include "client_ops.h" #include "silc-core.h" #define SILC_PROTOCOL (chat_protocol_lookup("SILC")) diff --git a/apps/irssi/src/silc/core/silc-channels.c b/apps/irssi/src/silc/core/silc-channels.c index 85255669..57678937 100644 --- a/apps/irssi/src/silc/core/silc-channels.c +++ b/apps/irssi/src/silc/core/silc-channels.c @@ -545,6 +545,488 @@ static void command_away(const char *data, SILC_SERVER_REC *server, /* XXX TODO */ } +typedef struct { + int type; /* 1 = msg, 2 = channel */ + SILC_SERVER_REC *server; +} *KeyInternal; + +static SilcSKEKeyMaterial *curr_key = NULL; + +/* Key agreement callback that is called after the key agreement protocol + has been performed. This is called also if error occured during the + key agreement protocol. The `key' is the allocated key material and + the caller is responsible of freeing it. The `key' is NULL if error + has occured. The application can freely use the `key' to whatever + purpose it needs. See lib/silcske/silcske.h for the definition of + the SilcSKEKeyMaterial structure. */ + +static void keyagr_completion(SilcClient client, + SilcClientConnection conn, + SilcClientEntry client_entry, + SilcKeyAgreementStatus status, + SilcSKEKeyMaterial *key, + void *context) +{ + KeyInternal i = (KeyInternal)context; + + curr_key = NULL; + + switch(status) { + case SILC_KEY_AGREEMENT_OK: + printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES, + SILCTXT_KEY_AGREEMENT_OK, client_entry->nickname); + + if (i->type == 1) { + /* Set the private key for this client */ + silc_client_del_private_message_key(client, conn, client_entry); + silc_client_add_private_message_key_ske(client, conn, client_entry, + NULL, key); + printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES, + SILCTXT_KEY_AGREEMENT_PRIVMSG, + client_entry->nickname); + silc_ske_free_key_material(key); + } + + break; + + case SILC_KEY_AGREEMENT_ERROR: + printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES, + SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname); + break; + + case SILC_KEY_AGREEMENT_FAILURE: + printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES, + SILCTXT_KEY_AGREEMENT_FAILURE, client_entry->nickname); + break; + + case SILC_KEY_AGREEMENT_TIMEOUT: + printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_NOTICES, + SILCTXT_KEY_AGREEMENT_TIMEOUT, client_entry->nickname); + break; + + default: + break; + } + + if (i) + silc_free(i); +} + +/* Local command KEY. This command is used to set and unset private + keys for channels, set and unset private keys for private messages + with remote clients and to send key agreement requests and + negotiate the key agreement protocol with remote client. The + key agreement is supported only to negotiate private message keys, + it currently cannot be used to negotiate private keys for channels, + as it is not convenient for that purpose. */ + +typedef struct { + SILC_SERVER_REC *server; + char *data; + WI_ITEM_REC *item; +} *KeyGetClients; + +/* Callback to be called after client information is resolved from the + server. */ + +SILC_CLIENT_CMD_FUNC(key_get_clients) +{ + KeyGetClients internal = (KeyGetClients)context; + signal_emit("command key", 3, internal->data, internal->server, + internal->item); + silc_free(internal->data); + silc_free(internal); +} + +static void command_key(const char *data, SILC_SERVER_REC *server, + WI_ITEM_REC *item) +{ + SilcClientConnection conn = server->conn; + SilcClientEntry client_entry = NULL; + SilcChannelEntry channel_entry = NULL; + uint32 num = 0; + char *nickname = NULL, *serv = NULL, *tmp; + int command = 0, port = 0, type = 0; + char *hostname = NULL; + KeyInternal internal = NULL; + uint32 argc = 0; + unsigned char **argv; + uint32 *argv_lens, *argv_types; + + if (!IS_SILC_SERVER(server) || !server->connected) + cmd_return_error(CMDERR_NOT_CONNECTED); + + /* Now parse all arguments */ + tmp = g_strconcat("KEY", " ", data, NULL); + silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 7); + g_free(tmp); + + if (argc < 4) { + silc_say(silc_client, conn, "Usage: /KEY msg|channel " + "set|unset|agreement|negotiate []"); + return; + } + + /* Get type */ + if (!strcasecmp(argv[1], "msg")) + type = 1; + if (!strcasecmp(argv[1], "channel")) + type = 2; + + if (type == 0) { + silc_say(silc_client, conn, "Usage: /KEY msg|channel " + "set|unset|agreement|negotiate []"); + return; + } + + if (type == 1) { + if (argv[2][0] == '*') { + nickname = "*"; + } else { + /* Parse the typed nickname. */ + if (!silc_parse_nickname(argv[2], &nickname, &serv, &num)) { + silc_say(silc_client, conn, "Bad nickname"); + return; + } + + /* Find client entry */ + client_entry = silc_idlist_get_client(silc_client, conn, nickname, + serv, num, TRUE); + if (!client_entry) { + KeyGetClients inter = silc_calloc(1, sizeof(*inter)); + inter->server = server; + inter->data = strdup(data); + inter->item = item; + + /* Client entry not found, it was requested thus mark this to be + pending command. */ + silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, + conn->cmd_ident, + NULL, silc_client_command_key_get_clients, + inter); + goto out; + } + } + } + + if (type == 2) { + /* Get channel entry */ + char *name; + + if (argv[2][0] == '*') { + if (!conn->current_channel) { + if (nickname) + silc_free(nickname); + if (serv) + silc_free(serv); + cmd_return_error(CMDERR_NOT_JOINED); + } + name = conn->current_channel->channel_name; + } else { + name = argv[2]; + } + + channel_entry = silc_client_get_channel(silc_client, conn, name); + if (!channel_entry) { + if (nickname) + silc_free(nickname); + if (serv) + silc_free(serv); + cmd_return_error(CMDERR_NOT_JOINED); + } + } + + /* Set command */ + if (!strcasecmp(argv[3], "set")) { + command = 1; + + if (argc == 4) { + if (curr_key && type == 1 && client_entry) { + silc_client_del_private_message_key(silc_client, conn, client_entry); + silc_client_add_private_message_key_ske(silc_client, conn, + client_entry, NULL, curr_key); + goto out; + } + } + + if (argc >= 5) { + if (type == 1 && client_entry) { + /* Set private message key */ + + silc_client_del_private_message_key(silc_client, conn, client_entry); + + if (argc >= 6) + silc_client_add_private_message_key(silc_client, conn, client_entry, + argv[5], argv[4], + argv_lens[4], + (argv[4][0] == '*' ? + TRUE : FALSE)); + else + silc_client_add_private_message_key(silc_client, conn, client_entry, + NULL, argv[4], + argv_lens[4], + (argv[4][0] == '*' ? + TRUE : FALSE)); + + /* Send the key to the remote client so that it starts using it + too. */ + silc_client_send_private_message_key(silc_client, conn, + client_entry, TRUE); + } else if (type == 2) { + /* Set private channel key */ + char *cipher = NULL, *hmac = NULL; + + if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) { + printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, + SILCTXT_CH_PRIVATE_KEY_NOMODE, + channel_entry->channel_name); + goto out; + } + + if (argc >= 6) + cipher = argv[5]; + if (argc >= 7) + hmac = argv[6]; + + if (!silc_client_add_channel_private_key(silc_client, conn, + channel_entry, + cipher, hmac, + argv[4], + argv_lens[4])) { + printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, + SILCTXT_CH_PRIVATE_KEY_ERROR, + channel_entry->channel_name); + goto out; + } + + printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, + SILCTXT_CH_PRIVATE_KEY_ADD, + channel_entry->channel_name); + } + } + + goto out; + } + + /* Unset command */ + if (!strcasecmp(argv[3], "unset")) { + command = 2; + + if (type == 1 && client_entry) { + /* Unset private message key */ + silc_client_del_private_message_key(silc_client, conn, client_entry); + } else if (type == 2) { + /* Unset channel key(s) */ + SilcChannelPrivateKey *keys; + uint32 keys_count; + int number; + + if (argc == 4) + silc_client_del_channel_private_keys(silc_client, conn, + channel_entry); + + if (argc > 4) { + number = atoi(argv[4]); + keys = silc_client_list_channel_private_keys(silc_client, conn, + channel_entry, + &keys_count); + if (!keys) + goto out; + + if (!number || number > keys_count) { + silc_client_free_channel_private_keys(keys, keys_count); + goto out; + } + + silc_client_del_channel_private_key(silc_client, conn, channel_entry, + keys[number - 1]); + silc_client_free_channel_private_keys(keys, keys_count); + } + + goto out; + } + } + + /* List command */ + if (!strcasecmp(argv[3], "list")) { + command = 3; + + if (type == 1) { + SilcPrivateMessageKeys keys; + uint32 keys_count; + int k, i, len; + char buf[1024]; + + keys = silc_client_list_private_message_keys(silc_client, conn, + &keys_count); + if (!keys) + goto out; + + /* list the private message key(s) */ + if (nickname[0] == '*') { + printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, + SILCTXT_PRIVATE_KEY_LIST); + for (k = 0; k < keys_count; k++) { + memset(buf, 0, sizeof(buf)); + strncat(buf, " ", 2); + len = strlen(keys[k].client_entry->nickname); + strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len); + if (len < 30) + for (i = 0; i < 30 - len; i++) + strcat(buf, " "); + strcat(buf, " "); + + len = strlen(keys[k].cipher); + strncat(buf, keys[k].cipher, len > 14 ? 14 : len); + if (len < 14) + for (i = 0; i < 14 - len; i++) + strcat(buf, " "); + strcat(buf, " "); + + if (keys[k].key) + strcat(buf, ""); + else + strcat(buf, "*generated*"); + + silc_say(silc_client, conn, "%s", buf); + } + } else { + printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, + SILCTXT_PRIVATE_KEY_LIST_NICK, + client_entry->nickname); + for (k = 0; k < keys_count; k++) { + if (keys[k].client_entry != client_entry) + continue; + + memset(buf, 0, sizeof(buf)); + strncat(buf, " ", 2); + len = strlen(keys[k].client_entry->nickname); + strncat(buf, keys[k].client_entry->nickname, len > 30 ? 30 : len); + if (len < 30) + for (i = 0; i < 30 - len; i++) + strcat(buf, " "); + strcat(buf, " "); + + len = strlen(keys[k].cipher); + strncat(buf, keys[k].cipher, len > 14 ? 14 : len); + if (len < 14) + for (i = 0; i < 14 - len; i++) + strcat(buf, " "); + strcat(buf, " "); + + if (keys[k].key) + strcat(buf, ""); + else + strcat(buf, "*generated*"); + + silc_say(silc_client, conn, "%s", buf); + } + } + + silc_client_free_private_message_keys(keys, keys_count); + } else if (type == 2) { + SilcChannelPrivateKey *keys; + uint32 keys_count; + int k, i, len; + char buf[1024]; + + keys = silc_client_list_channel_private_keys(silc_client, conn, + channel_entry, + &keys_count); + if (!keys) + goto out; + + printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, + SILCTXT_CH_PRIVATE_KEY_LIST, + channel_entry->channel_name); + for (k = 0; k < keys_count; k++) { + memset(buf, 0, sizeof(buf)); + strncat(buf, " ", 2); + + len = strlen(keys[k]->cipher->cipher->name); + strncat(buf, keys[k]->cipher->cipher->name, len > 16 ? 16 : len); + if (len < 16) + for (i = 0; i < 16 - len; i++) + strcat(buf, " "); + strcat(buf, " "); + + len = strlen(keys[k]->hmac->hmac->name); + strncat(buf, keys[k]->hmac->hmac->name, len > 16 ? 16 : len); + if (len < 16) + for (i = 0; i < 16 - len; i++) + strcat(buf, " "); + strcat(buf, " "); + + strcat(buf, ""); + + silc_say(silc_client, conn, "%s", buf); + } + + silc_client_free_channel_private_keys(keys, keys_count); + } + + goto out; + } + + /* Send command is used to send key agreement */ + if (!strcasecmp(argv[3], "agreement")) { + command = 4; + + if (argc >= 5) + hostname = argv[4]; + if (argc >= 6) + port = atoi(argv[5]); + + internal = silc_calloc(1, sizeof(*internal)); + internal->type = type; + internal->server = server; + } + + /* Start command is used to start key agreement (after receiving the + key_agreement client operation). */ + if (!strcasecmp(argv[3], "negotiate")) { + command = 5; + + if (argc >= 5) + hostname = argv[4]; + if (argc >= 6) + port = atoi(argv[5]); + + internal = silc_calloc(1, sizeof(*internal)); + internal->type = type; + internal->server = server; + } + + if (command == 0) { + silc_say(silc_client, conn, "Usage: /KEY msg|channel " + "set|unset|agreement|negotiate []"); + goto out; + } + + if (command == 4 && client_entry) { + printformat_module("fe-common/silc", server, NULL, MSGLEVEL_NOTICES, + SILCTXT_KEY_AGREEMENT, argv[2]); + silc_client_send_key_agreement(silc_client, conn, client_entry, hostname, + port, 120, keyagr_completion, internal); + goto out; + } + + if (command == 5 && client_entry && hostname) { + printformat_module("fe-common/silc", server, NULL, MSGLEVEL_NOTICES, + SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]); + silc_client_perform_key_agreement(silc_client, conn, client_entry, + hostname, port, keyagr_completion, + internal); + goto out; + } + + out: + if (nickname) + silc_free(nickname); + if (serv) + silc_free(serv); +} + void silc_channels_init(void) { signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed); @@ -570,6 +1052,7 @@ void silc_channels_init(void) command_bind("me", MODULE_NAME, (SIGNAL_FUNC) command_me); command_bind("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice); command_bind("away", MODULE_NAME, (SIGNAL_FUNC) command_away); + command_bind("key", MODULE_NAME, (SIGNAL_FUNC) command_key); silc_nicklist_init(); } @@ -601,6 +1084,7 @@ void silc_channels_deinit(void) command_unbind("me", (SIGNAL_FUNC) command_me); command_unbind("notice", (SIGNAL_FUNC) command_notice); command_unbind("away", (SIGNAL_FUNC) command_away); + command_unbind("key", (SIGNAL_FUNC) command_key); silc_nicklist_deinit(); } diff --git a/apps/irssi/src/silc/core/silc-core.c b/apps/irssi/src/silc/core/silc-core.c index 2b823ed2..4cfcd54d 100644 --- a/apps/irssi/src/silc/core/silc-core.c +++ b/apps/irssi/src/silc/core/silc-core.c @@ -59,1098 +59,6 @@ SilcSimContext **sims = NULL; uint32 sims_count = 0; #endif -static void silc_say(SilcClient client, SilcClientConnection conn, - char *msg, ...); -static void -silc_channel_message(SilcClient client, SilcClientConnection conn, - SilcClientEntry sender, SilcChannelEntry channel, - SilcMessageFlags flags, char *msg); -static void -silc_private_message(SilcClient client, SilcClientConnection conn, - SilcClientEntry sender, SilcMessageFlags flags, - char *msg); -static void silc_notify(SilcClient client, SilcClientConnection conn, - SilcNotifyType type, ...); -static void -silc_connect(SilcClient client, SilcClientConnection conn, int success); -static void -silc_disconnect(SilcClient client, SilcClientConnection conn); -static void -silc_command(SilcClient client, SilcClientConnection conn, - SilcClientCommandContext cmd_context, int success, - SilcCommand command); -static void -silc_command_reply(SilcClient client, SilcClientConnection conn, - SilcCommandPayload cmd_payload, int success, - SilcCommand command, SilcCommandStatus status, ...); -static void -silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn, - SilcSocketType conn_type, unsigned char *pk, - uint32 pk_len, SilcSKEPKType pk_type, - SilcVerifyPublicKey completion, void *context); -static void -silc_verify_public_key(SilcClient client, SilcClientConnection conn, - SilcSocketType conn_type, unsigned char *pk, - uint32 pk_len, SilcSKEPKType pk_type, - SilcVerifyPublicKey completion, void *context); -static void silc_ask_passphrase(SilcClient client, SilcClientConnection conn, - SilcAskPassphrase completion, void *context); -static int -silc_get_auth_method(SilcClient client, SilcClientConnection conn, - char *hostname, uint16 port, - SilcProtocolAuthMeth *auth_meth, - unsigned char **auth_data, - uint32 *auth_data_len); -static void -silc_failure(SilcClient client, SilcClientConnection conn, - SilcProtocol protocol, void *failure); -static int -silc_key_agreement(SilcClient client, SilcClientConnection conn, - SilcClientEntry client_entry, char *hostname, - int port, - SilcKeyAgreementCallback *completion, - void **context); - -static void silc_say(SilcClient client, SilcClientConnection conn, - char *msg, ...) -{ - SILC_SERVER_REC *server; - va_list va; - char *str; - - server = conn == NULL ? NULL : conn->context; - - va_start(va, msg); - str = g_strdup_vprintf(msg, va); - printtext(server, NULL, MSGLEVEL_CRAP, "%s", str); - g_free(str); - va_end(va); -} - -static void silc_say_error(char *msg, ...) -{ - va_list va; - char *str; - - va_start(va, msg); - str = g_strdup_vprintf(msg, va); - printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", str); - - g_free(str); - va_end(va); -} - -/* Message for a channel. The `sender' is the nickname of the sender - received in the packet. The `channel_name' is the name of the channel. */ - -static void -silc_channel_message(SilcClient client, SilcClientConnection conn, - SilcClientEntry sender, SilcChannelEntry channel, - SilcMessageFlags flags, char *msg) -{ - SILC_SERVER_REC *server; - SILC_NICK_REC *nick; - SILC_CHANNEL_REC *chanrec; - - server = conn == NULL ? NULL : conn->context; - chanrec = silc_channel_find_entry(server, channel); - - nick = silc_nicklist_find(chanrec, sender); - - if (flags & SILC_MESSAGE_FLAG_ACTION) - printformat_module("fe-common/silc", server, channel->channel_name, - MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION, msg); - else if (flags & SILC_MESSAGE_FLAG_NOTICE) - printformat_module("fe-common/silc", server, channel->channel_name, - MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE, msg); - else - signal_emit("message public", 6, server, msg, - nick == NULL ? "[]" : nick->nick, - nick == NULL ? NULL : nick->host, - chanrec->name, nick); -} - -/* Private message to the client. The `sender' is the nickname of the - sender received in the packet. */ - -static void -silc_private_message(SilcClient client, SilcClientConnection conn, - SilcClientEntry sender, SilcMessageFlags flags, - char *msg) -{ - SILC_SERVER_REC *server; - - server = conn == NULL ? NULL : conn->context; - signal_emit("message private", 4, server, msg, - sender->nickname ? sender->nickname : "[]", - sender->username ? sender->username : NULL); -} - -/* Notify message to the client. The notify arguments are sent in the - same order as servers sends them. The arguments are same as received - from the server except for ID's. If ID is received application receives - the corresponding entry to the ID. For example, if Client ID is received - application receives SilcClientEntry. Also, if the notify type is - for channel the channel entry is sent to application (even if server - does not send it). */ - -typedef struct { - int type; - const char *name; -} NOTIFY_REC; - -#define MAX_NOTIFY (sizeof(notifies)/sizeof(notifies[0])) -static NOTIFY_REC notifies[] = { - { SILC_NOTIFY_TYPE_NONE, NULL }, - { SILC_NOTIFY_TYPE_INVITE, "invite" }, - { SILC_NOTIFY_TYPE_JOIN, "join" }, - { SILC_NOTIFY_TYPE_LEAVE, "leave" }, - { SILC_NOTIFY_TYPE_SIGNOFF, "signoff" }, - { SILC_NOTIFY_TYPE_TOPIC_SET, "topic" }, - { SILC_NOTIFY_TYPE_NICK_CHANGE, "nick" }, - { SILC_NOTIFY_TYPE_CMODE_CHANGE, "cmode" }, - { SILC_NOTIFY_TYPE_CUMODE_CHANGE, "cumode" }, - { SILC_NOTIFY_TYPE_MOTD, "motd" }, - { SILC_NOTIFY_TYPE_CHANNEL_CHANGE, "channel_change" }, - { SILC_NOTIFY_TYPE_SERVER_SIGNOFF, "server_signoff" }, - { SILC_NOTIFY_TYPE_KICKED, "kick" }, - { SILC_NOTIFY_TYPE_KILLED, "kill" }, - { SILC_NOTIFY_TYPE_UMODE_CHANGE, "umode" }, - { SILC_NOTIFY_TYPE_BAN, "ban" }, -}; - -static void silc_notify(SilcClient client, SilcClientConnection conn, - SilcNotifyType type, ...) -{ - SILC_SERVER_REC *server; - va_list va; - - server = conn == NULL ? NULL : conn->context; - va_start(va, type); - - if (type == SILC_NOTIFY_TYPE_NONE) { - /* Some generic notice from server */ - printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *)); - } else if (type < MAX_NOTIFY) { - /* Send signal about the notify event */ - char signal[50]; - g_snprintf(signal, sizeof(signal), "silc event %s", notifies[type].name); - signal_emit(signal, 2, server, va); - } else { - /* Unknown notify */ - printtext(server, NULL, MSGLEVEL_CRAP, "Unknown notify type %d", type); - } - - va_end(va); -} - -/* Called to indicate that connection was either successfully established - or connecting failed. This is also the first time application receives - the SilcClientConnection objecet which it should save somewhere. */ - -static void -silc_connect(SilcClient client, SilcClientConnection conn, int success) -{ - SILC_SERVER_REC *server = conn->context; - - if (success) { - server->connected = TRUE; - signal_emit("event connected", 1, server); - } else { - server->connection_lost = TRUE; - server->conn->context = NULL; - server_disconnect(SERVER(server)); - } -} - -/* Called to indicate that connection was disconnected to the server. */ - -static void -silc_disconnect(SilcClient client, SilcClientConnection conn) -{ - SILC_SERVER_REC *server = conn->context; - - server->conn->context = NULL; - server->conn = NULL; - server->connection_lost = TRUE; - server_disconnect(SERVER(server)); -} - -/* Command handler. This function is called always in the command function. - If error occurs it will be called as well. `conn' is the associated - client connection. `cmd_context' is the command context that was - originally sent to the command. `success' is FALSE if error occured - during command. `command' is the command being processed. It must be - noted that this is not reply from server. This is merely called just - after application has called the command. Just to tell application - that the command really was processed. */ - -static void -silc_command(SilcClient client, SilcClientConnection conn, - SilcClientCommandContext cmd_context, int success, - SilcCommand command) -{ -} - -/* Client info resolving callback when JOIN command reply is received. - This will cache all users on the channel. */ - -void silc_client_join_get_users(SilcClient client, - SilcClientConnection conn, - SilcClientEntry *clients, - uint32 clients_count, - void *context) -{ - SilcChannelEntry channel = (SilcChannelEntry)context; - SilcChannelUser chu; - SILC_SERVER_REC *server = conn->context; - SILC_CHANNEL_REC *chanrec; - SilcClientEntry founder = NULL; - NICK_REC *ownnick; - - if (!clients) - return; - - chanrec = silc_channel_find(server, channel->channel_name); - if (chanrec == NULL) - return; - - silc_list_start(channel->clients); - while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) { - if (chu->mode & SILC_CHANNEL_UMODE_CHANFO) - founder = chu->client; - silc_nicklist_insert(chanrec, chu, FALSE); - } - - ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry)); - nicklist_set_own(CHANNEL(chanrec), ownnick); - signal_emit("channel joined", 1, chanrec); - - if (chanrec->topic) - printformat_module("fe-common/silc", server, channel->channel_name, - MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC, - channel->channel_name, chanrec->topic); - - fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL); - - if (founder) { - if (founder == conn->local_entry) - printformat_module("fe-common/silc", - server, channel->channel_name, MSGLEVEL_CRAP, - SILCTXT_CHANNEL_FOUNDER_YOU, - channel->channel_name); - else - printformat_module("fe-common/silc", - server, channel->channel_name, MSGLEVEL_CRAP, - SILCTXT_CHANNEL_FOUNDER, - channel->channel_name, founder->nickname); - } -} - -/* Command reply handler. This function is called always in the command reply - function. If error occurs it will be called as well. Normal scenario - is that it will be called after the received command data has been parsed - and processed. The function is used to pass the received command data to - the application. - - `conn' is the associated client connection. `cmd_payload' is the command - payload data received from server and it can be ignored. It is provided - if the application would like to re-parse the received command data, - however, it must be noted that the data is parsed already by the library - thus the payload can be ignored. `success' is FALSE if error occured. - In this case arguments are not sent to the application. `command' is the - command reply being processed. The function has variable argument list - and each command defines the number and type of arguments it passes to the - application (on error they are not sent). */ - -static void -silc_command_reply(SilcClient client, SilcClientConnection conn, - SilcCommandPayload cmd_payload, int success, - SilcCommand command, SilcCommandStatus status, ...) - -{ - SILC_SERVER_REC *server = conn->context; - SILC_CHANNEL_REC *chanrec; - va_list vp; - - va_start(vp, status); - - switch(command) { - case SILC_COMMAND_WHOIS: - { - char buf[1024], *nickname, *username, *realname; - uint32 idle, mode; - SilcBuffer channels; - - if (status == SILC_STATUS_ERR_NO_SUCH_NICK || - status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) { - char *tmp; - tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload), - 3, NULL); - if (tmp) - silc_say_error("%s: %s", tmp, - silc_client_command_status_message(status)); - else - silc_say_error("%s", silc_client_command_status_message(status)); - break; - } - - if (!success) - return; - - (void)va_arg(vp, SilcClientEntry); - nickname = va_arg(vp, char *); - username = va_arg(vp, char *); - realname = va_arg(vp, char *); - channels = va_arg(vp, SilcBuffer); - mode = va_arg(vp, uint32); - idle = va_arg(vp, uint32); - - printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, - SILCTXT_WHOIS_USERINFO, nickname, username, - realname); - - if (channels) { - SilcDList list = silc_channel_payload_parse_list(channels); - if (list) { - SilcChannelPayload entry; - memset(buf, 0, sizeof(buf)); - silc_dlist_start(list); - while ((entry = silc_dlist_get(list)) != SILC_LIST_END) { - char *m = silc_client_chumode_char(silc_channel_get_mode(entry)); - uint32 name_len; - char *name = silc_channel_get_name(entry, &name_len); - - if (m) - strncat(buf, m, strlen(m)); - strncat(buf, name, name_len); - strncat(buf, " ", 1); - silc_free(m); - } - - printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, - SILCTXT_WHOIS_CHANNELS, buf); - silc_channel_payload_list_free(list); - } - } - - if (mode) { - memset(buf, 0, sizeof(buf)); - - if ((mode & SILC_UMODE_SERVER_OPERATOR) || - (mode & SILC_UMODE_ROUTER_OPERATOR)) { - strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ? - "Server Operator " : - (mode & SILC_UMODE_ROUTER_OPERATOR) ? - "SILC Operator " : "[Unknown mode] "); - } - if (mode & SILC_UMODE_GONE) - strcat(buf, "away"); - - printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, - SILCTXT_WHOIS_MODES, buf); - } - - if (idle && nickname) { - memset(buf, 0, sizeof(buf)); - snprintf(buf, sizeof(buf) - 1, "%lu %s", - idle > 60 ? (idle / 60) : idle, - idle > 60 ? "minutes" : "seconds"); - - printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, - SILCTXT_WHOIS_IDLE, buf); - } - } - break; - - case SILC_COMMAND_WHOWAS: - { - char *nickname, *username, *realname; - - if (status == SILC_STATUS_ERR_NO_SUCH_NICK || - status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) { - char *tmp; - tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload), - 3, NULL); - if (tmp) - silc_say_error("%s: %s", tmp, - silc_client_command_status_message(status)); - else - silc_say_error("%s", silc_client_command_status_message(status)); - break; - } - - if (!success) - return; - - (void)va_arg(vp, SilcClientEntry); - nickname = va_arg(vp, char *); - username = va_arg(vp, char *); - realname = va_arg(vp, char *); - - printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, - SILCTXT_WHOWAS_USERINFO, nickname, username, - realname ? realname : ""); - } - break; - - case SILC_COMMAND_INVITE: - { - SilcChannelEntry channel; - char *invite_list; - - if (!success) - return; - - /* XXX should use irssi routines */ - - channel = va_arg(vp, SilcChannelEntry); - invite_list = va_arg(vp, char *); - - if (invite_list) - silc_say(client, conn, "%s invite list: %s", channel->channel_name, - invite_list); - else - silc_say(client, conn, "%s invite list not set", - channel->channel_name); - } - break; - - case SILC_COMMAND_JOIN: - { - char *channel, *mode, *topic; - uint32 modei; - SilcChannelEntry channel_entry; - SilcBuffer client_id_list; - uint32 list_count; - - channel = va_arg(vp, char *); - channel_entry = va_arg(vp, SilcChannelEntry); - modei = va_arg(vp, uint32); - (void)va_arg(vp, uint32); - (void)va_arg(vp, unsigned char *); - (void)va_arg(vp, unsigned char *); - (void)va_arg(vp, unsigned char *); - topic = va_arg(vp, char *); - (void)va_arg(vp, unsigned char *); - list_count = va_arg(vp, uint32); - client_id_list = va_arg(vp, SilcBuffer); - - if (!success) - return; - - chanrec = silc_channel_find(server, channel); - if (chanrec != NULL && !success) - channel_destroy(CHANNEL(chanrec)); - else if (chanrec == NULL && success) - chanrec = silc_channel_create(server, channel, TRUE); - - if (topic) { - g_free_not_null(chanrec->topic); - chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic); - signal_emit("channel topic changed", 1, chanrec); - } - - mode = silc_client_chmode(modei, channel_entry); - g_free_not_null(chanrec->mode); - chanrec->mode = g_strdup(mode == NULL ? "" : mode); - signal_emit("channel mode changed", 1, chanrec); - - /* Resolve the client information */ - silc_client_get_clients_by_list(client, conn, list_count, client_id_list, - silc_client_join_get_users, - channel_entry); - break; - } - - case SILC_COMMAND_NICK: - { - SilcClientEntry client = va_arg(vp, SilcClientEntry); - char *old; - - if (!success) - return; - - old = g_strdup(server->nick); - server_change_nick(SERVER(server), client->nickname); - nicklist_rename_unique(SERVER(server), - server->conn->local_entry, server->nick, - client, client->nickname); - - signal_emit("message own_nick", 4, server, server->nick, old, ""); - g_free(old); - break; - } - - case SILC_COMMAND_LIST: - { - char *topic, *name; - int usercount; - unsigned char buf[256], tmp[16]; - int i, len; - - if (!success) - return; - - /* XXX should use irssi routines */ - - (void)va_arg(vp, SilcChannelEntry); - name = va_arg(vp, char *); - topic = va_arg(vp, char *); - usercount = va_arg(vp, int); - - if (status == SILC_STATUS_LIST_START || - status == SILC_STATUS_OK) - silc_say(client, conn, - " Channel Users Topic"); - - memset(buf, 0, sizeof(buf)); - strncat(buf, " ", 2); - len = strlen(name); - strncat(buf, name, len > 40 ? 40 : len); - if (len < 40) - for (i = 0; i < 40 - len; i++) - strcat(buf, " "); - strcat(buf, " "); - - memset(tmp, 0, sizeof(tmp)); - if (usercount) { - snprintf(tmp, sizeof(tmp), "%d", usercount); - strcat(buf, tmp); - } - len = strlen(tmp); - if (len < 10) - for (i = 0; i < 10 - len; i++) - strcat(buf, " "); - strcat(buf, " "); - - if (topic) { - len = strlen(topic); - strncat(buf, topic, len); - } - - silc_say(client, conn, "%s", buf); - } - break; - - case SILC_COMMAND_UMODE: - { - uint32 mode; - - if (!success) - return; - - mode = va_arg(vp, uint32); - - /* XXX todo */ - } - break; - - case SILC_COMMAND_OPER: - silc_say(client, conn, "You are now server operator"); - break; - - case SILC_COMMAND_SILCOPER: - silc_say(client, conn, "You are now SILC operator"); - break; - - case SILC_COMMAND_USERS: - { - SilcChannelEntry channel; - SilcChannelUser chu; - int line_len; - char *line; - - if (!success) - return; - - channel = va_arg(vp, SilcChannelEntry); - - /* There are two ways to do this, either parse the list (that - the command_reply sends (just take it with va_arg()) or just - traverse the channel's client list. I'll do the latter. See - JOIN command reply for example for the list. */ - - silc_say(client, conn, "Users on %s", channel->channel_name); - - line = silc_calloc(1024, sizeof(*line)); - line_len = 1024; - silc_list_start(channel->clients); - while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) { - SilcClientEntry e = chu->client; - int i, len1; - char *m, tmp[80]; - - memset(line, 0, line_len); - - if (strlen(e->nickname) + strlen(e->server) + 100 > line_len) { - silc_free(line); - line_len += strlen(e->nickname) + strlen(e->server) + 100; - line = silc_calloc(line_len, sizeof(*line)); - } - - memset(tmp, 0, sizeof(tmp)); - m = silc_client_chumode_char(chu->mode); - - strncat(line, " ", 1); - strncat(line, e->nickname, strlen(e->nickname)); - strncat(line, e->server ? "@" : "", 1); - - len1 = 0; - if (e->server) - len1 = strlen(e->server); - strncat(line, e->server ? e->server : "", len1 > 30 ? 30 : len1); - - len1 = strlen(line); - if (len1 >= 30) { - memset(&line[29], 0, len1 - 29); - } else { - for (i = 0; i < 30 - len1 - 1; i++) - strcat(line, " "); - } - - if (e->mode & SILC_UMODE_GONE) - strcat(line, " G"); - else - strcat(line, " H"); - strcat(tmp, m ? m : ""); - strncat(line, tmp, strlen(tmp)); - - if (strlen(tmp) < 5) - for (i = 0; i < 5 - strlen(tmp); i++) - strcat(line, " "); - - strcat(line, e->username ? e->username : ""); - - silc_say(client, conn, "%s", line); - - if (m) - silc_free(m); - } - - silc_free(line); - } - break; - - case SILC_COMMAND_BAN: - { - SilcChannelEntry channel; - char *ban_list; - - if (!success) - return; - - /* XXX should use irssi routines */ - - channel = va_arg(vp, SilcChannelEntry); - ban_list = va_arg(vp, char *); - - if (ban_list) - silc_say(client, conn, "%s ban list: %s", channel->channel_name, - ban_list); - else - silc_say(client, conn, "%s ban list not set", channel->channel_name); - } - break; - - case SILC_COMMAND_GETKEY: - { - SilcIdType id_type; - void *entry; - SilcPublicKey public_key; - unsigned char *pk; - uint32 pk_len; - - id_type = va_arg(vp, uint32); - entry = va_arg(vp, void *); - public_key = va_arg(vp, SilcPublicKey); - - pk = silc_pkcs_public_key_encode(public_key, &pk_len); - - if (id_type == SILC_ID_CLIENT) { - silc_verify_public_key_internal(client, conn, SILC_SOCKET_TYPE_CLIENT, - pk, pk_len, SILC_SKE_PK_TYPE_SILC, - NULL, NULL); - } - - silc_free(pk); - } - - case SILC_COMMAND_TOPIC: - { - SilcChannelEntry channel; - char *topic; - - if (!success) - return; - - channel = va_arg(vp, SilcChannelEntry); - topic = va_arg(vp, char *); - - if (topic) { - chanrec = silc_channel_find_entry(server, channel); - if (chanrec) { - g_free_not_null(chanrec->topic); - chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic); - signal_emit("channel topic changed", 1, chanrec); - } - printformat_module("fe-common/silc", server, channel->channel_name, - MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC, - channel->channel_name, topic); - } - } - break; - } - - va_end(vp); -} - -/* Internal routine to verify public key. If the `completion' is provided - it will be called to indicate whether public was verified or not. */ - -typedef struct { - SilcClient client; - SilcClientConnection conn; - char *filename; - char *entity; - unsigned char *pk; - uint32 pk_len; - SilcSKEPKType pk_type; - SilcVerifyPublicKey completion; - void *context; -} *PublicKeyVerify; - -static void verify_public_key_completion(const char *line, void *context) -{ - PublicKeyVerify verify = (PublicKeyVerify)context; - - if (line[0] == 'Y' || line[0] == 'y') { - /* Call the completion */ - if (verify->completion) - verify->completion(TRUE, verify->context); - - /* Save the key for future checking */ - silc_pkcs_save_public_key_data(verify->filename, verify->pk, - verify->pk_len, SILC_PKCS_FILE_PEM); - } else { - /* Call the completion */ - if (verify->completion) - verify->completion(FALSE, verify->context); - - silc_say(verify->client, - verify->conn, "Will not accept the %s key", verify->entity); - } - - silc_free(verify->filename); - silc_free(verify->entity); - silc_free(verify); -} - -static void -silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn, - SilcSocketType conn_type, unsigned char *pk, - uint32 pk_len, SilcSKEPKType pk_type, - SilcVerifyPublicKey completion, void *context) -{ - int i; - char file[256], filename[256], *fingerprint; - struct passwd *pw; - struct stat st; - char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER || - conn_type == SILC_SOCKET_TYPE_ROUTER) ? - "server" : "client"); - PublicKeyVerify verify; - - if (pk_type != SILC_SKE_PK_TYPE_SILC) { - silc_say(client, conn, "We don't support %s public key type %d", - entity, pk_type); - if (completion) - completion(FALSE, context); - return; - } - - pw = getpwuid(getuid()); - if (!pw) { - if (completion) - completion(FALSE, context); - return; - } - - memset(filename, 0, sizeof(filename)); - memset(file, 0, sizeof(file)); - - if (conn_type == SILC_SOCKET_TYPE_SERVER || - conn_type == SILC_SOCKET_TYPE_ROUTER) { - snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, - conn->sock->hostname, conn->sock->port); - snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s", - pw->pw_dir, entity, file); - } else { - /* Replace all whitespaces with `_'. */ - fingerprint = silc_hash_fingerprint(NULL, pk, pk_len); - for (i = 0; i < strlen(fingerprint); i++) - if (fingerprint[i] == ' ') - fingerprint[i] = '_'; - - snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint); - snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s", - pw->pw_dir, entity, file); - silc_free(fingerprint); - } - - /* Take fingerprint of the public key */ - fingerprint = silc_hash_fingerprint(NULL, pk, pk_len); - - verify = silc_calloc(1, sizeof(*verify)); - verify->client = client; - verify->conn = conn; - verify->filename = strdup(filename); - verify->entity = strdup(entity); - verify->pk = pk; - verify->pk_len = pk_len; - verify->pk_type = pk_type; - verify->completion = completion; - verify->context = context; - - /* Check whether this key already exists */ - if (stat(filename, &st) < 0) { - /* Key does not exist, ask user to verify the key and save it */ - - silc_say(client, conn, "Received %s public key", entity); - silc_say(client, conn, "Fingerprint for the %s key is", entity); - silc_say(client, conn, "%s", fingerprint); - - keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion, - "Would you like to accept the key (y/n)? ", 0, - verify); - silc_free(fingerprint); - return; - } else { - /* The key already exists, verify it. */ - SilcPublicKey public_key; - unsigned char *encpk; - uint32 encpk_len; - - /* Load the key file */ - if (!silc_pkcs_load_public_key(filename, &public_key, - SILC_PKCS_FILE_PEM)) - if (!silc_pkcs_load_public_key(filename, &public_key, - SILC_PKCS_FILE_BIN)) { - silc_say(client, conn, "Received %s public key", entity); - silc_say(client, conn, "Fingerprint for the %s key is", entity); - silc_say(client, conn, "%s", fingerprint); - silc_say(client, conn, "Could not load your local copy of the %s key", - entity); - keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion, - "Would you like to accept the key " - "anyway (y/n)? ", 0, - verify); - silc_free(fingerprint); - return; - } - - /* Encode the key data */ - encpk = silc_pkcs_public_key_encode(public_key, &encpk_len); - if (!encpk) { - silc_say(client, conn, "Received %s public key", entity); - silc_say(client, conn, "Fingerprint for the %s key is", entity); - silc_say(client, conn, "%s", fingerprint); - silc_say(client, conn, "Your local copy of the %s key is malformed", - entity); - keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion, - "Would you like to accept the key " - "anyway (y/n)? ", 0, - verify); - silc_free(fingerprint); - return; - } - - /* Compare the keys */ - if (memcmp(encpk, pk, encpk_len)) { - silc_say(client, conn, "Received %s public key", entity); - silc_say(client, conn, "Fingerprint for the %s key is", entity); - silc_say(client, conn, "%s", fingerprint); - silc_say(client, conn, "%s key does not match with your local copy", - entity); - silc_say(client, conn, - "It is possible that the key has expired or changed"); - silc_say(client, conn, "It is also possible that some one is performing " - "man-in-the-middle attack"); - - /* Ask user to verify the key and save it */ - keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion, - "Would you like to accept the key " - "anyway (y/n)? ", 0, - verify); - silc_free(fingerprint); - return; - } - - /* Local copy matched */ - if (completion) - completion(TRUE, context); - silc_free(fingerprint); - } -} - -/* Verifies received public key. The `conn_type' indicates which entity - (server, client etc.) has sent the public key. If user decides to trust - the key may be saved as trusted public key for later use. The - `completion' must be called after the public key has been verified. */ - -static void -silc_verify_public_key(SilcClient client, SilcClientConnection conn, - SilcSocketType conn_type, unsigned char *pk, - uint32 pk_len, SilcSKEPKType pk_type, - SilcVerifyPublicKey completion, void *context) -{ - silc_verify_public_key_internal(client, conn, conn_type, pk, - pk_len, pk_type, - completion, context); -} - -/* Asks passphrase from user on the input line. */ - -typedef struct { - SilcAskPassphrase completion; - void *context; -} *AskPassphrase; - -static void ask_passphrase_completion(const char *passphrase, void *context) -{ - AskPassphrase p = (AskPassphrase)context; - p->completion((unsigned char *)passphrase, - passphrase ? strlen(passphrase) : 0, p->context); - silc_free(p); -} - -static void silc_ask_passphrase(SilcClient client, SilcClientConnection conn, - SilcAskPassphrase completion, void *context) -{ - AskPassphrase p = silc_calloc(1, sizeof(*p)); - p->completion = completion; - p->context = context; - - keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion, - "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p); -} - -/* Find authentication method and authentication data by hostname and - port. The hostname may be IP address as well. The found authentication - method and authentication data is returned to `auth_meth', `auth_data' - and `auth_data_len'. The function returns TRUE if authentication method - is found and FALSE if not. `conn' may be NULL. */ - -static int -silc_get_auth_method(SilcClient client, SilcClientConnection conn, - char *hostname, uint16 port, - SilcProtocolAuthMeth *auth_meth, - unsigned char **auth_data, - uint32 *auth_data_len) -{ - - /* XXX must resolve from configuration whether this connection has - any specific authentication data */ - - *auth_meth = SILC_AUTH_NONE; - *auth_data = NULL; - *auth_data_len = 0; - - return TRUE; -} - -/* Notifies application that failure packet was received. This is called - if there is some protocol active in the client. The `protocol' is the - protocol context. The `failure' is opaque pointer to the failure - indication. Note, that the `failure' is protocol dependant and application - must explicitly cast it to correct type. Usually `failure' is 32 bit - failure type (see protocol specs for all protocol failure types). */ - -static void -silc_failure(SilcClient client, SilcClientConnection conn, - SilcProtocol protocol, void *failure) -{ - if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) { - SilcSKEStatus status = (SilcSKEStatus)failure; - - if (status == SILC_SKE_STATUS_BAD_VERSION) - silc_say_error("You are running incompatible client version (it may be " - "too old or too new)"); - if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY) - silc_say_error("Server does not support your public key type"); - if (status == SILC_SKE_STATUS_UNKNOWN_GROUP) - silc_say_error("Server does not support one of your proposed KE group"); - if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER) - silc_say_error("Server does not support one of your proposed cipher"); - if (status == SILC_SKE_STATUS_UNKNOWN_PKCS) - silc_say_error("Server does not support one of your proposed PKCS"); - if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION) - silc_say_error("Server does not support one of your proposed " - "hash function"); - if (status == SILC_SKE_STATUS_UNKNOWN_HMAC) - silc_say_error("Server does not support one of your proposed HMAC"); - if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE) - silc_say_error("Incorrect signature"); - } - - if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) { - uint32 err = (uint32)failure; - - if (err == SILC_AUTH_FAILED) - silc_say(client, conn, "Authentication failed"); - } -} - -/* Asks whether the user would like to perform the key agreement protocol. - This is called after we have received an key agreement packet or an - reply to our key agreement packet. This returns TRUE if the user wants - the library to perform the key agreement protocol and FALSE if it is not - desired (application may start it later by calling the function - silc_client_perform_key_agreement). */ - -static int -silc_key_agreement(SilcClient client, SilcClientConnection conn, - SilcClientEntry client_entry, char *hostname, - int port, - SilcKeyAgreementCallback *completion, - void **context) -{ - char host[256]; - - /* We will just display the info on the screen and return FALSE and user - will have to start the key agreement with a command. */ - - if (hostname) { - memset(host, 0, sizeof(host)); - snprintf(host, sizeof(host) - 1, "(%s on port %d)", hostname, port); - } - - silc_say(client, conn, "%s wants to perform key agreement %s", - client_entry->nickname, hostname ? host : ""); - - *completion = NULL; - *context = NULL; - - return FALSE; -} - -/* SILC client operations */ -SilcClientOperations ops = { - silc_say, - silc_channel_message, - silc_private_message, - silc_notify, - silc_command, - silc_command_reply, - silc_connect, - silc_disconnect, - silc_get_auth_method, - silc_verify_public_key, - silc_ask_passphrase, - silc_failure, - silc_key_agreement, -}; - static int my_silc_scheduler(void) { silc_schedule_one(0); diff --git a/apps/irssi/src/silc/core/silc-queries.c b/apps/irssi/src/silc/core/silc-queries.c index ef0090e3..6717cb36 100644 --- a/apps/irssi/src/silc/core/silc-queries.c +++ b/apps/irssi/src/silc/core/silc-queries.c @@ -24,18 +24,17 @@ #include "silc-queries.h" -QUERY_REC *silc_query_create(SILC_SERVER_REC *server, +QUERY_REC *silc_query_create(const char *server_tag, const char *nick, int automatic) { QUERY_REC *rec; - g_return_val_if_fail(server == NULL || IS_SILC_SERVER(server), NULL); g_return_val_if_fail(nick != NULL, NULL); rec = g_new0(QUERY_REC, 1); rec->chat_type = SILC_PROTOCOL; rec->name = g_strdup(nick); - rec->server = (SERVER_REC *) server; + rec->server_tag = g_strdup(server_tag); query_init(rec, automatic); return rec; } diff --git a/apps/irssi/src/silc/core/silc-queries.h b/apps/irssi/src/silc/core/silc-queries.h index 22340541..9443b59c 100644 --- a/apps/irssi/src/silc/core/silc-queries.h +++ b/apps/irssi/src/silc/core/silc-queries.h @@ -13,7 +13,7 @@ #define silc_query_find(server, name) \ query_find(SERVER(server), name) -QUERY_REC *silc_query_create(SILC_SERVER_REC *server, +QUERY_REC *silc_query_create(const char *server_tag, const char *nick, int automatic); void silc_queries_init(void); void silc_queries_deinit(void); diff --git a/apps/irssi/src/silc/core/silc-servers.c b/apps/irssi/src/silc/core/silc-servers.c index 50233995..46ed0330 100644 --- a/apps/irssi/src/silc/core/silc-servers.c +++ b/apps/irssi/src/silc/core/silc-servers.c @@ -329,6 +329,7 @@ void silc_server_init(void) command_bind("users", MODULE_NAME, (SIGNAL_FUNC) command_self); command_bind("list", MODULE_NAME, (SIGNAL_FUNC) command_self); command_bind("ban", MODULE_NAME, (SIGNAL_FUNC) command_self); + command_bind("oper", MODULE_NAME, (SIGNAL_FUNC) command_self); command_bind("silcoper", MODULE_NAME, (SIGNAL_FUNC) command_self); command_bind("umode", MODULE_NAME, (SIGNAL_FUNC) command_self); command_bind("invite", MODULE_NAME, (SIGNAL_FUNC) command_self); @@ -360,6 +361,7 @@ void silc_server_deinit(void) command_unbind("cumode", (SIGNAL_FUNC) command_self); command_unbind("users", (SIGNAL_FUNC) command_self); command_unbind("list", (SIGNAL_FUNC) command_self); + command_unbind("oper", (SIGNAL_FUNC) command_self); command_unbind("silcoper", (SIGNAL_FUNC) command_self); command_unbind("umode", (SIGNAL_FUNC) command_self); command_unbind("invite", (SIGNAL_FUNC) command_self); -- 2.24.0