updates.
[silc.git] / lib / silcclient / command_reply.c
index 35a7e87c261aca18f7401924ae632cc1a213fc62..10ca6f960fa3b9f3e1d98fd7a2e543480ef5a6dd 100644 (file)
 #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)
 
@@ -74,6 +96,7 @@ void silc_client_command_reply_process(SilcClient client,
   /* Allocate command reply context. This must be free'd by the
      command reply routine receiving it. */
   ctx = silc_calloc(1, sizeof(*ctx));
+  ctx->users++;
   ctx->client = client;
   ctx->sock = sock;
   ctx->payload = payload;
@@ -112,11 +135,26 @@ 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 
+silc_client_command_reply_dup(SilcClientCommandReplyContext cmd)
+{
+  cmd->users++;
+  SILC_LOG_DEBUG(("Command reply context %p refcnt %d->%d", cmd, 
+                 cmd->users - 1, cmd->users));
+  return cmd;
+}
+
 /* Free command reply context and its internals. */
 
 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
 {
-  if (cmd) {
+  cmd->users--;
+  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);
     silc_free(cmd);
   }
@@ -203,8 +241,7 @@ silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
     client_entry->fingerprint_len = fingerprint_len;
   }
 
-  if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
-    client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
+  client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
 
   /* Notify application */
   if (!cmd->callbacks_count && notify)
@@ -236,6 +273,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(whois)
  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) {
@@ -312,6 +350,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(whowas)
 
  out:
   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
+ err:
   silc_client_command_reply_free(cmd);
 }
 
@@ -370,8 +409,7 @@ silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
                                name, info, NULL, 0);
     }
 
-    if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
-      client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
+    client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
 
     /* Notify application */
     if (notify)
@@ -454,6 +492,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(identify)
  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) {
@@ -499,7 +538,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(nick)
   }
 
   argc = silc_argument_get_arg_num(cmd->args);
-  if (argc < 2 || argc > 2) {
+  if (argc < 2 || argc > 3) {
     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
        "Cannot set nickname: bad reply to command");
     COMMAND_REPLY_ERROR;
@@ -599,6 +638,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(list)
  out:
   silc_free(channel_id);
   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
+ err:
   silc_client_command_reply_free(cmd);
 }
 
@@ -865,7 +905,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(join)
   }
 
   argc = silc_argument_get_arg_num(cmd->args);
-  if (argc < 7 || argc > 14) {
+  if (argc < 7 || argc > 15) {
     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
        "Cannot join channel: Bad reply packet");
     COMMAND_REPLY_ERROR;
@@ -1568,22 +1608,6 @@ 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) {
-      if (client_entry) {
-       if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
-         /* Attach to this resolving and wait until it finishes */
-         silc_client_command_pending(conn, SILC_COMMAND_NONE, 
-                                     client_entry->resolve_cmd_ident,
-                                     get_clients, cmd);
-         wait_res = TRUE;
-
-         silc_buffer_pull(&client_id_list, idp_len);
-         silc_buffer_pull(&client_mode_list, 4);
-         continue;
-       }
-       client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
-       client_entry->resolve_cmd_ident = conn->cmd_ident + 1;
-      }
-
       /* 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. */
@@ -1595,7 +1619,7 @@ silc_client_command_reply_users_save(SilcClientCommandReplyContext 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)) {
@@ -1793,10 +1817,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
   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);
@@ -1811,6 +1832,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
  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) {
@@ -1844,10 +1866,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
   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);
@@ -1862,6 +1881,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
  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) {
@@ -1900,10 +1920,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(info_i)
   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);
@@ -1935,6 +1952,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(info_i)
  out:
   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
   silc_free(server_id);
+ err:
   silc_client_command_reply_free(cmd);
 }
 
@@ -1964,10 +1982,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(users_i)
 {
   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(
@@ -1979,6 +1994,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(users_i)
  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,