X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=apps%2Firssi%2Fsrc%2Fsilc%2Fcore%2Fclient_ops.c;h=6d8e905bb4ee7b5359bfe2af424f1e618fbff608;hb=a818c5b5411bbc4436d1c5f011236985c96bb787;hp=b832c49ed1bfa63a5b5602a8c415f19d841d22f7;hpb=70fceb1b71e76e1ff2719988cad63a9113b38641;p=silc.git diff --git a/apps/irssi/src/silc/core/client_ops.c b/apps/irssi/src/silc/core/client_ops.c index b832c49e..6d8e905b 100644 --- a/apps/irssi/src/silc/core/client_ops.c +++ b/apps/irssi/src/silc/core/client_ops.c @@ -40,8 +40,9 @@ static void silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn, - SilcSocketType conn_type, unsigned char *pk, - uint32 pk_len, SilcSKEPKType pk_type, + const char *name, SilcSocketType conn_type, + unsigned char *pk, SilcUInt32 pk_len, + SilcSKEPKType pk_type, SilcVerifyPublicKey completion, void *context); void silc_say(SilcClient client, SilcClientConnection conn, @@ -84,6 +85,11 @@ void silc_channel_message(SilcClient client, SilcClientConnection conn, SILC_NICK_REC *nick; SILC_CHANNEL_REC *chanrec; + SILC_LOG_DEBUG(("Start")); + + if (!msg) + return; + server = conn == NULL ? NULL : conn->context; chanrec = silc_channel_find_entry(server, channel); if (!chanrec) @@ -92,15 +98,9 @@ void silc_channel_message(SilcClient client, SilcClientConnection conn, nick = silc_nicklist_find(chanrec, sender); if (!nick) { /* We didn't find client but it clearly exists, add it. */ - SilcChannelUser chu; - - silc_list_start(channel->clients); - while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) { - if (chu->client == sender) { - nick = silc_nicklist_insert(chanrec, chu, FALSE); - break; - } - } + SilcChannelUser chu = silc_client_on_channel(channel, sender); + if (chu) + nick = silc_nicklist_insert(chanrec, chu, FALSE); } if (flags & SILC_MESSAGE_FLAG_ACTION) @@ -128,6 +128,8 @@ void silc_private_message(SilcClient client, SilcClientConnection conn, SILC_SERVER_REC *server; char userhost[256]; + SILC_LOG_DEBUG(("Start")); + server = conn == NULL ? NULL : conn->context; memset(userhost, 0, sizeof(userhost)); if (sender->username) @@ -146,52 +148,409 @@ void silc_private_message(SilcClient client, SilcClientConnection conn, 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" }, -}; - void silc_notify(SilcClient client, SilcClientConnection conn, SilcNotifyType type, ...) { - SILC_SERVER_REC *server; va_list va; - - server = conn == NULL ? NULL : conn->context; + SILC_SERVER_REC *server; + SILC_CHANNEL_REC *chanrec; + SILC_NICK_REC *nickrec; + SilcClientEntry client_entry, client_entry2; + SilcChannelEntry channel; + SilcServerEntry server_entry; + SilcIdType idtype; + void *entry; + SilcUInt32 mode; + char userhost[512]; + char *name, *tmp; + GSList *list1, *list_tmp; + + SILC_LOG_DEBUG(("Start")); + va_start(va, type); + + server = conn == NULL ? NULL : conn->context; - if (type == SILC_NOTIFY_TYPE_NONE) { + switch(type) { + case 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 { + break; + + case SILC_NOTIFY_TYPE_INVITE: + /* + * Invited or modified invite list. + */ + + SILC_LOG_DEBUG(("Notify: INVITE")); + + channel = va_arg(va, SilcChannelEntry); + name = va_arg(va, char *); + client_entry = va_arg(va, SilcClientEntry); + + memset(userhost, 0, sizeof(userhost)); + snprintf(userhost, sizeof(userhost) - 1, "%s@%s", + client_entry->username, client_entry->hostname); + signal_emit("message invite", 4, server, channel ? channel->channel_name : + name, client_entry->nickname, userhost); + break; + + case SILC_NOTIFY_TYPE_JOIN: + /* + * Joined channel. + */ + + SILC_LOG_DEBUG(("Notify: JOIN")); + + client_entry = va_arg(va, SilcClientEntry); + channel = va_arg(va, SilcChannelEntry); + + if (client_entry == server->conn->local_entry) { + /* You joined to channel */ + chanrec = silc_channel_find(server, channel->channel_name); + if (chanrec != NULL && !chanrec->joined) + chanrec->entry = channel; + } else { + chanrec = silc_channel_find_entry(server, channel); + if (chanrec != NULL) { + SilcChannelUser chu = silc_client_on_channel(channel, client_entry); + if (chu) + nickrec = silc_nicklist_insert(chanrec, chu, TRUE); + } + } + + memset(userhost, 0, sizeof(userhost)); + if (client_entry->username) + snprintf(userhost, sizeof(userhost) - 1, "%s@%s", + client_entry->username, client_entry->hostname); + signal_emit("message join", 4, server, channel->channel_name, + client_entry->nickname, + client_entry->username == NULL ? "" : userhost); + break; + + case SILC_NOTIFY_TYPE_LEAVE: + /* + * Left a channel. + */ + + SILC_LOG_DEBUG(("Notify: LEAVE")); + + client_entry = va_arg(va, SilcClientEntry); + channel = va_arg(va, SilcChannelEntry); + + memset(userhost, 0, sizeof(userhost)); + if (client_entry->username) + snprintf(userhost, sizeof(userhost) - 1, "%s@%s", + client_entry->username, client_entry->hostname); + signal_emit("message part", 5, server, channel->channel_name, + client_entry->nickname, client_entry->username ? + userhost : "", client_entry->nickname); + + chanrec = silc_channel_find_entry(server, channel); + if (chanrec != NULL) { + nickrec = silc_nicklist_find(chanrec, client_entry); + if (nickrec != NULL) + nicklist_remove(CHANNEL(chanrec), NICK(nickrec)); + } + break; + + case SILC_NOTIFY_TYPE_SIGNOFF: + /* + * Left the network. + */ + + SILC_LOG_DEBUG(("Notify: SIGNOFF")); + + client_entry = va_arg(va, SilcClientEntry); + tmp = va_arg(va, char *); + + silc_server_free_ftp(server, client_entry); + + memset(userhost, 0, sizeof(userhost)); + if (client_entry->username) + snprintf(userhost, sizeof(userhost) - 1, "%s@%s", + client_entry->username, client_entry->hostname); + signal_emit("message quit", 4, server, client_entry->nickname, + client_entry->username ? userhost : "", + tmp ? tmp : ""); + + list1 = nicklist_get_same_unique(SERVER(server), client_entry); + for (list_tmp = list1; list_tmp != NULL; list_tmp = + list_tmp->next->next) { + CHANNEL_REC *channel = list_tmp->data; + NICK_REC *nickrec = list_tmp->next->data; + + nicklist_remove(channel, nickrec); + } + break; + + case SILC_NOTIFY_TYPE_TOPIC_SET: + /* + * Changed topic. + */ + + SILC_LOG_DEBUG(("Notify: TOPIC_SET")); + + idtype = va_arg(va, int); + entry = va_arg(va, void *); + tmp = va_arg(va, char *); + channel = va_arg(va, SilcChannelEntry); + + chanrec = silc_channel_find_entry(server, channel); + if (chanrec != NULL) { + g_free_not_null(chanrec->topic); + chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp); + signal_emit("channel topic changed", 1, chanrec); + } + + if (idtype == SILC_ID_CLIENT) { + client_entry = (SilcClientEntry)entry; + memset(userhost, 0, sizeof(userhost)); + snprintf(userhost, sizeof(userhost) - 1, "%s@%s", + client_entry->username, client_entry->hostname); + signal_emit("message topic", 5, server, channel->channel_name, + tmp, client_entry->nickname, userhost); + } else if (idtype == SILC_ID_SERVER) { + server_entry = (SilcServerEntry)entry; + signal_emit("message topic", 5, server, channel->channel_name, + tmp, server_entry->server_name, + server_entry->server_name); + } else { + channel = (SilcChannelEntry)entry; + signal_emit("message topic", 5, server, channel->channel_name, + tmp, channel->channel_name, channel->channel_name); + } + break; + + case SILC_NOTIFY_TYPE_NICK_CHANGE: + /* + * Changed nickname. + */ + + SILC_LOG_DEBUG(("Notify: NICK_CHANGE")); + + client_entry = va_arg(va, SilcClientEntry); + client_entry2 = va_arg(va, SilcClientEntry); + + memset(userhost, 0, sizeof(userhost)); + snprintf(userhost, sizeof(userhost) - 1, "%s@%s", + client_entry2->username, client_entry2->hostname); + nicklist_rename_unique(SERVER(server), + client_entry, client_entry->nickname, + client_entry2, client_entry2->nickname); + signal_emit("message nick", 4, server, client_entry2->nickname, + client_entry->nickname, userhost); + break; + + case SILC_NOTIFY_TYPE_CMODE_CHANGE: + /* + * Changed channel mode. + */ + + SILC_LOG_DEBUG(("Notify: CMODE_CHANGE")); + + idtype = va_arg(va, int); + entry = va_arg(va, void *); + mode = va_arg(va, SilcUInt32); + (void)va_arg(va, char *); + (void)va_arg(va, char *); + channel = va_arg(va, SilcChannelEntry); + + tmp = silc_client_chmode(mode, + channel->channel_key ? + channel->channel_key->cipher->name : "", + channel->hmac ? + silc_hmac_get_name(channel->hmac) : ""); + + chanrec = silc_channel_find_entry(server, channel); + if (chanrec != NULL) { + g_free_not_null(chanrec->mode); + chanrec->mode = g_strdup(tmp == NULL ? "" : tmp); + signal_emit("channel mode changed", 1, chanrec); + } + + if (idtype == SILC_ID_CLIENT) { + client_entry = (SilcClientEntry)entry; + printformat_module("fe-common/silc", server, channel->channel_name, + MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE, + channel->channel_name, tmp ? tmp : "removed all", + client_entry->nickname); + } else if (idtype == SILC_ID_SERVER) { + server_entry = (SilcServerEntry)entry; + printformat_module("fe-common/silc", server, channel->channel_name, + MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE, + channel->channel_name, tmp ? tmp : "removed all", + server_entry->server_name); + } + + silc_free(tmp); + break; + + case SILC_NOTIFY_TYPE_CUMODE_CHANGE: + /* + * Changed user's mode on channel. + */ + + SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE")); + + client_entry = va_arg(va, SilcClientEntry); + mode = va_arg(va, SilcUInt32); + client_entry2 = va_arg(va, SilcClientEntry); + channel = va_arg(va, SilcChannelEntry); + + tmp = silc_client_chumode(mode); + chanrec = silc_channel_find_entry(server, channel); + if (chanrec != NULL) { + SILC_NICK_REC *nick; + + if (client_entry2 == server->conn->local_entry) + chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0; + + nick = silc_nicklist_find(chanrec, client_entry2); + if (nick != NULL) { + nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0; + nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0; + signal_emit("nick mode changed", 2, chanrec, nick); + } + } + + printformat_module("fe-common/silc", server, channel->channel_name, + MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE, + channel->channel_name, client_entry2->nickname, + tmp ? tmp : "removed all", + client_entry->nickname); + + if (mode & SILC_CHANNEL_UMODE_CHANFO) + printformat_module("fe-common/silc", + server, channel->channel_name, MSGLEVEL_CRAP, + SILCTXT_CHANNEL_FOUNDER, + channel->channel_name, client_entry2->nickname); + + silc_free(tmp); + break; + + case SILC_NOTIFY_TYPE_MOTD: + /* + * Received MOTD. + */ + + SILC_LOG_DEBUG(("Notify: MOTD")); + + tmp = va_arg(va, char *); + + if (!settings_get_bool("skip_motd")) + printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp); + break; + + case SILC_NOTIFY_TYPE_KICKED: + /* + * Someone was kicked from channel. + */ + + SILC_LOG_DEBUG(("Notify: KICKED")); + + client_entry = va_arg(va, SilcClientEntry); + tmp = va_arg(va, char *); + client_entry2 = va_arg(va, SilcClientEntry); + channel = va_arg(va, SilcChannelEntry); + + chanrec = silc_channel_find_entry(server, channel); + + if (client_entry == conn->local_entry) { + printformat_module("fe-common/silc", server, channel->channel_name, + MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU, + channel->channel_name, client_entry2->nickname, + tmp ? tmp : ""); + if (chanrec) { + chanrec->kicked = TRUE; + channel_destroy((CHANNEL_REC *)chanrec); + } + } else { + printformat_module("fe-common/silc", server, channel->channel_name, + MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED, + client_entry->nickname, channel->channel_name, + client_entry2->nickname, tmp ? tmp : ""); + + if (chanrec) { + SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry); + if (nickrec != NULL) + nicklist_remove(CHANNEL(chanrec), NICK(nickrec)); + } + } + break; + + case SILC_NOTIFY_TYPE_KILLED: + /* + * Someone was killed from the network. + */ + + SILC_LOG_DEBUG(("Notify: KILLED")); + + client_entry = va_arg(va, SilcClientEntry); + tmp = va_arg(va, char *); + + if (client_entry == conn->local_entry) { + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU, + tmp ? tmp : ""); + } else { + list1 = nicklist_get_same_unique(SERVER(server), client_entry); + for (list_tmp = list1; list_tmp != NULL; list_tmp = + list_tmp->next->next) { + CHANNEL_REC *channel = list_tmp->data; + NICK_REC *nickrec = list_tmp->next->data; + nicklist_remove(channel, nickrec); + } + + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED, + client_entry->nickname, + tmp ? tmp : ""); + } + break; + + case SILC_NOTIFY_TYPE_SERVER_SIGNOFF: + { + /* + * Server has quit the network. + */ + int i; + SilcClientEntry *clients; + SilcUInt32 clients_count; + + SILC_LOG_DEBUG(("Notify: SIGNOFF")); + + (void)va_arg(va, void *); + clients = va_arg(va, SilcClientEntry *); + clients_count = va_arg(va, SilcUInt32); + + for (i = 0; i < clients_count; i++) { + memset(userhost, 0, sizeof(userhost)); + if (clients[i]->username) + snprintf(userhost, sizeof(userhost) - 1, "%s@%s", + clients[i]->username, clients[i]->hostname); + signal_emit("message quit", 4, server, clients[i]->nickname, + clients[i]->username ? userhost : "", + "server signoff"); + + silc_server_free_ftp(server, clients[i]); + + list1 = nicklist_get_same_unique(SERVER(server), clients[i]); + for (list_tmp = list1; list_tmp != NULL; list_tmp = + list_tmp->next->next) { + CHANNEL_REC *channel = list_tmp->data; + NICK_REC *nickrec = list_tmp->next->data; + nicklist_remove(channel, nickrec); + } + } + } + break; + + default: /* Unknown notify */ printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type); + break; } va_end(va); @@ -199,7 +558,7 @@ void silc_notify(SilcClient client, SilcClientConnection conn, /* 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. */ + the SilcClientConnection object which it should save somewhere. */ void silc_connect(SilcClient client, SilcClientConnection conn, int success) { @@ -215,7 +574,8 @@ void silc_connect(SilcClient client, SilcClientConnection conn, int success) signal_emit("event connected", 1, server); } else { server->connection_lost = TRUE; - server->conn->context = NULL; + if (server->conn) + server->conn->context = NULL; server_disconnect(SERVER(server)); } } @@ -226,7 +586,9 @@ void silc_disconnect(SilcClient client, SilcClientConnection conn) { SILC_SERVER_REC *server = conn->context; - if (server->conn) { + SILC_LOG_DEBUG(("Start")); + + if (server->conn && server->conn->local_entry) { nicklist_rename_unique(SERVER(server), server->conn->local_entry, server->nick, server->conn->local_entry, @@ -255,6 +617,8 @@ void silc_command(SilcClient client, SilcClientConnection conn, { SILC_SERVER_REC *server = conn->context; + SILC_LOG_DEBUG(("Start")); + if (!success) return; @@ -278,10 +642,11 @@ void silc_command(SilcClient client, SilcClientConnection conn, static void silc_client_join_get_users(SilcClient client, SilcClientConnection conn, SilcClientEntry *clients, - uint32 clients_count, + SilcUInt32 clients_count, void *context) { SilcChannelEntry channel = (SilcChannelEntry)context; + SilcHashTableList htl; SilcChannelUser chu; SILC_SERVER_REC *server = conn->context; SILC_CHANNEL_REC *chanrec; @@ -295,14 +660,15 @@ static void silc_client_join_get_users(SilcClient client, if (chanrec == NULL) return; - silc_list_start(channel->clients); - while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) { + silc_hash_table_list(channel->user_list, &htl); + while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { if (!chu->client->nickname) continue; if (chu->mode & SILC_CHANNEL_UMODE_CHANFO) founder = chu->client; silc_nicklist_insert(chanrec, chu, FALSE); } + silc_hash_table_list_reset(&htl); ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry)); nicklist_set_own(CHANNEL(chanrec), ownnick); @@ -385,24 +751,44 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, va_start(vp, status); + SILC_LOG_DEBUG(("Start")); + switch(command) { case SILC_COMMAND_WHOIS: { char buf[1024], *nickname, *username, *realname, *nick; - uint32 idle, mode; + unsigned char *fingerprint; + SilcUInt32 idle, mode; SilcBuffer channels; SilcClientEntry client_entry; - 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 (status == SILC_STATUS_ERR_NO_SUCH_NICK) { + /* Print the unknown nick for user */ + unsigned char *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; + } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) { + /* Try to find the entry for the unknown client ID, since we + might have, and print the nickname of it for user. */ + SilcUInt32 tmp_len; + unsigned char *tmp = + silc_argument_get_arg_type(silc_command_get_args(cmd_payload), + 2, &tmp_len); + if (tmp) { + SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len); + if (client_id) { + client_entry = silc_client_get_client_by_id(client, conn, + client_id); + if (client_entry && client_entry->nickname) + silc_say_error("%s: %s", client_entry->nickname, + silc_client_command_status_message(status)); + silc_free(client_id); + } + } break; } @@ -414,8 +800,9 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, 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); + mode = va_arg(vp, SilcUInt32); + idle = va_arg(vp, SilcUInt32); + fingerprint = va_arg(vp, unsigned char *); silc_parse_userfqdn(nickname, &nick, NULL); printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, @@ -427,14 +814,15 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, silc_free(nick); if (channels) { - SilcDList list = silc_channel_payload_parse_list(channels); + SilcDList list = silc_channel_payload_parse_list(channels->data, + channels->len); 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; + SilcUInt32 name_len; char *name = silc_channel_get_name(entry, &name_len); if (m) @@ -476,9 +864,53 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, SILCTXT_WHOIS_IDLE, buf); } + + if (fingerprint) { + fingerprint = silc_fingerprint(fingerprint, 20); + printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, + SILCTXT_WHOIS_FINGERPRINT, fingerprint); + silc_free(fingerprint); + } } break; + case SILC_COMMAND_IDENTIFY: + { + SilcClientEntry client_entry; + + if (status == SILC_STATUS_ERR_NO_SUCH_NICK) { + /* Print the unknown nick for user */ + unsigned char *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)); + break; + } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) { + /* Try to find the entry for the unknown client ID, since we + might have, and print the nickname of it for user. */ + SilcUInt32 tmp_len; + unsigned char *tmp = + silc_argument_get_arg_type(silc_command_get_args(cmd_payload), + 2, &tmp_len); + if (tmp) { + SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len); + if (client_id) { + client_entry = silc_client_get_client_by_id(client, conn, + client_id); + if (client_entry && client_entry->nickname) + silc_say_error("%s: %s", client_entry->nickname, + silc_client_command_status_message(status)); + silc_free(client_id); + } + } + break; + } + + break; + } + case SILC_COMMAND_WHOWAS: { char *nickname, *username, *realname; @@ -491,8 +923,6 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, 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; } @@ -541,24 +971,24 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, case SILC_COMMAND_JOIN: { char *channel, *mode, *topic; - uint32 modei; + SilcUInt32 modei; SilcChannelEntry channel_entry; SilcBuffer client_id_list; - uint32 list_count; + SilcUInt32 list_count; if (!success) return; channel = va_arg(vp, char *); channel_entry = va_arg(vp, SilcChannelEntry); - modei = va_arg(vp, uint32); - (void)va_arg(vp, uint32); + modei = va_arg(vp, SilcUInt32); + (void)va_arg(vp, SilcUInt32); (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); + list_count = va_arg(vp, SilcUInt32); client_id_list = va_arg(vp, SilcBuffer); chanrec = silc_channel_find(server, channel); @@ -584,6 +1014,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, silc_client_get_clients_by_list(client, conn, list_count, client_id_list, silc_client_join_get_users, channel_entry); + break; } @@ -600,7 +1031,6 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, 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; @@ -625,7 +1055,10 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, SILCTXT_LIST_HEADER); - snprintf(users, sizeof(users) - 1, "%d", usercount); + if (!usercount) + snprintf(users, sizeof(users) - 1, "N/A"); + else + snprintf(users, sizeof(users) - 1, "%d", usercount); printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, SILCTXT_LIST, name, users, topic ? topic : ""); @@ -634,20 +1067,24 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, case SILC_COMMAND_UMODE: { - uint32 mode; + SilcUInt32 mode; if (!success) return; - mode = va_arg(vp, uint32); + mode = va_arg(vp, SilcUInt32); - if (mode & SILC_UMODE_SERVER_OPERATOR) + if (mode & SILC_UMODE_SERVER_OPERATOR && + !(server->umode & SILC_UMODE_SERVER_OPERATOR)) printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, SILCTXT_SERVER_OPER); - if (mode & SILC_UMODE_ROUTER_OPERATOR) + if (mode & SILC_UMODE_ROUTER_OPERATOR && + !(server->umode & SILC_UMODE_ROUTER_OPERATOR)) printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER); + + server->umode = mode; } break; @@ -669,6 +1106,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, case SILC_COMMAND_USERS: { + SilcHashTableList htl; SilcChannelEntry channel; SilcChannelUser chu; @@ -681,8 +1119,8 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, MSGLEVEL_CRAP, SILCTXT_USERS_HEADER, channel->channel_name); - silc_list_start(channel->clients); - while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) { + silc_hash_table_list(channel->user_list, &htl); + while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { SilcClientEntry e = chu->client; char stat[5], *mode; @@ -707,6 +1145,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, if (mode) silc_free(mode); } + silc_hash_table_list_reset(&htl); } break; @@ -738,13 +1177,14 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, void *entry; SilcPublicKey public_key; unsigned char *pk; - uint32 pk_len; + SilcUInt32 pk_len; GetkeyContext getkey; + char *name; if (!success) return; - id_type = va_arg(vp, uint32); + id_type = va_arg(vp, SilcUInt32); entry = va_arg(vp, void *); public_key = va_arg(vp, SilcPublicKey); @@ -757,8 +1197,12 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, getkey->client = client; getkey->conn = conn; getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len); - - silc_verify_public_key_internal(client, conn, + + name = (id_type == SILC_ID_CLIENT ? + ((SilcClientEntry)entry)->nickname : + ((SilcServerEntry)entry)->server_name); + + silc_verify_public_key_internal(client, conn, name, (id_type == SILC_ID_CLIENT ? SILC_SOCKET_TYPE_CLIENT : SILC_SOCKET_TYPE_SERVER), @@ -771,6 +1215,27 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, } } break; + + case SILC_COMMAND_INFO: + { + SilcServerEntry server_entry; + char *server_name; + char *server_info; + + if (!success) + return; + + server_entry = va_arg(vp, SilcServerEntry); + server_name = va_arg(vp, char *); + server_info = va_arg(vp, char *); + + if (server_name && server_info ) + { + printtext(server, NULL, MSGLEVEL_CRAP, "Server: %s", server_name); + printtext(server, NULL, MSGLEVEL_CRAP, "%s", server_info); + } + } + break; case SILC_COMMAND_TOPIC: { @@ -806,16 +1271,14 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, 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; + char *entity_name; unsigned char *pk; - uint32 pk_len; + SilcUInt32 pk_len; SilcSKEPKType pk_type; SilcVerifyPublicKey completion; void *context; @@ -839,23 +1302,33 @@ static void verify_public_key_completion(const char *line, void *context) verify->completion(FALSE, verify->context); printformat_module("fe-common/silc", NULL, NULL, - MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD, verify->entity); + MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD, + verify->entity_name ? verify->entity_name : + verify->entity); } silc_free(verify->filename); silc_free(verify->entity); + silc_free(verify->entity_name); silc_free(verify->pk); silc_free(verify); } +/* Internal routine to verify public key. If the `completion' is provided + it will be called to indicate whether public was verified or not. For + server/router public key this will check for filename that includes the + remote host's IP address and remote host's hostname. */ + static void silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn, - SilcSocketType conn_type, unsigned char *pk, - uint32 pk_len, SilcSKEPKType pk_type, + const char *name, SilcSocketType conn_type, + unsigned char *pk, SilcUInt32 pk_len, + SilcSKEPKType pk_type, SilcVerifyPublicKey completion, void *context) { int i; - char file[256], filename[256], *fingerprint, *format; + char file[256], filename[256], filename2[256], *ipf, *hostf = NULL; + char *fingerprint, *babbleprint, *format; struct passwd *pw; struct stat st; char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER || @@ -880,14 +1353,32 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn, } memset(filename, 0, sizeof(filename)); + memset(filename2, 0, sizeof(filename2)); 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); + if (!name) { + snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, + conn->sock->ip, conn->sock->port); + snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s", + pw->pw_dir, entity, file); + + snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, + conn->sock->hostname, conn->sock->port); + snprintf(filename2, sizeof(filename2) - 1, "%s/.silc/%skeys/%s", + pw->pw_dir, entity, file); + + ipf = filename; + hostf = filename2; + } else { + snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, + name, conn->sock->port); + snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s", + pw->pw_dir, entity, file); + + ipf = filename; + } } else { /* Replace all whitespaces with `_'. */ fingerprint = silc_hash_fingerprint(NULL, pk, pk_len); @@ -899,16 +1390,22 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn, snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s", pw->pw_dir, entity, file); silc_free(fingerprint); + + ipf = filename; } /* Take fingerprint of the public key */ fingerprint = silc_hash_fingerprint(NULL, pk, pk_len); + babbleprint = silc_hash_babbleprint(NULL, pk, pk_len); verify = silc_calloc(1, sizeof(*verify)); verify->client = client; verify->conn = conn; - verify->filename = strdup(filename); + verify->filename = strdup(ipf); verify->entity = strdup(entity); + verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ? + (name ? strdup(name) : strdup(conn->sock->hostname)) + : NULL); verify->pk = silc_calloc(pk_len, sizeof(*verify->pk)); memcpy(verify->pk, pk, pk_len); verify->pk_len = pk_len; @@ -917,13 +1414,16 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn, verify->context = context; /* Check whether this key already exists */ - if (stat(filename, &st) < 0) { + if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) { /* Key does not exist, ask user to verify the key and save it */ printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, - SILCTXT_PUBKEY_RECEIVED, entity); + SILCTXT_PUBKEY_RECEIVED,verify->entity_name ? + verify->entity_name : entity); printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint); + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_PUBKEY_BABBLEPRINT, babbleprint); format = format_get_text("fe-common/silc", NULL, NULL, NULL, SILCTXT_PUBKEY_ACCEPT); keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion, @@ -935,35 +1435,45 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn, /* 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)) { - printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, - SILCTXT_PUBKEY_RECEIVED, entity); - printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, - SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint); - printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, - SILCTXT_PUBKEY_COULD_NOT_LOAD, entity); - format = format_get_text("fe-common/silc", NULL, NULL, NULL, - SILCTXT_PUBKEY_ACCEPT_ANYWAY); - keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion, - format, 0, verify); - g_free(format); - silc_free(fingerprint); - return; - } - + SilcUInt32 encpk_len; + + /* Load the key file, try for both IP filename and hostname filename */ + if (!silc_pkcs_load_public_key(ipf, &public_key, + SILC_PKCS_FILE_PEM) && + !silc_pkcs_load_public_key(ipf, &public_key, + SILC_PKCS_FILE_BIN) && + (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key, + SILC_PKCS_FILE_PEM) && + !silc_pkcs_load_public_key(hostf, &public_key, + SILC_PKCS_FILE_BIN)))) { + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_PUBKEY_RECEIVED,verify->entity_name ? + verify->entity_name : entity); + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint); + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_PUBKEY_BABBLEPRINT, babbleprint); + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_PUBKEY_COULD_NOT_LOAD, entity); + format = format_get_text("fe-common/silc", NULL, NULL, NULL, + SILCTXT_PUBKEY_ACCEPT_ANYWAY); + keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion, + format, 0, verify); + g_free(format); + silc_free(fingerprint); + return; + } + /* Encode the key data */ encpk = silc_pkcs_public_key_encode(public_key, &encpk_len); if (!encpk) { printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, - SILCTXT_PUBKEY_RECEIVED, entity); + SILCTXT_PUBKEY_RECEIVED,verify->entity_name ? + verify->entity_name : entity); printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint); + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_PUBKEY_BABBLEPRINT, babbleprint); printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, SILCTXT_PUBKEY_MALFORMED, entity); format = format_get_text("fe-common/silc", NULL, NULL, NULL, @@ -978,9 +1488,12 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn, /* Compare the keys */ if (memcmp(encpk, pk, encpk_len)) { printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, - SILCTXT_PUBKEY_RECEIVED, entity); + SILCTXT_PUBKEY_RECEIVED,verify->entity_name ? + verify->entity_name : entity); printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint); + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_PUBKEY_BABBLEPRINT, babbleprint); printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, SILCTXT_PUBKEY_NO_MATCH, entity); printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, @@ -1013,10 +1526,10 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn, void silc_verify_public_key(SilcClient client, SilcClientConnection conn, SilcSocketType conn_type, unsigned char *pk, - uint32 pk_len, SilcSKEPKType pk_type, + SilcUInt32 pk_len, SilcSKEPKType pk_type, SilcVerifyPublicKey completion, void *context) { - silc_verify_public_key_internal(client, conn, conn_type, pk, + silc_verify_public_key_internal(client, conn, NULL, conn_type, pk, pk_len, pk_type, completion, context); } @@ -1063,6 +1576,8 @@ static void silc_get_auth_method_callback(SilcClient client, { InternalGetAuthMethod internal = (InternalGetAuthMethod)context; + SILC_LOG_DEBUG(("Start")); + switch (auth_meth) { case SILC_AUTH_NONE: /* No authentication required. */ @@ -1092,11 +1607,13 @@ static void silc_get_auth_method_callback(SilcClient client, is found and FALSE if not. `conn' may be NULL. */ void silc_get_auth_method(SilcClient client, SilcClientConnection conn, - char *hostname, uint16 port, + char *hostname, SilcUInt16 port, SilcGetAuthMeth completion, void *context) { InternalGetAuthMethod internal; + SILC_LOG_DEBUG(("Start")); + /* XXX must resolve from configuration whether this connection has any specific authentication data */ @@ -1122,6 +1639,8 @@ void silc_get_auth_method(SilcClient client, SilcClientConnection conn, void silc_failure(SilcClient client, SilcClientConnection conn, SilcProtocol protocol, void *failure) { + SILC_LOG_DEBUG(("Start")); + if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) { SilcSKEStatus status = (SilcSKEStatus)failure; @@ -1155,7 +1674,7 @@ void silc_failure(SilcClient client, SilcClientConnection conn, } if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) { - uint32 err = (uint32)failure; + SilcUInt32 err = (SilcUInt32)failure; if (err == SILC_AUTH_FAILED) printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, @@ -1171,12 +1690,14 @@ void silc_failure(SilcClient client, SilcClientConnection conn, silc_client_perform_key_agreement). */ int silc_key_agreement(SilcClient client, SilcClientConnection conn, - SilcClientEntry client_entry, char *hostname, - uint16 port, SilcKeyAgreementCallback *completion, + SilcClientEntry client_entry, const char *hostname, + SilcUInt16 port, SilcKeyAgreementCallback *completion, void **context) { char portstr[12]; + SILC_LOG_DEBUG(("Start")); + /* We will just display the info on the screen and return FALSE and user will have to start the key agreement with a command. */ @@ -1184,10 +1705,10 @@ int silc_key_agreement(SilcClient client, SilcClientConnection conn, snprintf(portstr, sizeof(portstr) - 1, "%d", port); if (!hostname) - printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_NOTICES, + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname); else - printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_NOTICES, + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, SILCTXT_KEY_AGREEMENT_REQUEST_HOST, client_entry->nickname, hostname, portstr); @@ -1197,6 +1718,37 @@ int silc_key_agreement(SilcClient client, SilcClientConnection conn, return FALSE; } +void silc_ftp(SilcClient client, SilcClientConnection conn, + SilcClientEntry client_entry, SilcUInt32 session_id, + const char *hostname, SilcUInt16 port) +{ + SILC_SERVER_REC *server; + char portstr[12]; + FtpSession ftp = silc_calloc(1, sizeof(*ftp)); + + SILC_LOG_DEBUG(("Start")); + + server = conn->context; + + ftp->client_entry = client_entry; + ftp->session_id = session_id; + ftp->send = FALSE; + ftp->conn = conn; + silc_dlist_add(server->ftp_sessions, ftp); + server->current_session = ftp; + + if (hostname) + snprintf(portstr, sizeof(portstr) - 1, "%d", port); + + if (!hostname) + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_FILE_REQUEST, client_entry->nickname); + else + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_FILE_REQUEST_HOST, + client_entry->nickname, hostname, portstr); +} + /* SILC client operations */ SilcClientOperations ops = { silc_say, @@ -1212,4 +1764,5 @@ SilcClientOperations ops = { silc_ask_passphrase, silc_failure, silc_key_agreement, + silc_ftp, };