updates.
authorPekka Riikonen <priikone@silcnet.org>
Fri, 12 Apr 2002 18:24:46 +0000 (18:24 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Fri, 12 Apr 2002 18:24:46 +0000 (18:24 +0000)
13 files changed:
CHANGES
apps/irssi/src/silc/core/client_ops.c
apps/irssi/src/silc/core/silc-servers.c
apps/silcd/packet_receive.c
lib/silcclient/client_notify.c
lib/silcclient/client_prvmsg.c
lib/silcclient/client_resume.c
lib/silcclient/command.c
lib/silcclient/command.h
lib/silcclient/command_reply.c
lib/silcclient/command_reply.h
lib/silcclient/idlist.c
lib/silcclient/idlist.h

diff --git a/CHANGES b/CHANGES
index dcb48950c76eaa1d1d700a52cfa76defd6a9ccba..089a3c93384d5dbef6efb2616e8c637d552091b2 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,13 @@
+Fri Apr 12 20:09:08 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
+
+         Added resolve_cmd_ident field to the SilcClientEntry structure
+         too so that if the entry is for example being resolved so 
+         another command may attach to the same pending command reply
+         without requiring to resolve the same entry again.  Added
+          support for adding multiple pending commands for one
+         command idenfier.  Affected files lib/silcclient/command.[ch],
+         lib/silcclient/command_reply.[ch], lib/silcclient/idlist.h.
+
 Fri Apr 12 10:17:51 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
 
        * Defined that server receives WHOIS command reply for private
index 6bbf81a555d7a98c0f57b055cefad95577af90d4..5a5ee7b54ca127dfeadd24424f798b4a1bac6665 100644 (file)
@@ -633,7 +633,7 @@ void silc_connect(SilcClient client, SilcClientConnection conn,
 {
   SILC_SERVER_REC *server = conn->context;
 
-  if (!server || status == SILC_CLIENT_CONN_ERROR) {
+  if (!server) {
     silc_client_close_connection(client, conn);
     return;
   }
@@ -749,6 +749,9 @@ static void silc_client_join_get_users(SilcClient client,
   SilcClientEntry founder = NULL;
   NICK_REC *ownnick;
 
+  SILC_LOG_DEBUG(("Start, channel %s, %d users", channel->channel_name,
+                 silc_hash_table_count(channel->user_list)));
+
   if (!clients)
     return;
 
index 841b8411f23f7ad4408e62e6200e474273b44ebc..835e20bc579345fdb42603f05ccc69eec238a2f4 100644 (file)
@@ -41,6 +41,8 @@
 #include "window-item-def.h"
 
 #include "fe-common/core/printtext.h"
+#include "fe-common/core/fe-channels.h"
+#include "fe-common/core/keyboard.h"
 #include "fe-common/silc/module-formats.h"
 
 #include "silc-commands.h"
@@ -214,6 +216,11 @@ static void sig_connected(SILC_SERVER_REC *server)
                                    server);
   server->conn = conn;
 
+  if (params.detach_data)
+    keyboard_entry_redirect(NULL,
+                           "-- Resuming old session, may take a while ...",
+                           ENTRY_REDIRECT_FLAG_HIDDEN, server);
+
   silc_free(params.detach_data);
   unlink(file);
 
index 42085c6f54386e543886cd501b15246d3b1cf374..afdc1a622ecb6bb0111bf3adb6dd6ada4be16ba5 100644 (file)
@@ -3059,7 +3059,8 @@ void silc_server_resume_client(SilcServer server,
 
     /* As router we must deliver this packet directly to the original
        server whom this client was earlier. */
-    if (server->server_type == SILC_ROUTER && detached_client->router)
+    if (server->server_type == SILC_ROUTER && detached_client->router &&
+       detached_client->router->server_type != SILC_ROUTER)
       silc_server_packet_send(server, detached_client->router->connection,
                              SILC_PACKET_RESUME_CLIENT, 0, 
                              buf->data, buf->len, TRUE);
@@ -3253,6 +3254,11 @@ void silc_server_resume_client(SilcServer server,
       }
     }
 
+    if (server->server_type == SILC_ROUTER &&
+       sock->type == SILC_SOCKET_TYPE_ROUTER && 
+       server_entry->server_type == SILC_ROUTER)
+      local = FALSE;
+
     SILC_LOG_DEBUG(("Resuming detached client"));
 
     /* Change the client to correct list. */
index 7a48419f04a6f1a7e18ab4b85433815cb8e9f219..c13030695bb6c2544828ff63cf2bfb0f946c775f 100644 (file)
@@ -223,9 +223,10 @@ void silc_client_notify_by_server(SilcClient client,
        client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
        goto out;
       }
-      client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
       silc_client_notify_by_server_resolve(client, conn, packet, 
                                           SILC_ID_CLIENT, client_id);
+      client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
+      client_entry->resolve_cmd_ident = conn->cmd_ident;
       goto out;
     } else {
       if (client_entry != conn->local_entry)
index a6e09917b0853f1f4e2183fb2c713a10f59e2645..439fe0e32d3853877fa8b3346b41dec2cf3598e8 100644 (file)
@@ -168,6 +168,7 @@ void silc_client_private_message(SilcClient client,
        goto out;
       }
       remote_client->status |= SILC_CLIENT_STATUS_RESOLVING;
+      remote_client->resolve_cmd_ident = conn->cmd_ident + 1;
     }
 
     /* Resolve the client info */
index b0e08ed65031d5ea97cafa7a64ca86e49c7f356a..d3fd7a9dd9f5260f5bc25ac40ca328b4b0b47c70 100644 (file)
@@ -173,19 +173,32 @@ typedef struct {
   SilcClientResumeSessionCallback callback;
   void *context;
   SilcUInt32 channel_count;
+  SilcUInt32 *cmd_idents;
+  SilcUInt32 cmd_idents_count;
   bool 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. */
+
+SILC_CLIENT_CMD_REPLY_FUNC(resume_special)
+{
+  SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+  int i;
 
-  if (cmd->callback)
-    (*cmd->callback)(cmd->context, cmd);
+  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 +206,18 @@ SILC_CLIENT_CMD_REPLY_FUNC(resume)
 SILC_TASK_CALLBACK(silc_client_resume_call_completion)
 {
   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);
+
+  memset(session, 'F', sizeof(*session));
+  silc_free(session);
 }
 
 /* This function is used to perform the resuming procedure after the
@@ -266,18 +289,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, 
                                  conn->cmd_ident,
                                  silc_client_command_resume_identify,
                                  session);
+
+      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);
@@ -517,7 +547,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 */
index f04e4510aaff84f3c8d490c76b0bb5cbe4bf70df..1e829efa368a0ae4b9b700d873ef7d936f854856 100644 (file)
@@ -86,10 +86,13 @@ void silc_client_command_call(SilcClientCommand command,
 }
 
 /* Add new pending command to be executed when reply to a command has been
-   received.  The `reply_cmd' is the command that will call the `callback'
-   with `context' when reply has been received.  If `ident is non-zero
-   the `callback' will be executed when received reply with command 
-   identifier `ident'. */
+   received. The `reply_cmd' is the command that will call the `callback'
+   with `context' when reply has been received.  It can be SILC_COMMAND_NONE
+   to match any command with the `ident'.  If `ident' is non-zero
+   the `callback' will be executed when received reply with command
+   identifier `ident'. If there already exists pending command for the
+   specified command, ident, callback and context this function has no
+   effect. */
 
 void silc_client_command_pending(SilcClientConnection conn,
                                 SilcCommand reply_cmd,
@@ -99,6 +102,16 @@ void silc_client_command_pending(SilcClientConnection conn,
 {
   SilcClientCommandPending *reply;
 
+  /* Check whether identical pending already exists for same command,
+     ident, callback and callback context. If it does then it would be
+     error to register it again. */
+  silc_dlist_start(conn->pending_commands);
+  while ((reply = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
+    if (reply->reply_cmd == reply_cmd && reply->ident == ident &&
+       reply->callback == callback && reply->context == context)
+      return;
+  }
+
   reply = silc_calloc(1, sizeof(*reply));
   reply->reply_cmd = reply_cmd;
   reply->ident = ident;
@@ -125,26 +138,33 @@ void silc_client_command_pending_del(SilcClientConnection conn,
 }
 
 /* Checks for pending commands and marks callbacks to be called from
-   the command reply function. Returns TRUE if there were pending command. */
-
-int silc_client_command_pending_check(SilcClientConnection conn,
-                                     SilcClientCommandReplyContext ctx,
-                                     SilcCommand command, 
-                                     SilcUInt16 ident)
+   the command reply function. */
+
+SilcClientCommandPendingCallbacks
+silc_client_command_pending_check(SilcClientConnection conn,
+                                 SilcClientCommandReplyContext ctx,
+                                 SilcCommand command, 
+                                 SilcUInt16 ident,
+                                 SilcUInt32 *callbacks_count)
 {
   SilcClientCommandPending *r;
+  SilcClientCommandPendingCallbacks callbacks = NULL;
+  int i = 0;
 
   silc_dlist_start(conn->pending_commands);
   while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) {
-    if (r->reply_cmd == command && r->ident == ident) {
-      ctx->context = r->context;
-      ctx->callback = r->callback;
+    if ((r->reply_cmd == command || r->reply_cmd == SILC_COMMAND_NONE)
+       && r->ident == ident) {
+      callbacks = silc_realloc(callbacks, sizeof(*callbacks) * (i + 1));
+      callbacks[i].context = r->context;
+      callbacks[i].callback = r->callback;
       ctx->ident = ident;
-      return TRUE;
+      i++;
     }
   }
 
-  return FALSE;
+  *callbacks_count = i;
+  return callbacks;
 }
 
 /* Allocate Command Context */
index 33479ec86062e51c6f3ec9237548ed2e4cc6c0a9..46fb36509bc830781800e32bae61be9ad425e17f 100644 (file)
@@ -87,12 +87,13 @@ silc_client_command_unregister(client, SILC_COMMAND_##cmd,          \
 void silc_client_command_##func(void *context, void *context2)
 
 /* Executed pending command callback */
-#define SILC_CLIENT_PENDING_EXEC(ctx, cmd)                             \
-do {                                                                   \
-  if ((ctx)->callback)                                                 \
-    (*ctx->callback)(ctx->context, ctx);                               \
-  silc_client_command_pending_del((ctx)->sock->user_data, (cmd),       \
-                                 (ctx)->ident);                        \
+#define SILC_CLIENT_PENDING_EXEC(ctx, cmd)                               \
+do {                                                                     \
+  int _i;                                                                \
+  for (_i = 0; _i < ctx->callbacks_count; _i++)                                  \
+    if (ctx->callbacks[_i].callback)                                     \
+      (*ctx->callbacks[_i].callback)(ctx->callbacks[_i].context, ctx);   \
+  silc_client_command_pending_del(ctx->sock->user_data, cmd, ctx->ident); \
 } while(0)
 
 bool silc_client_command_register(SilcClient client,
@@ -112,11 +113,12 @@ void silc_client_commands_unregister(SilcClient client);
 void silc_client_command_pending_del(SilcClientConnection conn,
                                     SilcCommand reply_cmd,
                                     SilcUInt16 ident);
-int silc_client_command_pending_check(SilcClientConnection conn,
-                                     SilcClientCommandReplyContext ctx,
-                                     SilcCommand command, 
-                                     SilcUInt16 ident);
-
+SilcClientCommandPendingCallbacks
+silc_client_command_pending_check(SilcClientConnection conn,
+                                 SilcClientCommandReplyContext ctx,
+                                 SilcCommand command, 
+                                 SilcUInt16 ident,
+                                 SilcUInt32 *callbacks_count);
 SILC_CLIENT_CMD_FUNC(whois);
 SILC_CLIENT_CMD_FUNC(whowas);
 SILC_CLIENT_CMD_FUNC(identify);
index 415f6d49b2568d061250ac3eb84c88c1db7a0ddd..424d3ea2cd9ac1e8993f878e71489b63ed3a52f1 100644 (file)
@@ -127,9 +127,10 @@ void silc_client_command_reply_process(SilcClient client,
   silc_command_get_status(ctx->payload, &ctx->status, &ctx->error);
 
   /* Check for pending commands and mark to be exeucted */
-  silc_client_command_pending_check(sock->user_data, ctx, 
-                                   silc_command_get(ctx->payload), 
-                                   ctx->ident);
+  ctx->callbacks =
+    silc_client_command_pending_check(sock->user_data, ctx, 
+                                     silc_command_get(ctx->payload), 
+                                     ctx->ident, &ctx->callbacks_count);
 
   /* Execute command reply */
 
@@ -267,7 +268,7 @@ silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
     client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
 
   /* Notify application */
-  if (!cmd->callback && notify)
+  if (!cmd->callbacks_count && notify)
     COMMAND_REPLY((ARGS, client_entry, nickname, username, realname, 
                   has_channels ? &channels : NULL, mode, idle, 
                   fingerprint, has_user_modes ? &ch_user_modes : NULL));
@@ -1527,6 +1528,7 @@ silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd,
   int i;
   unsigned char **res_argv = NULL;
   SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
+  bool wait_res = FALSE;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -1576,6 +1578,8 @@ silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd,
     return 1;
   }
 
+  SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
+
   /* Cache the received Client ID's and modes. */
   for (i = 0; i < list_count; i++) {
     SilcUInt16 idp_len;
@@ -1597,11 +1601,18 @@ silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd,
     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
@@ -1662,7 +1673,10 @@ silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd,
     silc_free(res_argv_types);
     return 1;
   }
-  
+
+  if (wait_res)
+    return 1;
+
   silc_buffer_push(&client_id_list, (client_id_list.data - 
                                     client_id_list.head));
   silc_buffer_push(&client_mode_list, (client_mode_list.data - 
index 782b0aa244c2f106087641f8deed76ac454b979b..f950447d35f8944fd3c28eeff6e71e47e339c300 100644 (file)
@@ -26,6 +26,12 @@ typedef struct {
   SilcCommand cmd;
 } SilcClientCommandReply;
 
+/* Context holding pending command callbacks. */
+typedef struct {
+  SilcCommandCb callback;
+  void *context;
+} *SilcClientCommandPendingCallbacks;
+
 /* Context sent as argument to all command reply functions */
 struct SilcClientCommandReplyContextStruct {
   SilcClient client;
@@ -37,8 +43,8 @@ struct SilcClientCommandReplyContextStruct {
   SilcPacketContext *packet;
 
   /* If defined this executes the pending command. */
-  SilcCommandCb callback;
-  void *context;
+  SilcClientCommandPendingCallbacks callbacks;
+  SilcUInt32 callbacks_count;
   SilcUInt16 ident;
 };
 
index 9f21b8a5fd06908b6ba18d4d8e021998fdaf6412..2d5a8c0cdb8f2fc780605d6252cdbc32b5a828e1 100644 (file)
@@ -362,6 +362,7 @@ void silc_client_get_clients_by_list(SilcClient client,
   unsigned char **res_argv = NULL;
   SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
   GetClientsByListInternal in;
+  bool wait_res = FALSE;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -402,13 +403,21 @@ void silc_client_get_clients_by_list(SilcClient client,
 
       if (entry) {
        if (entry->status & SILC_CLIENT_STATUS_RESOLVING) {
-         entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
+         /* Attach to this resolving and wait until it finishes */
+         silc_client_command_pending(
+                           conn, SILC_COMMAND_NONE, 
+                           entry->resolve_cmd_ident,
+                           silc_client_command_get_clients_list_callback, 
+                           (void *)in);
+         wait_res = TRUE;
+
          silc_free(client_id);
          silc_buffer_pull(client_id_list, idp_len);
          continue;
        }
 
        entry->status |= SILC_CLIENT_STATUS_RESOLVING;
+       entry->resolve_cmd_ident = conn->cmd_ident + 1;
       }
 
       /* No we don't have it, query it from the server. Assemble argument
@@ -429,6 +438,9 @@ void silc_client_get_clients_by_list(SilcClient client,
     silc_buffer_pull(client_id_list, idp_len);
   }
 
+  silc_buffer_push(client_id_list, client_id_list->data - 
+                  client_id_list->head);
+
   /* Query the client information from server if the list included clients
      that we don't know about. */
   if (res_argc) {
@@ -452,8 +464,6 @@ void silc_client_get_clients_by_list(SilcClient client,
                                silc_client_command_get_clients_list_callback, 
                                (void *)in);
 
-    silc_buffer_push(client_id_list, client_id_list->data - 
-                    client_id_list->head);
     silc_buffer_free(res_cmd);
     silc_free(res_argv);
     silc_free(res_argv_lens);
@@ -461,8 +471,8 @@ void silc_client_get_clients_by_list(SilcClient client,
     return;
   }
 
-  silc_buffer_push(client_id_list, client_id_list->data - 
-                  client_id_list->head);
+  if (wait_res)
+    return;
 
   /* We have the clients in cache, get them and call the completion */
   silc_client_command_get_clients_list_callback((void *)in, NULL);
index 39b4f022d5a0b65d69e73d409d7764e465bef238..3e7eb25306a5a51f55afe9965445ab69c3d46e98 100644 (file)
@@ -40,17 +40,18 @@ struct SilcClientEntryStruct {
   SilcClientID *id;            /* The Client ID */
   unsigned char *fingerprint;  /* Fingerprint of client's public key */
   SilcUInt32 fingerprint_len;  /* Length of the fingerprint */
-  bool valid;                  /* FALSE if this entry is not valid */
   SilcCipher send_key;         /* Private message key for sending */
   SilcCipher receive_key;      /* Private message key for receiving */
-  unsigned char *key;          /* Set only if appliation provided the
-                                  key material. NULL if the library 
-                                  generated the key. */
-  SilcUInt32 key_len;
-  bool generated;              /* TRUE if library generated the key */
   SilcClientKeyAgreement ke;   /* Current key agreement context or NULL */
   SilcClientStatus status;     /* Status mask */
   SilcHashTable channels;      /* All channels client has joined */
+  unsigned char *key;          /* Set only if appliation provided the
+                                  key material. NULL if the library 
+                                  generated the key. */
+  SilcUInt32 key_len;          /* Key length */
+  SilcUInt16 resolve_cmd_ident;        /* Command identifier when resolving */
+  bool generated;              /* TRUE if library generated `key' */
+  bool valid;                  /* FALSE if this entry is not valid */
 };
 
 /* Client and its mode on a channel */