X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcclient%2Fcommand_reply.c;h=37384977c1e04cf8245669a25f5630a38baff8ba;hb=40f8443d8d3a6577336ee66d18e04d9ac4d956bb;hp=a3284016753562d9e0c4cc927b88a04c68a0cc88;hpb=75a2d69f7d56b8298e80f9a4546f22ddf138be39;p=silc.git diff --git a/lib/silcclient/command_reply.c b/lib/silcclient/command_reply.c index a3284016..37384977 100644 --- a/lib/silcclient/command_reply.c +++ b/lib/silcclient/command_reply.c @@ -1,10 +1,10 @@ /* - command_reply.c + command_reply.c Author: Pekka Riikonen - Copyright (C) 1997 - 2002 Pekka Riikonen + Copyright (C) 1997 - 2005 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 @@ -25,20 +25,20 @@ * application through command_reply client operation. The arguments are * exactly same and in same order as the server sent it. However, ID's are * not sent to the application. Instead, corresponding ID entry is sent - * to the application. For example, instead of sending Client ID the + * to the application. For example, instead of sending Client ID the * corresponding SilcClientEntry is sent to the application. The case is * same with for example Channel ID's. This way application has all the * necessary data already in hand without redundant searching. If ID is * received but ID entry does not exist, NULL is sent. */ -#include "silcincludes.h" +#include "silc.h" #include "silcclient.h" #include "client_internal.h" #define SAY cmd->client->internal->ops->say -/* All functions that call the COMMAND_CHECK_STATUS macro must have +/* All functions that call the COMMAND_CHECK_STATUS macro must have out: and err: goto labels. out label should call the pending command replies, and the err label just handle error condition. */ @@ -48,11 +48,11 @@ do { \ if (!silc_command_get_status(cmd->payload, NULL, NULL)) { \ if (SILC_STATUS_IS_ERROR(cmd->status)) { \ /* Single error */ \ - COMMAND_REPLY_ERROR; \ + COMMAND_REPLY_ERROR(cmd->status); \ goto out; \ } \ /* List of errors */ \ - COMMAND_REPLY_ERROR; \ + COMMAND_REPLY_ERROR(cmd->error); \ if (cmd->status == SILC_STATUS_LIST_END) \ goto out; \ goto err; \ @@ -84,7 +84,7 @@ void silc_client_command_reply_process(SilcClient client, SilcCommandPayload payload; SilcCommand command; SilcCommandCb reply = NULL; - + /* Get command reply payload from packet */ payload = silc_command_payload_parse(buffer->data, buffer->len); if (!payload) { @@ -92,7 +92,7 @@ void silc_client_command_reply_process(SilcClient client, SILC_LOG_DEBUG(("Bad command reply packet")); return; } - + /* Allocate command reply context. This must be free'd by the command reply routine receiving it. */ ctx = silc_calloc(1, sizeof(*ctx)); @@ -107,8 +107,8 @@ void silc_client_command_reply_process(SilcClient client, /* Check for pending commands and mark to be exeucted */ ctx->callbacks = - silc_client_command_pending_check(sock->user_data, ctx, - silc_command_get(ctx->payload), + silc_client_command_pending_check(sock->user_data, ctx, + silc_command_get(ctx->payload), ctx->ident, &ctx->callbacks_count); /* Execute command reply */ @@ -138,11 +138,11 @@ void silc_client_command_reply_process(SilcClient client, /* Duplicate Command Reply Context by adding reference counter. The context won't be free'd untill it hits zero. */ -SilcClientCommandReplyContext +SilcClientCommandReplyContext silc_client_command_reply_dup(SilcClientCommandReplyContext cmd) { cmd->users++; - SILC_LOG_DEBUG(("Command reply context %p refcnt %d->%d", cmd, + SILC_LOG_DEBUG(("Command reply context %p refcnt %d->%d", cmd, cmd->users - 1, cmd->users)); return cmd; } @@ -152,7 +152,7 @@ silc_client_command_reply_dup(SilcClientCommandReplyContext cmd) void silc_client_command_reply_free(SilcClientCommandReplyContext cmd) { cmd->users--; - SILC_LOG_DEBUG(("Command reply context %p refcnt %d->%d", cmd, + SILC_LOG_DEBUG(("Command reply context %p refcnt %d->%d", cmd, cmd->users + 1, cmd->users)); if (cmd->users < 1) { silc_command_payload_free(cmd->payload); @@ -160,10 +160,10 @@ void silc_client_command_reply_free(SilcClientCommandReplyContext cmd) } } -static void +void silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd, SilcStatus status, - bool notify) + SilcBool notify) { SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data; SilcClientID *client_id; @@ -174,30 +174,30 @@ silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd, char *realname = NULL; SilcUInt32 idle = 0, mode = 0; SilcBufferStruct channels, ch_user_modes; - bool has_channels = FALSE, has_user_modes = FALSE; + SilcBool has_channels = FALSE, has_user_modes = FALSE; unsigned char *fingerprint; SilcUInt32 fingerprint_len; - + id_data = silc_argument_get_arg_type(cmd->args, 2, &len); if (!id_data) { if (notify) - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); return; } - + client_id = silc_id_payload_parse_id(id_data, len, NULL); if (!client_id) { if (notify) - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); return; } - + nickname = silc_argument_get_arg_type(cmd->args, 3, &len); username = silc_argument_get_arg_type(cmd->args, 4, &len); realname = silc_argument_get_arg_type(cmd->args, 5, &len); if (!nickname || !username || !realname) { if (notify) - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); return; } @@ -227,11 +227,16 @@ silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd, client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id); if (!client_entry) { SILC_LOG_DEBUG(("Adding new client entry")); - client_entry = + client_entry = silc_client_add_client(cmd->client, conn, nickname, username, realname, client_id, mode); + if (!client_entry) { + if (notify) + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); + return; + } } else { - silc_client_update_client(cmd->client, conn, client_entry, + silc_client_update_client(cmd->client, conn, client_entry, nickname, username, realname, mode); silc_free(client_id); } @@ -253,8 +258,8 @@ silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd, /* Notify application */ if (!cmd->callbacks_count && notify) - COMMAND_REPLY((ARGS, client_entry, nickname, username, realname, - has_channels ? &channels : NULL, mode, idle, + COMMAND_REPLY((SILC_ARGS, client_entry, nickname, username, realname, + has_channels ? &channels : NULL, mode, idle, fingerprint, has_user_modes ? &ch_user_modes : NULL, client_entry->attrs)); } @@ -323,13 +328,13 @@ SILC_CLIENT_CMD_REPLY_FUNC(whowas) id_data = silc_argument_get_arg_type(cmd->args, 2, &len); if (!id_data) { - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } - + client_id = silc_id_payload_parse_id(id_data, len, NULL); if (!client_id) { - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } @@ -341,14 +346,14 @@ SILC_CLIENT_CMD_REPLY_FUNC(whowas) username = silc_argument_get_arg_type(cmd->args, 4, &len); realname = silc_argument_get_arg_type(cmd->args, 5, &len); if (!nickname || !username) { - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } /* Notify application. We don't save any history information to any - cache. Just pass the data to the application for displaying on + cache. Just pass the data to the application for displaying on the screen. */ - COMMAND_REPLY((ARGS, client_entry, nickname, username, realname)); + COMMAND_REPLY((SILC_ARGS, client_entry, nickname, username, realname)); /* Pending callbacks are not executed if this was an list entry */ if (cmd->status != SILC_STATUS_OK && @@ -363,10 +368,10 @@ SILC_CLIENT_CMD_REPLY_FUNC(whowas) silc_client_command_reply_free(cmd); } -static void +static void silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd, SilcStatus status, - bool notify) + SilcBool notify) { SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data; SilcClient client = cmd->client; @@ -381,17 +386,17 @@ silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd, char *name = NULL, *info = NULL; SilcIDPayload idp = NULL; SilcIdType id_type; - + id_data = silc_argument_get_arg_type(cmd->args, 2, &len); if (!id_data) { if (notify) - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); return; } idp = silc_id_payload_parse(id_data, len); if (!idp) { if (notify) - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); return; } @@ -410,11 +415,16 @@ silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd, client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id); if (!client_entry) { SILC_LOG_DEBUG(("Adding new client entry")); - client_entry = + client_entry = silc_client_add_client(cmd->client, conn, name, info, NULL, silc_id_dup(client_id, id_type), 0); + if (!client_entry) { + if (notify) + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); + return; + } } else { - silc_client_update_client(cmd->client, conn, client_entry, + silc_client_update_client(cmd->client, conn, client_entry, name, info, NULL, 0); } @@ -422,7 +432,7 @@ silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd, /* Notify application */ if (notify) - COMMAND_REPLY((ARGS, client_entry, name, info)); + COMMAND_REPLY((SILC_ARGS, client_entry, name, info)); break; case SILC_ID_SERVER: @@ -438,7 +448,7 @@ silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd, silc_id_dup(server_id, id_type)); if (!server_entry) { if (notify) - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); return; } } else { @@ -449,7 +459,7 @@ silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd, /* Notify application */ if (notify) - COMMAND_REPLY((ARGS, server_entry, name, info)); + COMMAND_REPLY((SILC_ARGS, server_entry, name, info)); break; case SILC_ID_CHANNEL: @@ -466,12 +476,17 @@ silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd, /* Add new channel entry */ channel_entry = silc_client_add_channel(client, conn, name, 0, channel_id); + if (!channel_entry) { + if (notify) + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); + return; + } channel_id = NULL; } /* Notify application */ if (notify) - COMMAND_REPLY((ARGS, channel_entry, name, info)); + COMMAND_REPLY((SILC_ARGS, channel_entry, name, info)); break; } @@ -482,7 +497,7 @@ silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd, } /* Received reply for IDENTIFY command. This maybe called several times - for one IDENTIFY command as server may reply with list of results. + for one IDENTIFY command as server may reply with list of results. This is totally silent and does not print anything on screen. */ SILC_CLIENT_CMD_REPLY_FUNC(identify) @@ -539,14 +554,15 @@ SILC_CLIENT_CMD_REPLY_FUNC(nick) SilcIDPayload idp; unsigned char *tmp; SilcUInt32 argc, len; + SilcClientID old_client_id; SILC_LOG_DEBUG(("Start")); if (cmd->error != SILC_STATUS_OK) { SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, - "Cannot set nickname: %s", + "Cannot set nickname: %s", silc_get_status_message(cmd->error)); - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(cmd->error); goto out; } @@ -554,15 +570,18 @@ SILC_CLIENT_CMD_REPLY_FUNC(nick) if (argc < 2 || argc > 3) { SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "Cannot set nickname: bad reply to command"); - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } + /* Save old Client ID */ + old_client_id = *conn->local_id; + /* Take received Client ID */ tmp = silc_argument_get_arg_type(cmd->args, 2, &len); idp = silc_id_payload_parse(tmp, len); if (!idp) { - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } silc_client_receive_new_id(cmd->client, cmd->sock, idp); @@ -576,13 +595,24 @@ SILC_CLIENT_CMD_REPLY_FUNC(nick) silc_free(conn->nickname); conn->nickname = strdup(tmp); conn->local_entry->nickname = conn->nickname; + + /* Normalize nickname */ + tmp = silc_identifier_check(conn->nickname, strlen(conn->nickname), + SILC_STRING_UTF8, 128, NULL); + if (!tmp) { + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_BAD_NICKNAME); + goto out; + } + silc_client_nickname_format(cmd->client, conn, conn->local_entry); - silc_idcache_add(conn->internal->client_cache, strdup(tmp), - conn->local_entry->id, conn->local_entry, 0, NULL); + + silc_idcache_add(conn->internal->client_cache, tmp, + conn->local_entry->id, conn->local_entry, 0, NULL); } - + /* Notify application */ - COMMAND_REPLY((ARGS, conn->local_entry, conn->local_entry->nickname)); + COMMAND_REPLY((SILC_ARGS, conn->local_entry, conn->local_entry->nickname, + (const SilcClientID *)&old_client_id)); out: SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK); @@ -604,19 +634,20 @@ SILC_CLIENT_CMD_REPLY_FUNC(list) tmp = silc_argument_get_arg_type(cmd->args, 2, &len); if (!tmp) { - COMMAND_REPLY_ERROR; + /* There were no channels in the network. */ + COMMAND_REPLY((SILC_ARGS, NULL, NULL, 0)); goto out; } channel_id = silc_id_payload_parse_id(tmp, len, NULL); if (!channel_id) { - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } name = silc_argument_get_arg_type(cmd->args, 3, NULL); if (!name) { - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } @@ -626,21 +657,21 @@ SILC_CLIENT_CMD_REPLY_FUNC(list) SILC_GET32_MSB(usercount, tmp); /* Check whether the channel exists, and add it to cache if it doesn't. */ - channel_entry = silc_client_get_channel_by_id(cmd->client, conn, + channel_entry = silc_client_get_channel_by_id(cmd->client, conn, channel_id); if (!channel_entry) { /* Add new channel entry */ channel_entry = silc_client_add_channel(cmd->client, conn, name, 0, channel_id); if (!channel_entry) { - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } channel_id = NULL; } /* Notify application */ - COMMAND_REPLY((ARGS, channel_entry, name, topic, usercount)); + COMMAND_REPLY((SILC_ARGS, channel_entry, name, topic, usercount)); /* Pending callbacks are not executed if this was an list entry */ if (cmd->status != SILC_STATUS_OK && @@ -670,14 +701,14 @@ SILC_CLIENT_CMD_REPLY_FUNC(topic) if (cmd->error != SILC_STATUS_OK) { SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, - "%s", silc_get_status_message(cmd->error)); - COMMAND_REPLY_ERROR; + "Cannot set topic: %s", silc_get_status_message(cmd->error)); + COMMAND_REPLY_ERROR(cmd->error); goto out; } argc = silc_argument_get_arg_num(cmd->args); if (argc < 1 || argc > 3) { - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } @@ -699,12 +730,17 @@ SILC_CLIENT_CMD_REPLY_FUNC(topic) channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id); if (!channel) { silc_free(channel_id); - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } - + + if (topic) { + silc_free(channel->topic); + channel->topic = silc_memdup(topic, strlen(topic)); + } + /* Notify application */ - COMMAND_REPLY((ARGS, channel, topic)); + COMMAND_REPLY((SILC_ARGS, channel, topic)); out: SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC); @@ -721,11 +757,12 @@ SILC_CLIENT_CMD_REPLY_FUNC(invite) SilcChannelID *channel_id; unsigned char *tmp; SilcUInt32 len; + SilcBufferStruct buf; if (cmd->error != SILC_STATUS_OK) { SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, - "%s", silc_get_status_message(cmd->error)); - COMMAND_REPLY_ERROR; + "Cannot invite: %s", silc_get_status_message(cmd->error)); + COMMAND_REPLY_ERROR(cmd->error); goto out; } @@ -742,15 +779,17 @@ SILC_CLIENT_CMD_REPLY_FUNC(invite) channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id); if (!channel) { silc_free(channel_id); - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } /* Get the invite list */ tmp = silc_argument_get_arg_type(cmd->args, 3, &len); + if (tmp) + silc_buffer_set(&buf, tmp, len); /* Notify application */ - COMMAND_REPLY((ARGS, channel, tmp)); + COMMAND_REPLY((SILC_ARGS, channel, tmp ? &buf : NULL)); out: SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE); @@ -758,21 +797,38 @@ SILC_CLIENT_CMD_REPLY_FUNC(invite) } /* Received reply to the KILL command. */ - + SILC_CLIENT_CMD_REPLY_FUNC(kill) { SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context; SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data; + SilcClientID *client_id; + SilcClientEntry client_entry = NULL; + SilcUInt32 len; + unsigned char *id_data; if (cmd->error != SILC_STATUS_OK) { SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, - "%s", silc_get_status_message(cmd->error)); - COMMAND_REPLY_ERROR; + "Cannot kill: %s", silc_get_status_message(cmd->error)); + COMMAND_REPLY_ERROR(cmd->error); goto out; } + id_data = silc_argument_get_arg_type(cmd->args, 2, &len); + if (id_data) { + client_id = silc_id_payload_parse_id(id_data, len, NULL); + if (!client_id) { + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); + goto out; + } + + /* Get the client entry, if exists */ + client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id); + silc_free(client_id); + } + /* Notify application */ - COMMAND_REPLY((ARGS)); + COMMAND_REPLY((SILC_ARGS, client_entry)); out: SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL); @@ -795,9 +851,9 @@ SILC_CLIENT_CMD_REPLY_FUNC(info) SILC_LOG_DEBUG(("Start")); if (cmd->error != SILC_STATUS_OK) { - SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s", + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s", silc_get_status_message(cmd->error)); - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(cmd->error); goto out; } @@ -832,7 +888,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(info) } /* Notify application */ - COMMAND_REPLY((ARGS, server, server->server_name, server->server_info)); + COMMAND_REPLY((SILC_ARGS, server, server->server_name, server->server_info)); out: SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO); @@ -852,7 +908,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(stats) if (cmd->error != SILC_STATUS_OK) { SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s", silc_get_status_message(cmd->error)); - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(cmd->error); goto out; } @@ -865,7 +921,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(stats) buf = silc_argument_get_arg_type(cmd->args, 3, &buf_len); /* Notify application */ - COMMAND_REPLY((ARGS, buf, buf_len)); + COMMAND_REPLY((SILC_ARGS, buf, buf_len)); out: SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_STATS); @@ -885,7 +941,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(ping) if (cmd->error != SILC_STATUS_OK) { SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s", silc_get_status_message(cmd->error)); - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(cmd->error); goto out; } @@ -893,7 +949,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(ping) id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len, cmd->packet->src_id_type); if (!id || !conn->internal->ping) { - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } @@ -902,11 +958,11 @@ SILC_CLIENT_CMD_REPLY_FUNC(ping) continue; if (SILC_ID_SERVER_COMPARE(conn->internal->ping[i].dest_id, id)) { diff = curtime - conn->internal->ping[i].start_time; - SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, - "Ping reply from %s: %d second%s", - conn->internal->ping[i].dest_name, diff, + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, + "Ping reply from %s: %d second%s", + conn->internal->ping[i].dest_name, diff, diff == 1 ? "" : "s"); - + conn->internal->ping[i].start_time = 0; silc_free(conn->internal->ping[i].dest_id); conn->internal->ping[i].dest_id = NULL; @@ -919,7 +975,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(ping) silc_free(id); /* Notify application */ - COMMAND_REPLY((ARGS)); + COMMAND_REPLY((SILC_ARGS)); out: SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING); @@ -938,6 +994,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(join) SilcUInt32 argc, mode = 0, len, list_count; char *topic, *tmp, *channel_name = NULL, *hmac; SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL; + SilcBufferStruct chpklist; int i; SILC_LOG_DEBUG(("Start")); @@ -945,8 +1002,8 @@ SILC_CLIENT_CMD_REPLY_FUNC(join) if (cmd->error != SILC_STATUS_OK) { if (cmd->error != SILC_STATUS_ERR_USER_ON_CHANNEL) SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, - "%s", silc_get_status_message(cmd->error)); - COMMAND_REPLY_ERROR; + "Cannot join channel: %s", silc_get_status_message(cmd->error)); + COMMAND_REPLY_ERROR(cmd->error); goto out; } @@ -954,7 +1011,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(join) if (argc < 7) { SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "Cannot join channel: Bad reply packet"); - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } @@ -963,7 +1020,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(join) if (!tmp) { SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "Cannot join channel: Bad reply packet"); - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } channel_name = tmp; @@ -973,12 +1030,12 @@ SILC_CLIENT_CMD_REPLY_FUNC(join) if (!tmp) { SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "Cannot join channel: Bad reply packet"); - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } channel_id = silc_id_payload_parse_id(tmp, len, NULL); if (!channel_id) { - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } @@ -1005,19 +1062,24 @@ SILC_CLIENT_CMD_REPLY_FUNC(join) silc_client_replace_channel_id(cmd->client, conn, channel, channel_id); } else { /* Create new channel entry */ - channel = silc_client_add_channel(cmd->client, conn, channel_name, + channel = silc_client_add_channel(cmd->client, conn, channel_name, mode, channel_id); } + if (!channel) { + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_BAD_CHANNEL); + goto out; + } conn->current_channel = channel; + channel->mode = mode; /* Get hmac */ hmac = silc_argument_get_arg_type(cmd->args, 11, NULL); if (hmac) { if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) { - SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "Cannot join channel: Unsupported HMAC `%s'", hmac); - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } } @@ -1067,9 +1129,11 @@ SILC_CLIENT_CMD_REPLY_FUNC(join) client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id); if (!client_entry) { /* No, we don't have it, add entry for it. */ - client_entry = + client_entry = silc_client_add_client(cmd->client, conn, NULL, NULL, NULL, silc_id_dup(client_id, SILC_ID_CLIENT), 0); + if (!client_entry) + goto out; } /* Join client to the channel */ @@ -1086,31 +1150,54 @@ SILC_CLIENT_CMD_REPLY_FUNC(join) silc_buffer_pull(client_id_list, idp_len); silc_buffer_pull(client_mode_list, 4); } - silc_buffer_push(client_id_list, client_id_list->data - + silc_buffer_push(client_id_list, client_id_list->data - client_id_list->head); - silc_buffer_push(client_mode_list, client_mode_list->data - + silc_buffer_push(client_mode_list, client_mode_list->data - client_mode_list->head); /* Save channel key */ - if (keyp && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) + if (keyp) silc_client_save_channel_key(cmd->client, conn, keyp, channel); + /* Get founder key */ + tmp = silc_argument_get_arg_type(cmd->args, 15, &len); + if (tmp) { + if (channel->founder_key) + silc_pkcs_public_key_free(channel->founder_key); + channel->founder_key = NULL; + silc_pkcs_public_key_payload_decode(tmp, len, &channel->founder_key); + } + + /* Get user limit */ + tmp = silc_argument_get_arg_type(cmd->args, 17, &len); + if (tmp && len == 4) + SILC_GET32_MSB(channel->user_limit, tmp); + if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT)) + channel->user_limit = 0; + + /* Get channel public key list */ + tmp = silc_argument_get_arg_type(cmd->args, 16, &len); + if (tmp) + silc_buffer_set(&chpklist, tmp, len); + + if (topic) { + silc_free(channel->topic); + channel->topic = silc_memdup(topic, strlen(topic)); + } + /* Notify application */ - COMMAND_REPLY((ARGS, channel_name, channel, mode, 0, + COMMAND_REPLY((SILC_ARGS, channel_name, channel, mode, 0, keyp ? keyp->head : NULL, NULL, - NULL, topic, hmac, list_count, client_id_list, - client_mode_list)); + NULL, topic, hmac, list_count, client_id_list, + client_mode_list, channel->founder_key, + tmp ? &chpklist : NULL, channel->user_limit)); out: SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN); silc_client_command_reply_free(cmd); - - if (keyp) - silc_buffer_free(keyp); - if (client_id_list) - silc_buffer_free(client_id_list); - if (client_mode_list) - silc_buffer_free(client_mode_list); + silc_buffer_free(keyp); + silc_buffer_free(client_id_list); + silc_buffer_free(client_mode_list); } /* Received reply for MOTD command */ @@ -1125,20 +1212,20 @@ SILC_CLIENT_CMD_REPLY_FUNC(motd) if (cmd->error != SILC_STATUS_OK) { SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s", silc_get_status_message(cmd->error)); - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(cmd->error); return; } argc = silc_argument_get_arg_num(cmd->args); if (argc > 3) { - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } if (argc == 3) { motd = silc_argument_get_arg_type(cmd->args, 3, NULL); if (!motd) { - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } @@ -1149,12 +1236,12 @@ SILC_CLIENT_CMD_REPLY_FUNC(motd) memset(line, 0, sizeof(line)); silc_strncat(line, sizeof(line), cp, i - 1); cp += i; - + if (i == 2) line[0] = ' '; - + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line); - + if (!strlen(cp)) break; i = 0; @@ -1163,7 +1250,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(motd) } /* Notify application */ - COMMAND_REPLY((ARGS, motd)); + COMMAND_REPLY((SILC_ARGS, motd)); out: SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD); @@ -1181,14 +1268,14 @@ SILC_CLIENT_CMD_REPLY_FUNC(umode) if (cmd->error != SILC_STATUS_OK) { SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, - "%s", silc_get_status_message(cmd->error)); - COMMAND_REPLY_ERROR; + "Cannot change mode: %s", silc_get_status_message(cmd->error)); + COMMAND_REPLY_ERROR(cmd->error); goto out; } tmp = silc_argument_get_arg_type(cmd->args, 2, NULL); if (!tmp) { - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } @@ -1196,7 +1283,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(umode) conn->local_entry->mode = mode; /* Notify application */ - COMMAND_REPLY((ARGS, mode)); + COMMAND_REPLY((SILC_ARGS, mode)); out: SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE); @@ -1214,11 +1301,13 @@ SILC_CLIENT_CMD_REPLY_FUNC(cmode) SilcChannelID *channel_id; SilcChannelEntry channel; SilcUInt32 len; + SilcPublicKey public_key = NULL; + SilcBufferStruct channel_pubkeys; if (cmd->error != SILC_STATUS_OK) { SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, - "%s", silc_get_status_message(cmd->error)); - COMMAND_REPLY_ERROR; + "Cannot change mode: %s", silc_get_status_message(cmd->error)); + COMMAND_REPLY_ERROR(cmd->error); goto out; } @@ -1234,15 +1323,15 @@ SILC_CLIENT_CMD_REPLY_FUNC(cmode) channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id); if (!channel) { silc_free(channel_id); - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } - + /* Get channel mode */ tmp = silc_argument_get_arg_type(cmd->args, 3, NULL); if (!tmp) { silc_free(channel_id); - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } @@ -1250,12 +1339,34 @@ SILC_CLIENT_CMD_REPLY_FUNC(cmode) SILC_GET32_MSB(mode, tmp); channel->mode = mode; + /* Get founder public key */ + tmp = silc_argument_get_arg_type(cmd->args, 4, &len); + if (tmp) { + if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key)) + public_key = NULL; + } + + /* Get user limit */ + tmp = silc_argument_get_arg_type(cmd->args, 6, &len); + if (tmp && len == 4) + SILC_GET32_MSB(channel->user_limit, tmp); + if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT)) + channel->user_limit = 0; + + /* Get channel public key(s) */ + tmp = silc_argument_get_arg_type(cmd->args, 5, &len); + if (tmp) + silc_buffer_set(&channel_pubkeys, tmp, len); + /* Notify application */ - COMMAND_REPLY((ARGS, channel, mode)); + COMMAND_REPLY((SILC_ARGS, channel, mode, public_key, + tmp ? &channel_pubkeys : NULL, channel->user_limit)); silc_free(channel_id); out: + if (public_key) + silc_pkcs_public_key_free(public_key); SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE); silc_client_command_reply_free(cmd); } @@ -1273,18 +1384,18 @@ SILC_CLIENT_CMD_REPLY_FUNC(cumode) SilcChannelUser chu; unsigned char *modev, *tmp, *id; SilcUInt32 len, mode; - + if (cmd->error != SILC_STATUS_OK) { SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, - "%s", silc_get_status_message(cmd->error)); - COMMAND_REPLY_ERROR; + "Cannot change mode: %s", silc_get_status_message(cmd->error)); + COMMAND_REPLY_ERROR(cmd->error); goto out; } - + /* Get channel mode */ modev = silc_argument_get_arg_type(cmd->args, 2, NULL); if (!modev) { - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } @@ -1300,30 +1411,30 @@ SILC_CLIENT_CMD_REPLY_FUNC(cumode) channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id); if (!channel) { silc_free(channel_id); - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } - + /* Get Client ID */ id = silc_argument_get_arg_type(cmd->args, 4, &len); if (!id) { silc_free(channel_id); - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } client_id = silc_id_payload_parse_id(id, len, NULL); if (!client_id) { silc_free(channel_id); - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } - + /* Get client entry */ client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id); if (!client_entry) { silc_free(channel_id); silc_free(client_id); - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } @@ -1334,10 +1445,10 @@ SILC_CLIENT_CMD_REPLY_FUNC(cumode) chu->mode = mode; /* Notify application */ - COMMAND_REPLY((ARGS, mode, channel, client_entry)); + COMMAND_REPLY((SILC_ARGS, mode, channel, client_entry)); silc_free(client_id); silc_free(channel_id); - + out: SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE); silc_client_command_reply_free(cmd); @@ -1347,18 +1458,60 @@ SILC_CLIENT_CMD_REPLY_FUNC(kick) { SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context; SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data; + SilcClientID *client_id = NULL; + SilcChannelID *channel_id = NULL; + SilcClientEntry client_entry = NULL; + SilcChannelEntry channel = NULL; + unsigned char *tmp; + SilcUInt32 len; if (cmd->error != SILC_STATUS_OK) { SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, - "%s", silc_get_status_message(cmd->error)); - COMMAND_REPLY_ERROR; + "Cannot kick: %s", silc_get_status_message(cmd->error)); + COMMAND_REPLY_ERROR(cmd->error); goto out; } + /* Take Channel ID */ + tmp = silc_argument_get_arg_type(cmd->args, 2, &len); + if (tmp) { + channel_id = silc_id_payload_parse_id(tmp, len, NULL); + if (!channel_id) { + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); + goto out; + } + + /* Get the channel entry */ + channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id); + if (!channel) { + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); + goto out; + } + } + + /* Get Client ID */ + tmp = silc_argument_get_arg_type(cmd->args, 3, &len); + if (tmp) { + client_id = silc_id_payload_parse_id(tmp, len, NULL); + if (!client_id) { + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); + goto out; + } + + /* Get client entry */ + client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id); + if (!client_entry) { + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); + goto out; + } + } + /* Notify application */ - COMMAND_REPLY((ARGS)); + COMMAND_REPLY((SILC_ARGS, channel, client_entry)); out: + silc_free(channel_id); + silc_free(client_id); SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK); silc_client_command_reply_free(cmd); } @@ -1371,12 +1524,12 @@ SILC_CLIENT_CMD_REPLY_FUNC(silcoper) if (cmd->error != SILC_STATUS_OK) { SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s", silc_get_status_message(cmd->error)); - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(cmd->error); goto out; } /* Notify application */ - COMMAND_REPLY((ARGS)); + COMMAND_REPLY((SILC_ARGS)); out: SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER); @@ -1391,12 +1544,12 @@ SILC_CLIENT_CMD_REPLY_FUNC(oper) if (cmd->error != SILC_STATUS_OK) { SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s", silc_get_status_message(cmd->error)); - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(cmd->error); goto out; } /* Notify application */ - COMMAND_REPLY((ARGS)); + COMMAND_REPLY((SILC_ARGS)); out: SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER); @@ -1412,18 +1565,18 @@ SILC_CLIENT_CMD_REPLY_FUNC(detach) if (cmd->error != SILC_STATUS_OK) { SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s", silc_get_status_message(cmd->error)); - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(cmd->error); goto out; } /* Notify application */ - COMMAND_REPLY((ARGS)); + COMMAND_REPLY((SILC_ARGS)); /* Generate the detachment data and deliver it to the client in the detach client operation */ detach = silc_client_get_detach_data(cmd->client, conn); if (detach) { - cmd->client->internal->ops->detach(cmd->client, conn, + cmd->client->internal->ops->detach(cmd->client, conn, detach->data, detach->len); silc_buffer_free(detach); } @@ -1441,12 +1594,12 @@ SILC_CLIENT_CMD_REPLY_FUNC(watch) if (cmd->error != SILC_STATUS_OK) { SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s", silc_get_status_message(cmd->error)); - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(cmd->error); goto out; } /* Notify application */ - COMMAND_REPLY((ARGS)); + COMMAND_REPLY((SILC_ARGS)); out: SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WATCH); @@ -1461,11 +1614,12 @@ SILC_CLIENT_CMD_REPLY_FUNC(ban) SilcChannelID *channel_id; unsigned char *tmp; SilcUInt32 len; + SilcBufferStruct buf; if (cmd->error != SILC_STATUS_OK) { SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s", silc_get_status_message(cmd->error)); - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(cmd->error); goto out; } @@ -1482,15 +1636,17 @@ SILC_CLIENT_CMD_REPLY_FUNC(ban) channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id); if (!channel) { silc_free(channel_id); - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } - + /* Get the ban list */ tmp = silc_argument_get_arg_type(cmd->args, 3, &len); + if (tmp) + silc_buffer_set(&buf, tmp, len); /* Notify application */ - COMMAND_REPLY((ARGS, channel, tmp)); + COMMAND_REPLY((SILC_ARGS, channel, tmp ? &buf : NULL)); out: SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN); @@ -1505,13 +1661,14 @@ SILC_CLIENT_CMD_REPLY_FUNC(leave) SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data; SilcChannelID *channel_id; SilcChannelEntry channel = NULL; + SilcChannelUser chu; unsigned char *tmp; SilcUInt32 len; if (cmd->error != SILC_STATUS_OK) { SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s", silc_get_status_message(cmd->error)); - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(cmd->error); goto out; } @@ -1526,15 +1683,27 @@ SILC_CLIENT_CMD_REPLY_FUNC(leave) channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id); if (!channel) { silc_free(channel_id); - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } + /* Remove us from this channel. */ + chu = silc_client_on_channel(channel, conn->local_entry); + if (chu) { + silc_hash_table_del(chu->client->channels, chu->channel); + silc_hash_table_del(chu->channel->user_list, chu->client); + silc_free(chu); + } + silc_free(channel_id); } /* Notify application */ - COMMAND_REPLY((ARGS, channel)); + COMMAND_REPLY((SILC_ARGS, channel)); + + /* Now delete the channel. */ + if (channel) + silc_client_del_channel(cmd->client, conn, channel); out: SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE); @@ -1556,7 +1725,7 @@ static void silc_client_command_reply_users_cb(SilcClient client, cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL; SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s", silc_get_status_message(cmd->error)); - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(cmd->error); SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS); silc_client_command_reply_free(cmd); return; @@ -1568,7 +1737,8 @@ static void silc_client_command_reply_users_cb(SilcClient client, static int silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd, SilcStatus status, - bool notify, + SilcBool notify, + SilcBool resolve, SilcGetChannelCallback get_channel, SilcCommandCb get_clients) { @@ -1583,26 +1753,26 @@ silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd, int i; unsigned char **res_argv = NULL; SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0; - bool wait_res = FALSE; + SilcBool wait_res = FALSE; SILC_LOG_DEBUG(("Start")); /* Get channel ID */ tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len); if (!tmp) { - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL); if (!channel_id) { - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } - + /* Get the list count */ tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len); if (!tmp) { - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } SILC_GET32_MSB(list_count, tmp); @@ -1610,7 +1780,7 @@ silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd, /* Get Client ID list */ tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len); if (!tmp) { - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } silc_buffer_set(&client_id_list, tmp, tmp_len); @@ -1618,7 +1788,7 @@ silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd, /* Get client mode list */ tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len); if (!tmp) { - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } silc_buffer_set(&client_mode_list, tmp, tmp_len); @@ -1654,19 +1824,21 @@ silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd, /* Check if we have this client cached already. */ client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id); if (!client_entry || !client_entry->username || !client_entry->realname) { - /* No we don't have it (or it is incomplete in information), query - it from the server. Assemble argument table that will be sent - for the WHOIS command later. */ - res_argv = silc_realloc(res_argv, sizeof(*res_argv) * - (res_argc + 1)); - res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) * - (res_argc + 1)); - res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) * - (res_argc + 1)); - res_argv[res_argc] = client_id_list.data; - res_argv_lens[res_argc] = idp_len; - res_argv_types[res_argc] = res_argc + 4; - res_argc++; + if (resolve) { + /* No we don't have it (or it is incomplete in information), query + it from the server. Assemble argument table that will be sent + for the WHOIS command later. */ + res_argv = silc_realloc(res_argv, sizeof(*res_argv) * + (res_argc + 1)); + res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) * + (res_argc + 1)); + res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) * + (res_argc + 1)); + res_argv[res_argc] = client_id_list.data; + res_argv_lens[res_argc] = idp_len; + res_argv_types[res_argc] = res_argc + 4; + res_argc++; + } } else { if (!silc_client_on_channel(channel, client_entry)) { chu = silc_calloc(1, sizeof(*chu)); @@ -1695,7 +1867,7 @@ silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd, res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS, res_argc, res_argv, res_argv_lens, res_argv_types, conn->cmd_ident); - silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, + silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len, TRUE); @@ -1716,14 +1888,14 @@ silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd, if (wait_res) return 1; - silc_buffer_push(&client_id_list, (client_id_list.data - + silc_buffer_push(&client_id_list, (client_id_list.data - client_id_list.head)); - silc_buffer_push(&client_mode_list, (client_mode_list.data - + silc_buffer_push(&client_mode_list, (client_mode_list.data - client_mode_list.head)); /* Notify application */ if (notify) - COMMAND_REPLY((ARGS, channel, list_count, &client_id_list, + COMMAND_REPLY((SILC_ARGS, channel, list_count, &client_id_list, &client_mode_list)); out: @@ -1738,17 +1910,35 @@ SILC_CLIENT_CMD_REPLY_FUNC(users) { SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context; SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data; + SilcClientCommandReplyContext r = (SilcClientCommandReplyContext)context2; SILC_LOG_DEBUG(("Start")); if (cmd->error != SILC_STATUS_OK) { SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, - "%s", silc_get_status_message(cmd->error)); - COMMAND_REPLY_ERROR; + "Query failed: %s", silc_get_status_message(cmd->error)); + COMMAND_REPLY_ERROR(cmd->error); goto out; } - if (silc_client_command_reply_users_save(cmd, cmd->status, TRUE, + if (r && !silc_command_get_status(r->payload, NULL, &cmd->error)) { + if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) { + /* Do not resolve anymore. Server may be sending us some non-existent + Client ID (a bug in server), and we want to show the users list + anyway. */ + silc_client_command_reply_users_save(cmd, cmd->status, TRUE, FALSE, + silc_client_command_reply_users_cb, + silc_client_command_reply_users); + goto out; + } else { + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, + "Query failed: %s", silc_get_status_message(cmd->error)); + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); + goto out; + } + } + + if (silc_client_command_reply_users_save(cmd, cmd->status, TRUE, TRUE, silc_client_command_reply_users_cb, silc_client_command_reply_users)) return; @@ -1770,10 +1960,8 @@ SILC_CLIENT_CMD_REPLY_FUNC(getkey) SilcClientEntry client_entry; SilcServerID *server_id = NULL; SilcServerEntry server_entry; - SilcSKEPKType type; - unsigned char *tmp, *pk; + unsigned char *tmp; SilcUInt32 len; - SilcUInt16 pk_len; SilcIdType id_type; SilcPublicKey public_key = NULL; @@ -1782,57 +1970,69 @@ SILC_CLIENT_CMD_REPLY_FUNC(getkey) if (cmd->error != SILC_STATUS_OK) { SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s", silc_get_status_message(cmd->error)); - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(cmd->error); goto out; } tmp = silc_argument_get_arg_type(cmd->args, 2, &len); if (!tmp) { - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } idp = silc_id_payload_parse(tmp, len); if (!idp) { - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } /* Get the public key payload */ tmp = silc_argument_get_arg_type(cmd->args, 3, &len); if (tmp) { - /* Decode the public key */ - SILC_GET16_MSB(pk_len, tmp); - SILC_GET16_MSB(type, tmp + 2); - pk = tmp + 4; - - if (type == SILC_SKE_PK_TYPE_SILC) - if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key)) - public_key = NULL; - } - + if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key)) + public_key = NULL; + } + + if (!public_key) { + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); + goto out; + } + id_type = silc_id_payload_get_type(idp); if (id_type == SILC_ID_CLIENT) { /* Received client's public key */ client_id = silc_id_payload_get_id(idp); client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id); if (!client_entry) { - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } + /* Save fingerprint */ + if (!client_entry->fingerprint) { + client_entry->fingerprint = silc_calloc(20, sizeof(unsigned char)); + client_entry->fingerprint_len = 20; + silc_hash_make(cmd->client->sha1hash, tmp + 4, len - 4, + client_entry->fingerprint); + } + if (!client_entry->public_key) { + client_entry->public_key = public_key; + public_key = NULL; + } + /* Notify application */ - COMMAND_REPLY((ARGS, id_type, client_entry, public_key)); + COMMAND_REPLY((SILC_ARGS, id_type, client_entry, + client_entry->public_key)); } else if (id_type == SILC_ID_SERVER) { /* Received server's public key */ server_id = silc_id_payload_get_id(idp); server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id); if (!server_entry) { - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } /* Notify application */ - COMMAND_REPLY((ARGS, id_type, server_entry, public_key)); + COMMAND_REPLY((SILC_ARGS, id_type, server_entry, public_key)); } out: @@ -1846,6 +2046,32 @@ SILC_CLIENT_CMD_REPLY_FUNC(getkey) silc_client_command_reply_free(cmd); } +/* Reply to SERVICE command. */ +/* XXX incomplete */ + +SILC_CLIENT_CMD_REPLY_FUNC(service) +{ + SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context; + SilcUInt32 tmp_len; + unsigned char *service_list, *name; + + COMMAND_CHECK_STATUS; + + /* Get service list */ + service_list = silc_argument_get_arg_type(cmd->args, 2, &tmp_len); + + /* Get requested service name */ + name = silc_argument_get_arg_type(cmd->args, 3, &tmp_len); + + /* Notify application */ + COMMAND_REPLY((SILC_ARGS, service_list, name)); + + out: + SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SERVICE); + err: + silc_client_command_reply_free(cmd); +} + SILC_CLIENT_CMD_REPLY_FUNC(quit) { silc_client_command_reply_free(context); @@ -1994,7 +2220,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(info_i) silc_client_add_server(cmd->client, conn, server_name, server_info, silc_id_dup(server_id, SILC_ID_SERVER)); } - + out: SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO); silc_free(server_id); @@ -2015,7 +2241,7 @@ static void silc_client_command_reply_users_i_cb(SilcClient client, cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL; SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s", silc_get_status_message(cmd->error)); - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(cmd->error); SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS); silc_client_command_reply_free(cmd); return; @@ -2032,7 +2258,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(users_i) /* Save USERS info */ if (silc_client_command_reply_users_save( - cmd, cmd->status, FALSE, + cmd, cmd->status, FALSE, TRUE, silc_client_command_reply_users_i_cb, silc_client_command_reply_users_i)) return; @@ -2060,12 +2286,12 @@ SILC_CLIENT_CMD_REPLY_FUNC(connect) if (cmd->error != SILC_STATUS_OK) { SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s", silc_get_status_message(cmd->error)); - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(cmd->error); goto out; } /* Notify application */ - COMMAND_REPLY((ARGS)); + COMMAND_REPLY((SILC_ARGS)); out: SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CONNECT); @@ -2080,18 +2306,18 @@ SILC_CLIENT_CMD_REPLY_FUNC(close) if (cmd->error != SILC_STATUS_OK) { SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s", silc_get_status_message(cmd->error)); - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(cmd->error); goto out; } /* Notify application */ - COMMAND_REPLY((ARGS)); + COMMAND_REPLY((SILC_ARGS)); out: SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CLOSE); silc_client_command_reply_free(cmd); } - + SILC_CLIENT_CMD_REPLY_FUNC(shutdown) { SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context; @@ -2100,12 +2326,12 @@ SILC_CLIENT_CMD_REPLY_FUNC(shutdown) if (cmd->error != SILC_STATUS_OK) { SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s", silc_get_status_message(cmd->error)); - COMMAND_REPLY_ERROR; + COMMAND_REPLY_ERROR(cmd->error); goto out; } /* Notify application */ - COMMAND_REPLY((ARGS)); + COMMAND_REPLY((SILC_ARGS)); out: SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_SHUTDOWN);