Merged silc_1_0_branch to trunk.
[silc.git] / lib / silcclient / client_resume.c
index 0d0d24ba7b19b4f393ec48b2d04d556617098a9e..3efe64ad2c2c6b59d6df4685ee27aa1bd7b91cac 100644 (file)
@@ -4,7 +4,7 @@
 
   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
@@ -27,6 +27,15 @@ SILC_CLIENT_CMD_FUNC(resume_identify);
 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. */
 
@@ -90,7 +99,7 @@ SilcBuffer silc_client_get_detach_data(SilcClient client,
 /* 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,
@@ -105,14 +114,14 @@ 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),
@@ -157,17 +166,6 @@ bool silc_client_process_detach_data(SilcClient client,
   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 {
@@ -176,8 +174,55 @@ 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
@@ -219,7 +264,7 @@ void silc_client_resume_session(SilcClient client,
 
   /* 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;
 
@@ -247,18 +292,25 @@ void silc_client_resume_session(SilcClient client,
       /* 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);
@@ -268,6 +320,9 @@ void silc_client_resume_session(SilcClient client,
     }
   }
 
+  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. */
 }
@@ -347,7 +402,7 @@ SILC_CLIENT_CMD_FUNC(resume_identify)
     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;
@@ -355,8 +410,7 @@ SILC_CLIENT_CMD_FUNC(resume_identify)
  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 */
@@ -375,7 +429,7 @@ SILC_CLIENT_CMD_FUNC(resume_cmode)
   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);
 
@@ -418,8 +472,7 @@ SILC_CLIENT_CMD_FUNC(resume_cmode)
  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 */
@@ -439,7 +492,7 @@ SILC_CLIENT_CMD_FUNC(resume_users)
   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);
 
@@ -449,19 +502,19 @@ SILC_CLIENT_CMD_FUNC(resume_users)
   /* 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);
@@ -469,7 +522,7 @@ SILC_CLIENT_CMD_FUNC(resume_users)
   /* 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);
@@ -477,7 +530,7 @@ SILC_CLIENT_CMD_FUNC(resume_users)
   /* 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);
@@ -491,8 +544,8 @@ SILC_CLIENT_CMD_FUNC(resume_users)
   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);
 
@@ -500,14 +553,13 @@ SILC_CLIENT_CMD_FUNC(resume_users)
   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;
@@ -516,6 +568,5 @@ SILC_CLIENT_CMD_FUNC(resume_users)
   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);
 }