+Fri May 3 11:37:10 EEST 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Fixed rekey protocol with PFS in the client library.
+ Affected file is lib/silcclient/protocol.c.
+
+ * Added support for list of errors in client library
+ command reply handling. Affected file is
+ lib/silcclient/command_reply.c.
+
+ * Defined that the WHOIS and IDENTIFY commands can send
+ list of errors. Updated the protocol specs. Protocol
+ TODO #2.
+
+ * Added support for sending list of errors to WHOIS and
+ IDENTIFY commands in server. Added support for receiving
+ list of errors in server. Affected files are
+ silcd/command.c and silcd/command_reply.c.
+
+ * Fixed client info resolving on LEAVE command in client
+ library to not crash. Affected file is
+ lib/silcclient/client_notify.c.
+
Thu May 2 08:45:11 CEST 2002 Pekka Riikonen <priikone@silcnet.org>
* Defined that the NICK command replies with thew changed
set the key only if application wishes to set (accept the key) it
(Do this to 1.0).
- o Additions to do after protocol version 1.1:
-
- o Add support for list of errors in command replies. Protocol
- TODO entry 1.
-
TODO/bugs In SILC Server
========================
and router does not have founder on channel (founder is left or there's
no founder on channel at all), the router will accept the server's
founder mode change, even though it perhaps should not do that (Fix
- this to 0.9).
-
- o The router should check for validity of received notify packets from
- routers (fix this to 0.9). Following NOTIFYs needs to be verified:
-
- o JOIN (check that joining is allowed)
- o SIGNOFF (maybe should check that notifier owns the client)
+ this to 0.9) (Protocol TODO #17 relates).
o Implement the SILC_CUMODE_QUIET user mode (Do this to 0.9.x).
signal_emit("message part", 5, server, chanrec->name,
server->nick, userhost, "");
+ chanrec->left = TRUE;
silc_command_exec(server, "LEAVE", chanrec->name);
signal_stop();
typedef struct {
void *id;
+ SilcIdType id_type;
SilcUInt32 index;
SilcStatus error;
} *ResolveError;
-#define ADD_ERROR(errptr, errptr_count, _id, _index, _status) \
+#define ADD_ERROR(errptr, errptr_count, _id, _id_type, _index, _status) \
do { \
errptr = silc_realloc(errptr, sizeof(*errptr) * (errptr_count + 1)); \
if (!errptr) \
return FALSE; \
errptr[errptr_count].id = _id; \
+ errptr[errptr_count].id_type = _id_type; \
errptr[errptr_count].index = _index; \
errptr[errptr_count].error = _status; \
errptr_count++; \
int i, k;
/* If client ID is in the command it must be used instead of nickname */
- tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
+ tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
if (!tmp) {
/* No ID, get the nickname@server string and parse it. */
tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
/* Command includes ID, we must use that. Take all ID's from the
command packet */
for (k = 0, i = 0; i < argc; i++) {
- tmp = silc_argument_get_arg_type(cmd->args, i + 3, &len);
+ tmp = silc_argument_get_arg_type(cmd->args, i + 4, &len);
if (!tmp)
continue;
id = silc_id_payload_parse_id(tmp, len, NULL);
(*client_id_count)++;
k++;
} else {
- ADD_ERROR((*error_client), (*error_client_count), NULL, i + 3,
+ ADD_ERROR((*error_client), (*error_client_count), NULL, 0, i + 4,
SILC_STATUS_ERR_BAD_CLIENT_ID);
}
}
/* Get the max count of reply messages allowed */
tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
- if (tmp) {
+ if (tmp)
SILC_GET32_MSB(*count, tmp);
- } else {
+ else
*count = 0;
- }
return TRUE;
}
sizeof(**r->res_argv));
memcpy(r->res_argv[r->res_argc], idp->data, idp->len);
r->res_argv_lens[r->res_argc] = idp->len;
- r->res_argv_types[r->res_argc] = r->res_argc + 3;
+ r->res_argv_types[r->res_argc] = r->res_argc + 4;
r->res_argc++;
silc_buffer_free(idp);
umode_list = NULL;
}
- if (count && k - 1 == count)
+ if (status == SILC_STATUS_LIST_END)
break;
k++;
}
silc_buffer_free(idp);
idp = NULL;
- if (count && k - 1 == count)
+ if (status == SILC_STATUS_LIST_END)
break;
k++;
}
goto out;
}
- ADD_ERROR(error_client, error_client_count, client_id[i], 0,
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
+ ADD_ERROR(error_client, error_client_count, client_id[i],
+ SILC_ID_CLIENT, 0, SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
}
}
} else if (nick) {
/* Get the max count of reply messages allowed */
tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
- if (tmp) {
+ if (tmp)
SILC_GET32_MSB(*count, tmp);
- } else {
+ else
*count = 0;
- }
return TRUE;
}
if (!valid_count) {
/* No valid entries found at all, just send error */
- unsigned char *tmp;
-
tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
- if (tmp)
- silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOWAS,
- SILC_STATUS_ERR_NO_SUCH_NICK, 0,
- 3, tmp, strlen(tmp));
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOWAS,
+ SILC_STATUS_ERR_NO_SUCH_NICK, 0,
+ 3, tmp, tmp ? strlen(tmp) : 0);
return;
}
status = SILC_STATUS_LIST_END;
if (count && k - 1 == count)
status = SILC_STATUS_LIST_END;
- if (count && k - 1 > count)
- break;
/* Send WHOWAS reply */
idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
silc_buffer_free(packet);
silc_buffer_free(idp);
+ if (status == SILC_STATUS_LIST_END)
+ break;
k++;
}
}
SilcUInt32 *servers_count,
SilcChannelEntry **channels,
SilcUInt32 *channels_count,
- SilcUInt32 *count)
+ SilcUInt32 *count,
+ ResolveError *error_id,
+ SilcUInt32 *error_id_count)
{
SilcServer server = cmd->server;
unsigned char *tmp;
bool check_global = FALSE;
void *entry;
int i;
- bool error = FALSE;
if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
check_global = TRUE;
continue;
idp = silc_id_payload_parse(tmp, len);
- if (!idp) {
- silc_free(*clients);
- silc_free(*servers);
- silc_free(*channels);
- silc_server_command_send_status_reply(
- cmd, SILC_COMMAND_IDENTIFY,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
- return 0;
- }
+ if (!idp)
+ ADD_ERROR((*error_id), (*error_id_count), NULL, 0, i + 5,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
id = silc_id_payload_get_id(idp);
-
switch (silc_id_payload_get_type(idp)) {
case SILC_ID_CLIENT:
- entry = (void *)silc_idlist_find_client_by_id(server->local_list,
- id, TRUE, NULL);
+ entry = silc_idlist_find_client_by_id(server->local_list,
+ id, TRUE, NULL);
if (!entry && check_global)
- entry = (void *)silc_idlist_find_client_by_id(server->global_list,
- id, TRUE, NULL);
+ entry = silc_idlist_find_client_by_id(server->global_list,
+ id, TRUE, NULL);
if (entry) {
*clients = silc_realloc(*clients, sizeof(**clients) *
(*clients_count + 1));
silc_free(*clients);
silc_free(*servers);
silc_free(*channels);
+ silc_free(*error_id);
return -1;
- } else {
- silc_server_command_send_status_data(
- cmd, SILC_COMMAND_IDENTIFY,
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
- 0, 2, tmp, len);
- error = TRUE;
}
+
+ ADD_ERROR((*error_id), (*error_id_count), NULL, 0, i + 5,
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
}
break;
case SILC_ID_SERVER:
- entry = (void *)silc_idlist_find_server_by_id(server->local_list,
- id, TRUE, NULL);
+ entry = silc_idlist_find_server_by_id(server->local_list,
+ id, TRUE, NULL);
if (!entry && check_global)
- entry = (void *)silc_idlist_find_server_by_id(server->global_list,
- id, TRUE, NULL);
+ entry = silc_idlist_find_server_by_id(server->global_list,
+ id, TRUE, NULL);
if (entry) {
*servers = silc_realloc(*servers, sizeof(**servers) *
(*servers_count + 1));
silc_free(*clients);
silc_free(*servers);
silc_free(*channels);
+ silc_free(*error_id);
return -1;
- } else {
- silc_server_command_send_status_data(
- cmd, SILC_COMMAND_IDENTIFY,
- SILC_STATUS_ERR_NO_SUCH_SERVER_ID,
- 0, 2, tmp, len);
- error = TRUE;
}
+
+ ADD_ERROR((*error_id), (*error_id_count), NULL, 0, i + 5,
+ SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
}
break;
case SILC_ID_CHANNEL:
- entry = (void *)silc_idlist_find_channel_by_id(server->local_list,
- id, NULL);
+ entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
if (!entry && check_global)
- entry = (void *)silc_idlist_find_channel_by_id(server->global_list,
- id, NULL);
+ entry = silc_idlist_find_channel_by_id(server->global_list, id,
+ NULL);
if (entry) {
*channels = silc_realloc(*channels, sizeof(**channels) *
(*channels_count + 1));
silc_free(*clients);
silc_free(*servers);
silc_free(*channels);
+ silc_free(*error_id);
return -1;
- } else {
- silc_server_command_send_status_data(
- cmd, SILC_COMMAND_IDENTIFY,
- SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
- 0, 2, tmp, len);
- error = TRUE;
}
+
+ ADD_ERROR((*error_id), (*error_id_count), NULL, 0, i + 5,
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
}
break;
}
}
}
- if (error) {
- silc_free(*clients);
- silc_free(*servers);
- silc_free(*channels);
- return FALSE;
- }
-
/* Get the max count of reply messages allowed */
tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
- if (tmp) {
+ if (tmp)
SILC_GET32_MSB(*count, tmp);
- } else {
+ else
*count = 0;
- }
return 1;
}
sizeof(**r->res_argv));
memcpy(r->res_argv[r->res_argc], idp->data, idp->len);
r->res_argv_lens[r->res_argc] = idp->len;
- r->res_argv_types[r->res_argc] = r->res_argc + 3;
+ r->res_argv_types[r->res_argc] = r->res_argc + 4;
r->res_argc++;
silc_buffer_free(idp);
SilcUInt32 servers_count,
SilcChannelEntry *channels,
SilcUInt32 channels_count,
+ ResolveError errors,
+ SilcUInt32 errors_count,
int count)
{
SilcServer server = cmd->server;
- int i, k, len, valid_count;
+ int i, k, valid_count;
+ SilcUInt32 len;
SilcBuffer packet, idp;
SilcStatus status;
SilcUInt16 ident = silc_command_get_ident(cmd->payload);
char nh[256], uh[256];
SilcSocketConnection hsock;
+ unsigned char *tmp;
status = SILC_STATUS_OK;
if (clients) {
SilcClientEntry entry;
+ valid_count = clients_count;
+
+ if (silc_argument_get_arg_type(cmd->args, 1, NULL)) {
+ /* Process only valid clients and ignore those that are not registered.
+ This is checked with nickname only because when resolved client IDs
+ we check that they are registered earlier. */
+ valid_count = 0;
+ for (i = 0; i < clients_count; i++) {
+ if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED)
+ valid_count++;
+ else
+ clients[i] = NULL;
+ }
- /* Process only valid entries. */
- valid_count = 0;
- for (i = 0; i < clients_count; i++) {
- if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED)
- valid_count++;
- else
- clients[i] = NULL;
- }
-
- if (!valid_count) {
- /* No valid entries found at all, just send error */
- unsigned char *tmp;
-
- tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
- if (tmp) {
+ if (!valid_count) {
+ /* No valid entries found at all, just send error */
+ tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
SILC_STATUS_ERR_NO_SUCH_NICK, 0,
- 3, tmp, strlen(tmp));
- } else {
- tmp = silc_argument_get_arg_type(cmd->args, 5, (SilcUInt32 *)&len);
- silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
- 0, 2, tmp, len);
+ 3, tmp, tmp ? strlen(tmp) : 0);
+ return;
}
- return;
}
/* Process all valid client entries and send command replies */
if (k >= 1)
status = SILC_STATUS_LIST_ITEM;
if (valid_count > 1 && k == valid_count - 1
- && !servers_count && !channels_count)
+ && !servers_count && !channels_count && !errors_count)
status = SILC_STATUS_LIST_END;
if (count && k - 1 == count)
status = SILC_STATUS_LIST_END;
silc_buffer_free(packet);
silc_buffer_free(idp);
- if (count && k - 1 == count)
+ if (status == SILC_STATUS_LIST_END)
break;
-
k++;
}
}
if (k >= 1)
status = SILC_STATUS_LIST_ITEM;
- if (servers_count > 1 && k == servers_count - 1 && !channels_count)
+ if (servers_count > 1 && k == servers_count - 1 && !channels_count &&
+ !errors_count)
status = SILC_STATUS_LIST_END;
if (count && k - 1 == count)
status = SILC_STATUS_LIST_END;
silc_buffer_free(packet);
silc_buffer_free(idp);
- if (count && k - 1 == count)
+ if (status == SILC_STATUS_LIST_END)
break;
-
k++;
}
}
if (k >= 1)
status = SILC_STATUS_LIST_ITEM;
- if (channels_count > 1 && k == channels_count - 1)
+ if (channels_count > 1 && k == channels_count - 1 && !errors_count)
status = SILC_STATUS_LIST_END;
if (count && k - 1 == count)
status = SILC_STATUS_LIST_END;
silc_buffer_free(packet);
silc_buffer_free(idp);
- if (count && k - 1 == count)
+ if (status == SILC_STATUS_LIST_END)
break;
+ k++;
+ }
+ }
+
+ /* Send error replies */
+ if (errors) {
+ if (status == SILC_STATUS_OK && errors_count > 1)
+ status = SILC_STATUS_LIST_START;
+ idp = NULL;
+ for (i = 0, k = 0; i < errors_count; i++) {
+ if (errors[i].id) {
+ idp = silc_id_payload_encode(errors[i].id, SILC_ID_CLIENT);
+ tmp = idp->data;
+ len = idp->len;
+ } else {
+ tmp = silc_argument_get_arg_type(cmd->args, errors[i].index, &len);
+ }
+
+ if (k >= 1)
+ status = SILC_STATUS_LIST_ITEM;
+ if (errors_count > 1 && k == errors_count - 1)
+ status = SILC_STATUS_LIST_END;
+ if (count && k - 1 == count)
+ status = SILC_STATUS_LIST_END;
+
+ /* Send error */
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+ (status == SILC_STATUS_OK ?
+ errors[i].error : status),
+ (status == SILC_STATUS_OK ?
+ 0 : errors[i].error),
+ 2, tmp, len);
+ silc_buffer_free(idp);
+ idp = NULL;
+
+ if (status == SILC_STATUS_LIST_END)
+ break;
k++;
}
}
SilcServerEntry *servers = NULL;
SilcChannelEntry *channels = NULL;
SilcUInt32 clients_count = 0, servers_count = 0, channels_count = 0;
+ SilcUInt32 errors_count = 0;
+ ResolveError errors = NULL;
/* Parse the IDENTIFY request */
ret = silc_server_command_identify_parse(cmd,
&clients, &clients_count,
&servers, &servers_count,
&channels, &channels_count,
- &count);
+ &count, &errors, &errors_count);
if (ret < 1)
return ret;
ret = 0;
/* Check that all mandatory fields are present and request those data
from the server who owns the client if necessary. */
- if (clients && !silc_server_command_identify_check_client(cmd, clients,
- clients_count)) {
+ if (!silc_server_command_identify_check_client(cmd, clients,
+ clients_count)) {
ret = -1;
goto out;
}
clients, clients_count,
servers, servers_count,
channels, channels_count,
+ errors, errors_count,
count);
out:
silc_free(clients);
silc_free(servers);
silc_free(channels);
+ silc_free(errors);
return ret;
}
#include "command_reply.h"
/* All functions that call the COMMAND_CHECK_STATUS macros must have
- out: goto label. */
-
-#define COMMAND_CHECK_STATUS \
-do { \
- SILC_LOG_DEBUG(("Start")); \
- if (!silc_command_get_status(cmd->payload, &status, &error)) \
- goto out; \
+ out: and err: goto labels. */
+
+#define COMMAND_CHECK_STATUS \
+do { \
+ SILC_LOG_DEBUG(("Start")); \
+ if (!silc_command_get_status(cmd->payload, &status, &error)) { \
+ if (SILC_STATUS_IS_ERROR(status)) \
+ goto out; \
+ if (status == SILC_STATUS_LIST_END) \
+ goto out; \
+ goto err; \
+ } \
} while(0)
/* Server command reply list. Not all commands have reply function as
}
}
+static void
+silc_server_command_process_error(SilcServerCommandReplyContext cmd,
+ SilcStatus error)
+{
+ SilcServer server = cmd->server;
+
+ /* If we received notify for invalid ID we'll remove the ID if we
+ have it cached. */
+ if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID &&
+ cmd->sock->type == SILC_SOCKET_TYPE_ROUTER) {
+ SilcClientEntry client;
+ SilcUInt32 tmp_len;
+ unsigned char *tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+ if (tmp) {
+ SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+ if (client_id) {
+ SILC_LOG_DEBUG(("Received invalid client ID notification, deleting "
+ "the entry from cache"));
+ client = silc_idlist_find_client_by_id(server->global_list,
+ client_id, FALSE, NULL);
+ if (client) {
+ silc_server_remove_from_channels(server, NULL, client, TRUE,
+ NULL, TRUE);
+ silc_idlist_del_client(server->global_list, client);
+ }
+ silc_free(client_id);
+ }
+ }
+ }
+}
+
/* Caches the received WHOIS information. */
static char
SILC_SERVER_CMD_REPLY_FUNC(whois)
{
SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
- SilcServer server = cmd->server;
SilcStatus status, error;
COMMAND_CHECK_STATUS;
}
out:
- /* If we received notify for invalid ID we'll remove the ID if we
- have it cached. */
- if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID &&
- cmd->sock->type == SILC_SOCKET_TYPE_ROUTER) {
- SilcClientEntry client;
- SilcUInt32 tmp_len;
- unsigned char *tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
- if (tmp) {
- SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
- if (client_id) {
- SILC_LOG_DEBUG(("Received invalid client ID notification, deleting "
- "the entry from cache"));
- client = silc_idlist_find_client_by_id(server->global_list,
- client_id, FALSE, NULL);
- if (client) {
- silc_server_remove_from_channels(server, NULL, client, TRUE,
- NULL, TRUE);
- silc_idlist_del_client(server->global_list, client);
- }
- silc_free(client_id);
- }
- }
- }
-
+ silc_server_command_process_error(cmd, error);
SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
silc_server_command_reply_free(cmd);
+ return;
+
+ err:
+ silc_server_command_process_error(cmd, error);
+ silc_server_command_reply_free(cmd);
}
/* Caches the received WHOWAS information for a short period of time. */
out:
SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
+ err:
silc_server_command_reply_free(cmd);
}
SILC_SERVER_CMD_REPLY_FUNC(identify)
{
SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
- SilcServer server = cmd->server;
SilcStatus status, error;
COMMAND_CHECK_STATUS;
}
out:
- /* If we received notify for invalid ID we'll remove the ID if we
- have it cached. */
- if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID &&
- cmd->sock->type == SILC_SOCKET_TYPE_ROUTER) {
- SilcClientEntry client;
- SilcUInt32 tmp_len;
- unsigned char *tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
- if (tmp) {
- SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
- if (client_id) {
- SILC_LOG_DEBUG(("Received invalid client ID notification, deleting "
- "the entry from cache"));
- client = silc_idlist_find_client_by_id(server->global_list,
- client_id, FALSE, NULL);
- if (client) {
- silc_server_remove_from_channels(server, NULL, client, TRUE,
- NULL, TRUE);
- silc_idlist_del_client(server->global_list, client);
- }
- silc_free(client_id);
- }
- }
- }
-
+ silc_server_command_process_error(cmd, error);
SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
silc_server_command_reply_free(cmd);
+ return;
+
+ err:
+ silc_server_command_process_error(cmd, error);
+ silc_server_command_reply_free(cmd);
}
/* Received reply fro INFO command. Cache the server and its information */
out:
SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
+ err:
silc_server_command_reply_free(cmd);
}
out:
SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
+ err:
silc_server_command_reply_free(cmd);
if (entry)
out:
SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
+ err:
silc_free(client_id);
silc_server_command_reply_free(cmd);
out:
SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_STATS);
+ err:
+ silc_server_command_reply_free(cmd);
}
SILC_SERVER_CMD_REPLY_FUNC(users)
out:
SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
silc_free(channel_id);
+ err:
silc_server_command_reply_free(cmd);
}
silc_free(server_id);
if (public_key)
silc_pkcs_public_key_free(public_key);
+ err:
silc_server_command_reply_free(cmd);
}
out:
SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
silc_free(channel_id);
+ err:
silc_server_command_reply_free(cmd);
}
out:
SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WATCH);
+ err:
silc_server_command_reply_free(cmd);
}
unsigned char *id_string, *auth = NULL;
SilcUInt16 id_len, auth_len = 0;
int ret, nickfail = 0;
- bool resolved, local, nick_change = FALSE;
+ bool resolved, local, nick_change = FALSE, resolve = FALSE;
SilcChannelEntry channel;
SilcHashTableList htl;
SilcChannelClientEntry chl;
return;
}
- /* Check that the client is detached, and that we have other info too */
- if (!(detached_client->mode & SILC_UMODE_DETACHED) ||
- !silc_hash_table_count(detached_client->channels) ||
- !detached_client->nickname) {
+ if (!(detached_client->mode & SILC_UMODE_DETACHED))
+ resolve = TRUE;
+ if (!silc_hash_table_count(detached_client->channels) &&
+ detached_client->router)
+ resolve = TRUE;
+ if (!detached_client->nickname)
+ resolve = TRUE;
+
+ if (resolve) {
if (server->server_type == SILC_SERVER && !server->standalone) {
/* The client info is being resolved. Reprocess this packet after
receiving the reply to the query. */
/* Check that we have the public key of the client, if not then we must
resolve it first. */
if (!detached_client->data.public_key) {
- if (server->standalone) {
+ if (server->server_type == SILC_SERVER && server->standalone) {
silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
"Resuming not possible");
idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
server->cmd_ident, 1,
- 3, idp->data, idp->len);
+ 4, idp->data, idp->len);
silc_server_packet_send(server, client ? client->router->connection :
server->router->connection,
SILC_PACKET_COMMAND, 0,
if (packet->len > 1 &&
silc_utf8_valid(packet->data + 1, packet->len - 1))
- message = silc_memdup(packet->data, packet->len);
+ message = silc_memdup(packet->data + 1, packet->len - 1);
client->internal->ops->say(client, sock->user_data,
SILC_CLIENT_MESSAGE_AUDIT,
silc_free(session->hostname);
silc_free(session->filepath);
+ silc_free(session->path);
silc_free(session);
}
silc_hash_table_del(channel->user_list, client_entry);
silc_free(chu);
}
+
+ if (!silc_hash_table_count(client_entry->channels)) {
+ SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
+ res->context = client;
+ res->sock = silc_socket_dup(conn->sock);
+ res->packet = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
+ silc_schedule_task_add(client->schedule, 0,
+ silc_client_notify_check_client, res,
+ (5 + (silc_rng_get_rn16(client->rng) % 529)),
+ 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+ }
}
break;
SilcClientResumeSession session = context;
int i;
- session->callback(session->client, session->conn, session->success,
- session->context);
-
for (i = 0; i < session->cmd_idents_count; i++)
silc_client_command_pending_del(session->conn, SILC_COMMAND_IDENTIFY,
session->cmd_idents[i]);
silc_free(session->cmd_idents);
+ session->callback(session->client, session->conn, session->success,
+ session->context);
+
memset(session, 'F', sizeof(*session));
silc_free(session);
}
{
SilcClientCommandPending *r;
+ if (!conn->pending_commands)
+ return;
+
silc_dlist_start(conn->pending_commands);
while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
if (r->reply_cmd == reply_cmd && r->ident == ident) {
#define SAY cmd->client->internal->ops->say
/* All functions that call the COMMAND_CHECK_STATUS macro must have
- out: goto label. */
+ out: and err: goto labels. out label should call the pending
+ command replies, and the err label just handle error condition. */
#define COMMAND_CHECK_STATUS \
do { \
SILC_LOG_DEBUG(("Start")); \
if (!silc_command_get_status(cmd->payload, NULL, NULL)) { \
+ if (SILC_STATUS_IS_ERROR(cmd->status)) { \
+ /* Single error */ \
+ COMMAND_REPLY_ERROR; \
+ goto out; \
+ } \
+ /* List of errors */ \
COMMAND_REPLY_ERROR; \
- goto out; \
+ if (cmd->status == SILC_STATUS_LIST_END) \
+ goto out; \
+ goto err; \
+ } \
+} while(0)
+
+/* Same as COMMAND_CHECK_STATUS but doesn't call client operation */
+#define COMMAND_CHECK_STATUS_I \
+do { \
+ SILC_LOG_DEBUG(("Start")); \
+ if (!silc_command_get_status(cmd->payload, NULL, NULL)) { \
+ if (SILC_STATUS_IS_ERROR(cmd->status)) \
+ goto out; \
+ if (cmd->status == SILC_STATUS_LIST_END) \
+ goto out; \
+ goto err; \
} \
} while(0)
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
+ err:
/* If we received notify for invalid ID we'll remove the ID if we
have it cached. */
if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
+ err:
silc_client_command_reply_free(cmd);
}
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
+ err:
/* If we received notify for invalid ID we'll remove the ID if we
have it cached. */
if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
out:
silc_free(channel_id);
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
+ err:
silc_client_command_reply_free(cmd);
}
(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 + 3;
+ res_argv_types[res_argc] = res_argc + 4;
res_argc++;
} else {
if (!silc_client_on_channel(channel, client_entry)) {
SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
- SILC_LOG_DEBUG(("Start"));
-
- if (cmd->error != SILC_STATUS_OK)
- goto out;
+ COMMAND_CHECK_STATUS_I;
/* Save WHOIS info */
silc_client_command_reply_whois_save(cmd, cmd->status, FALSE);
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
+ err:
/* If we received notify for invalid ID we'll remove the ID if we
have it cached. */
if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
- SILC_LOG_DEBUG(("Start"));
-
- if (cmd->error != SILC_STATUS_OK)
- goto out;
+ COMMAND_CHECK_STATUS_I;
/* Save IDENTIFY info */
silc_client_command_reply_identify_save(cmd, cmd->status, FALSE);
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
+ err:
/* If we received notify for invalid ID we'll remove the ID if we
have it cached. */
if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
char *server_name, *server_info;
SilcUInt32 len;
- SILC_LOG_DEBUG(("Start"));
-
- if (cmd->error != SILC_STATUS_OK)
- goto out;
+ COMMAND_CHECK_STATUS_I;
/* Get server ID */
tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
silc_free(server_id);
+ err:
silc_client_command_reply_free(cmd);
}
{
SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
- SILC_LOG_DEBUG(("Start"));
-
- if (cmd->error != SILC_STATUS_OK)
- goto out;
+ COMMAND_CHECK_STATUS_I;
/* Save USERS info */
if (silc_client_command_reply_users_save(
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
+ err:
/* Unregister this command reply */
silc_client_command_unregister(cmd->client, SILC_COMMAND_USERS,
NULL, silc_client_command_reply_users_i,
/* Send the command */
idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
silc_client_command_send(client, conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
- 1, 3, idp->data, idp->len);
+ 1, 4, idp->data, idp->len);
silc_buffer_free(idp);
/* Add pending callback */
/* We received the REKEY_DONE packet and all packets after this is
encrypted with the new key so set the decryption key to the new key */
- silc_client_protocol_rekey_generate(client, ctx, FALSE);
+ if (ctx->pfs == TRUE)
+ silc_client_protocol_rekey_generate_pfs(client, ctx, FALSE);
+ else
+ silc_client_protocol_rekey_generate(client, ctx, FALSE);
/* Protocol has ended, call the final callback */
if (protocol->final_callback)
#define SILC_STATUS_ERR_BAD_VERSION 53
/***/
+#define SILC_STATUS_IS_ERROR(status) (status >= SILC_STATUS_ERR_NO_SUCH_NICK)
+
#endif /* SILCSTATUS_H */