Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2002 Pekka Riikonen
+ Copyright (C) 2002, 2003 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
SILC_CLIENT_CMD_FUNC(resume_cmode);
SILC_CLIENT_CMD_FUNC(resume_users);
+#define RESUME_CALL_COMPLETION(client, session, s) \
+do { \
+ SILC_LOG_DEBUG(("Calling completion")); \
+ session->success = s; \
+ silc_schedule_task_add(client->schedule, 0, \
+ silc_client_resume_call_completion, session, \
+ 0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW); \
+} while(0)
+
/* Generates the session detachment data. This data can be used later
to resume back to the server. */
/* Processes the detachment data. This creates channels and other
stuff according the data found in the the connection parameters.
This doesn't actually resolve any detailed information from the
- server. To do that call silc_client_resume_session function.
+ server. To do that call silc_client_resume_session function.
This returns the old detached session client ID. */
bool silc_client_process_detach_data(SilcClient client,
SILC_LOG_DEBUG(("Start"));
silc_free(conn->nickname);
- silc_buffer_set(&detach, conn->params.detach_data,
- conn->params.detach_data_len);
+ silc_buffer_set(&detach, conn->internal->params.detach_data,
+ conn->internal->params.detach_data_len);
SILC_LOG_HEXDUMP(("Detach data"), detach.data, detach.len);
/* Take the old client ID from the detachment data */
len = silc_buffer_unformat(&detach,
- SILC_STR_UI16_NSTRING_ALLOC(&conn->nickname,
+ SILC_STR_UI16_NSTRING_ALLOC(&conn->nickname,
NULL),
SILC_STR_UI16_NSTRING_ALLOC(old_id, old_id_len),
SILC_STR_UI_INT(NULL),
return TRUE;
}
-/* Generic command reply callback */
-
-SILC_CLIENT_CMD_REPLY_FUNC(resume)
-{
- SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
-
- SILC_LOG_DEBUG(("Start"));
-
- if (cmd->callback)
- (*cmd->callback)(cmd->context, cmd);
-}
/* Resume session context */
typedef struct {
SilcClientResumeSessionCallback callback;
void *context;
SilcUInt32 channel_count;
+ SilcUInt32 *cmd_idents;
+ SilcUInt32 cmd_idents_count;
+ bool success;
} *SilcClientResumeSession;
+/* Generic command reply callback. */
+
+SILC_CLIENT_CMD_REPLY_FUNC(resume)
+{
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SILC_LOG_DEBUG(("Start"));
+ SILC_CLIENT_PENDING_EXEC(cmd, silc_command_get(cmd->payload));
+}
+
+/* Special command reply callback for IDENTIFY callbacks. This calls
+ the pending callback for every returned command entry. */
+
+SILC_CLIENT_CMD_REPLY_FUNC(resume_special)
+{
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ int i;
+
+ SILC_LOG_DEBUG(("Start"));
+ for (i = 0; i < cmd->callbacks_count; i++)
+ if (cmd->callbacks[i].callback)
+ (*cmd->callbacks[i].callback)(cmd->callbacks[i].context, cmd);
+}
+
+/* Completion calling callback */
+
+SILC_TASK_CALLBACK(silc_client_resume_call_completion)
+{
+ SilcClientResumeSession session = context;
+ int i;
+
+ SILC_LOG_DEBUG(("Session completed"));
+
+ 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);
+}
+
/* This function is used to perform the resuming procedure after the
client has connected to the server properly and has received the
Client ID for the resumed session. This resolves all channels
/* Second, send IDENTIFY command of all channels we know about. These
are the channels we've joined to according our detachment data. */
- if (silc_idcache_get_all(conn->channel_cache, &list)) {
+ if (silc_idcache_get_all(conn->internal->channel_cache, &list)) {
unsigned char **res_argv = NULL;
SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
/* Send the IDENTIFY command */
SILC_LOG_DEBUG(("Sending IDENTIFY"));
silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
- silc_client_command_reply_resume,
+ silc_client_command_reply_resume_special,
0, ++conn->cmd_ident);
- tmp = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
- res_argc, res_argv, res_argv_lens,
- res_argv_types, conn->cmd_ident);
- silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
+ silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
conn->cmd_ident,
silc_client_command_resume_identify,
session);
- silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
+
+ tmp = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
+ res_argc, res_argv, res_argv_lens,
+ res_argv_types, conn->cmd_ident);
+ silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
NULL, 0, NULL, NULL, tmp->data, tmp->len, TRUE);
+ session->cmd_idents = silc_realloc(session->cmd_idents,
+ sizeof(*session->cmd_idents) *
+ (session->cmd_idents_count + 1));
+ session->cmd_idents[session->cmd_idents_count] = conn->cmd_ident;
+ session->cmd_idents_count++;
+
for (i = 0; i < res_argc; i++)
silc_free(res_argv[i]);
silc_free(res_argv);
}
}
+ if (!session->channel_count)
+ RESUME_CALL_COMPLETION(client, session, TRUE);
+
/* Now, we wait for replies to come back and then continue with USERS,
CMODE and TOPIC commands. */
}
return;
/* Unregister this command reply */
- silc_client_command_unregister(client, SILC_COMMAND_IDENTIFY, NULL,
+ silc_client_command_unregister(client, SILC_COMMAND_IDENTIFY, NULL,
silc_client_command_reply_resume,
cmd->ident);
return;
err:
session->channel_count--;
if (!session->channel_count)
- session->callback(session->client, session->conn, FALSE,
- session->context);
+ RESUME_CALL_COMPLETION(client, session, FALSE);
}
/* Received cmode to channel entry */
SILC_LOG_DEBUG(("Start"));
/* Unregister this command reply */
- silc_client_command_unregister(client, SILC_COMMAND_CMODE, NULL,
+ silc_client_command_unregister(client, SILC_COMMAND_CMODE, NULL,
silc_client_command_reply_resume,
cmd->ident);
err:
session->channel_count--;
if (!session->channel_count)
- session->callback(session->client, session->conn, FALSE,
- session->context);
+ RESUME_CALL_COMPLETION(client, session, FALSE);
}
/* Received users reply to a channel entry */
SILC_LOG_DEBUG(("Start"));
/* Unregister this command reply */
- silc_client_command_unregister(client, SILC_COMMAND_USERS, NULL,
+ silc_client_command_unregister(client, SILC_COMMAND_USERS, NULL,
silc_client_command_reply_users_i,
cmd->ident);
/* 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 err;
}
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 err;
}
/* 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 err;
}
SILC_GET32_MSB(list_count, tmp);
/* 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 err;
}
silc_buffer_set(&client_id_list, tmp, tmp_len);
/* 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 err;
}
silc_buffer_set(&client_mode_list, tmp, tmp_len);
client->internal->ops->command_reply(client, conn, cmd->payload, TRUE,
SILC_COMMAND_JOIN, cmd->status,
channel->channel_name, channel,
- channel->mode, 0,
- NULL, NULL, NULL, NULL,
+ channel->mode, 0,
+ NULL, NULL, NULL, NULL,
channel->hmac, list_count,
&client_id_list, client_mode_list);
SILC_LOG_DEBUG(("Sending TOPIC"));
tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
silc_client_command_send(client, conn, SILC_COMMAND_TOPIC,
- conn->cmd_ident, 1, 1, tmp, tmp_len);
+ ++conn->cmd_ident, 1, 1, tmp, tmp_len);
/* Call the completion callback after we've got reply to all of
our channels */
session->channel_count--;
if (!session->channel_count)
- session->callback(session->client, session->conn, TRUE,
- session->context);
+ RESUME_CALL_COMPLETION(client, session, TRUE);
silc_free(channel_id);
return;
silc_free(channel_id);
session->channel_count--;
if (!session->channel_count)
- session->callback(session->client, session->conn, FALSE,
- session->context);
+ RESUME_CALL_COMPLETION(client, session, FALSE);
}