Added SILC Server library.
[silc.git] / lib / silcclient / client_resume.c
index b0e08ed65031d5ea97cafa7a64ca86e49c7f356a..5b984234c7f4fe48bfe60bbaf595612ce57765a9 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2002 Pekka Riikonen
+  Copyright (C) 2002, 2004 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
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcclient.h"
 #include "client_internal.h"
 
@@ -29,6 +29,7 @@ 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,   \
@@ -66,7 +67,7 @@ SilcBuffer silc_client_get_detach_data(SilcClient client,
 
   /* Save all joined channels */
   silc_hash_table_list(conn->local_entry->channels, &htl);
-  while (silc_hash_table_get(&htl, NULL, (void **)&chu)) {
+  while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
     unsigned char *chid = silc_id_id2str(chu->channel->id, SILC_ID_CHANNEL);
     SilcUInt16 chid_len = silc_id_get_len(chu->channel->id, SILC_ID_CHANNEL);
 
@@ -98,10 +99,10 @@ 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,
+SilcBool silc_client_process_detach_data(SilcClient client,
                                     SilcClientConnection conn,
                                     unsigned char **old_id,
                                     SilcUInt16 *old_id_len)
@@ -109,18 +110,21 @@ bool silc_client_process_detach_data(SilcClient client,
   SilcBufferStruct detach;
   SilcUInt32 ch_count;
   int i, len;
+  char *newnick;
 
   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);
 
+  *old_id = NULL;
+  *old_id_len = 0;
+
   /* 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(&newnick,
                                                         NULL),
                             SILC_STR_UI16_NSTRING_ALLOC(old_id, old_id_len),
                             SILC_STR_UI_INT(NULL),
@@ -128,6 +132,11 @@ bool silc_client_process_detach_data(SilcClient client,
                             SILC_STR_END);
   if (len == -1)
     return FALSE;
+  if (!newnick || !(*old_id) || !(*old_id_len))
+    return FALSE;
+
+  silc_free(conn->nickname);
+  conn->nickname = newnick;
 
   silc_buffer_pull(&detach, len);
 
@@ -173,19 +182,32 @@ typedef struct {
   SilcClientResumeSessionCallback callback;
   void *context;
   SilcUInt32 channel_count;
-  bool success;
+  SilcUInt32 *cmd_idents;
+  SilcUInt32 cmd_idents_count;
+  SilcBool success;
 } *SilcClientResumeSession;
 
-/* Generic command reply callback */
+/* 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. */
 
-  if (cmd->callback)
-    (*cmd->callback)(cmd->context, cmd);
+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 */
@@ -193,8 +215,20 @@ SILC_CLIENT_CMD_REPLY_FUNC(resume)
 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
@@ -215,7 +249,7 @@ void silc_client_resume_session(SilcClient client,
   SilcChannelEntry channel;
   SilcBuffer tmp;
   int i;
-  bool ret;
+  SilcBool ret;
 
   SILC_LOG_DEBUG(("Resuming detached session"));
 
@@ -238,7 +272,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;
 
@@ -266,18 +300,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);
@@ -287,6 +328,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. */
 }
@@ -366,7 +410,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;
@@ -393,7 +437,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);
 
@@ -456,7 +500,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);
 
@@ -466,19 +510,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);
@@ -486,7 +530,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);
@@ -494,7 +538,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);
@@ -508,8 +552,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);
 
@@ -517,7 +561,7 @@ 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 */