updates.
authorPekka Riikonen <priikone@silcnet.org>
Sun, 9 Sep 2001 20:44:15 +0000 (20:44 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Sun, 9 Sep 2001 20:44:15 +0000 (20:44 +0000)
13 files changed:
CHANGES
TODO
apps/silcd/command.c
apps/silcd/command.h
apps/silcd/command_reply.c
apps/silcd/command_reply.h
apps/silcd/idlist.c
apps/silcd/idlist.h
apps/silcd/packet_receive.c
apps/silcd/server.c
lib/silccore/silcidcache.c
lib/silcutil/silchashtable.c
lib/silcutil/silchashtable.h

diff --git a/CHANGES b/CHANGES
index fbcf9012d36cc1d164cfaa0633bd0fdd0b1f7ef2..307d1f209fd5778134f59ef4a1a52d0a1bcf514d 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,68 @@
+Sun Sep  9 15:49:16 EEST 2001  Pekka Riikonen <priikone@silcnet.org>
+
+       * Added check to the silc_server_new_id_real to not accept
+         new ID if it is the sender's own ID.  Affected file is
+         silcd/packet_receive.c.
+
+       * Assure that we do not announce ourself or the one we've
+         sending our announcements when we're router and are announcing
+         servers to our primary router.  Affected file silcd/server.c.
+
+       * Fixed silc_server_command_identify_check_client to assemble
+         correct WHOIS packet.  It send corrupted WHOIS packet and
+         caused problem with router to router connections.  Affected
+         file silcd/command.c.
+
+         Fixed also silc_server_command_whois_check the same way
+         as for the IDENTIFY command.
+
+       * Added new SilcIDListStatus to the server in the SilcIDListData
+         structure.   The status now includes the current status of
+         the entry (like registered, resolved etc.).  Affected file
+         silcd/idlist.[ch].  Defined a bunch of different status types
+         as well.  This replaced the old boolean registered field as well.
+
+         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.  This concept
+         should optimize the WHOIS and the IDENTIFY resolving under
+         heavy load by taking away unnecessary resolving for entries
+         that are being resolved already.
+
+         Added support for adding multiple pending commands for one
+         command idenfier.  Affected file silcd/command[_reply].[ch].
+
+       * Fixed WHOIS and IDENTIFY save to remove the cache entry
+         before deleting the data.  Otherwise the hash table will have
+         freed data in comparison functions.  Affected file is
+         silcd/command_reply.c.
+
+       * Fixed silc_idlist_replace_client_id to add the new entry to
+         the cache with NULL nickname.  Otherwise there will be invalid
+         memory as the nickname after the nickname is freed.  Affected
+         file silcd/packet_receive.c.
+
+       * Fixed the silc_idlist_get_clients_by_hash.  The entries was
+         saved into wrong slots because the previous number of entries
+         was not taken into account.  Affected file silcd/idlist.c.
+         Fixed same thing in silc_idlist_get_clients_by_nickname too.
+
+       * If we are router and we receive JOIN notify to a channel that
+         does not have any users then notified client is marked as the
+         channel founder, as it is it.  The affected file is
+         silcd/packet_receive.c
+
+       * Added to the extended hash table API's table_del_*ext functions
+         the destructor as argument too, so that the caller can decide
+         which destructor to use or whether to use destructor at all.
+         Affected file lib/silcutil/silchashtable.[ch].
+
+       * Fixed ID Cache purging.  It actually deleted the entries from
+         the hash table after the data was freed.  The hash table ended
+         up comparing freed memory.  The affected file is
+         lib/silccore/silcidcache.c.
+
 Sat Sep  8 10:22:10 EEST 2001  Pekka Riikonen <priikone@silcnet.org>
 
        * Fixed Irssi SILC client's KILL command's HELP syntax.
diff --git a/TODO b/TODO
index 99582e5f87e900b49d4f9fcf767cd20feb932630..78e31ea0f3b0af79d3977e97939802d8f445e84a 100644 (file)
--- a/TODO
+++ b/TODO
@@ -35,6 +35,13 @@ TODO/bugs in Irssi SILC client
 TODO/bugs In SILC Client Library
 ================================
 
+ o Someone changing nickname on the channel from nick to Nick will cause
+   that the new nick becomes Nick@host, because the old nick is not
+   removed from the cache before adding the new one.  This is because
+   of the way NICK_CHANGE notify is handled.  This should be fixed so
+   that if the old nick is to be removed the new nick will *replace*
+   the old one.
+
  o JOIN command's argument handling is buggy.  See the XXX in the code.
 
 
index 1aba7a0c07820575dbda1241457a49dba1e69f2a..d5fe84db3e5fbc6d819df439903eda74d36dac82 100644 (file)
@@ -122,7 +122,7 @@ static int silc_server_is_registered(SilcServer server,
                                     SilcCommand command)
 {
   SilcIDListData idata = (SilcIDListData)sock->user_data;
-  if (idata->registered)
+  if (idata->status & SILC_IDLIST_STATUS_REGISTERED)
     return TRUE;
 
   silc_server_command_send_status_reply(cmd, command,
@@ -289,7 +289,8 @@ silc_server_command_dup(SilcServerCommandContext ctx)
 
 /* 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
+   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'. */
 
@@ -331,25 +332,32 @@ void silc_server_command_pending_del(SilcServer server,
 /* Checks for pending commands and marks callbacks to be called from
    the command reply function. Returns TRUE if there were pending command. */
 
-int silc_server_command_pending_check(SilcServer server,
-                                     SilcServerCommandReplyContext ctx,
-                                     SilcCommand command, 
-                                     uint16 ident)
+SilcServerCommandPendingCallbacks
+silc_server_command_pending_check(SilcServer server,
+                                 SilcServerCommandReplyContext ctx,
+                                 SilcCommand command, 
+                                 uint16 ident,
+                                 uint32 *callbacks_count)
 {
   SilcServerCommandPending *r;
+  SilcServerCommandPendingCallbacks callbacks = NULL;
+  int i = 0;
 
   silc_dlist_start(server->pending_commands);
   while ((r = silc_dlist_get(server->pending_commands)) != SILC_LIST_END) {
-    if (r->reply_cmd == command && r->ident == ident) {
-      ctx->context = r->context;
-      ctx->callback = r->callback;
-      ctx->destructor = r->destructor;
+    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;
+      callbacks[i].destructor = r->destructor;
       ctx->ident = ident;
-      return TRUE;
+      i++;
     }
   }
 
-  return FALSE;
+  *callbacks_count = i;
+  return callbacks;
 }
 
 /* Destructor function for pending callbacks. This is called when using
@@ -460,15 +468,7 @@ silc_server_command_whois_parse(SilcServerCommandContext cmd,
     /* No ID, get the nickname@server string and parse it. */
     tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
     if (tmp) {
-      if (strchr(tmp, '@')) {
-       len = strcspn(tmp, "@");
-       *nickname = silc_calloc(len + 1, sizeof(char));
-       memcpy(*nickname, tmp, len);
-       *server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
-       memcpy(*server_name, tmp + len + 1, strlen(tmp) - len - 1);
-      } else {
-       *nickname = strdup(tmp);
-      }
+      silc_parse_userfqdn(tmp, nickname, server_name);
     } else {
       silc_server_command_send_status_reply(cmd, command,
                                            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
@@ -518,52 +518,141 @@ silc_server_command_whois_parse(SilcServerCommandContext cmd,
   return TRUE;
 }
 
+/* Resolve context used by both WHOIS and IDENTIFY commands */
+typedef struct {
+  SilcServerEntry router;
+  uint16 ident;
+  unsigned char **res_argv;
+  uint32 *res_argv_lens;
+  uint32 *res_argv_types;
+  uint32 res_argc;
+} *SilcServerResolveContext;
+
 static char
 silc_server_command_whois_check(SilcServerCommandContext cmd,
                                SilcClientEntry *clients,
                                uint32 clients_count)
 {
   SilcServer server = cmd->server;
-  int i;
   SilcClientEntry entry;
+  SilcServerResolveContext resolve = NULL, r = NULL;
+  uint32 resolve_count = 0;
+  int i, k;
 
   for (i = 0; i < clients_count; i++) {
     entry = clients[i];
 
-    if (!entry || entry->data.registered == FALSE)
+    if (!entry || (entry->nickname && entry->username && entry->userinfo) ||
+       !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED) ||
+       !entry->router)
       continue;
 
-    if (!entry->nickname || !entry->username || !entry->userinfo) {
-      SilcBuffer tmpbuf;
-      uint16 old_ident;
-
-      if (!entry->router)
-       continue;
-      
-      old_ident = silc_command_get_ident(cmd->payload);
-      silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
-      tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+    /* We need to resolve this entry since it is not complete */
 
-      /* Send WHOIS command */
-      silc_server_packet_send(server, entry->router->connection,
-                             SILC_PACKET_COMMAND, cmd->packet->flags,
-                             tmpbuf->data, tmpbuf->len, TRUE);
-      
-      /* Reprocess this packet after received reply */
-      silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
-                                 silc_command_get_ident(cmd->payload),
+    if (!cmd->pending && entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
+      /* The entry is being resolved (and we are not the resolver) so attach
+        to the command reply and we're done with this one. */
+      silc_server_command_pending(server, SILC_COMMAND_NONE, 
+                                 entry->resolve_cmd_ident,
                                  silc_server_command_destructor,
-                                 silc_server_command_whois, 
+                                 silc_server_command_whois,
                                  silc_server_command_dup(cmd));
-      cmd->pending = TRUE;
-      
-      silc_command_set_ident(cmd->payload, old_ident);
+    } else {
+      if (entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
+       /* We've resolved this and it still is not ready.  We'll return
+          and are that this will be handled again after it is resolved. */
+       for (i = 0; i < resolve_count; i++) {
+         for (k = 0; k < r->res_argc; k++)
+           silc_free(r->res_argv[k]);
+         silc_free(r->res_argv);
+         silc_free(r->res_argv_lens);
+         silc_free(r->res_argv_types);
+       }
+       silc_free(resolve);
+       return FALSE;
+      } else {
+       /* We'll resolve this client */
+       SilcBuffer idp;
+
+       r = NULL;
+       for (k = 0; k < resolve_count; k++) {
+         if (resolve[k].router == entry->router) {
+           r = &resolve[k];
+           break;
+         }
+       }
 
-      silc_buffer_free(tmpbuf);
-      return FALSE;
+       if (!r) {
+         resolve = silc_realloc(resolve, sizeof(*resolve) * 
+                                (resolve_count + 1));
+         r = &resolve[resolve_count];
+         memset(r, 0, sizeof(*r));
+         r->router = entry->router;
+         r->ident = ++server->cmd_ident;
+         resolve_count++;
+       }
+
+       r->res_argv = silc_realloc(r->res_argv, sizeof(*r->res_argv) *
+                                  (r->res_argc + 1));
+       r->res_argv_lens = silc_realloc(r->res_argv_lens, 
+                                       sizeof(*r->res_argv_lens) *
+                                       (r->res_argc + 1));
+       r->res_argv_types = silc_realloc(r->res_argv_types, 
+                                        sizeof(*r->res_argv_types) *
+                                        (r->res_argc + 1));
+       idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
+       r->res_argv[r->res_argc] = silc_calloc(idp->len, 
+                                              sizeof(**r->res_argv));
+       memcpy(r->res_argv[r->res_argc], idp->data, idp->len);
+       r->res_argv_lens[r->res_argc] = idp->len;
+       r->res_argv_types[r->res_argc] = r->res_argc + 3;
+       r->res_argc++;
+       silc_buffer_free(idp);
+
+       entry->resolve_cmd_ident = r->ident;
+       entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
+       entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
+      }
     }
   }
 
+  /* Do the resolving */
+  for (i = 0; i < resolve_count; i++) {
+    SilcBuffer res_cmd;
+
+    r = &resolve[i];
+
+    /* Send WHOIS request. We send WHOIS since we're doing the requesting
+       now anyway so make it a good one. */
+    res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
+                                         r->res_argc, r->res_argv, 
+                                         r->res_argv_lens,
+                                         r->res_argv_types, 
+                                         r->ident);
+    silc_server_packet_send(server, r->router->connection,
+                           SILC_PACKET_COMMAND, cmd->packet->flags,
+                           res_cmd->data, res_cmd->len, TRUE);
+
+    /* Reprocess this packet after received reply */
+    silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
+                               r->ident,
+                               silc_server_command_destructor,
+                               silc_server_command_whois,
+                               silc_server_command_dup(cmd));
+    cmd->pending = TRUE;
+
+    silc_buffer_free(res_cmd);
+    for (k = 0; k < r->res_argc; k++)
+      silc_free(r->res_argv[k]);
+    silc_free(r->res_argv);
+    silc_free(r->res_argv_lens);
+    silc_free(r->res_argv_types);
+  }
+  silc_free(resolve);
+
+  if (resolve_count)
+    return FALSE;
+
   return TRUE;
 }
 
@@ -586,7 +675,7 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
 
   len = 0;
   for (i = 0; i < clients_count; i++)
-    if (clients[i]->data.registered)
+    if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED)
       len++;
 
   status = SILC_STATUS_OK;
@@ -596,7 +685,7 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
   for (i = 0, k = 0; i < clients_count; i++) {
     entry = clients[i];
 
-    if (entry->data.registered == FALSE) {
+    if (!(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
       if (clients_count == 1) {
        if (entry->nickname) {
          silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
@@ -881,15 +970,8 @@ silc_server_command_whowas_parse(SilcServerCommandContext cmd,
   }
 
   /* Get the nickname@server string and parse it. */
-  if (strchr(tmp, '@')) {
-    len = strcspn(tmp, "@");
-    *nickname = silc_calloc(len + 1, sizeof(char));
-    memcpy(*nickname, tmp, len);
-    *server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
-    memcpy(*server_name, tmp + len + 1, strlen(tmp) - len - 1);
-  } else {
-    *nickname = strdup(tmp);
-  }
+  silc_parse_userfqdn(tmp, nickname, server_name);
+
   /* Get the max count of reply messages allowed */
   tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
   if (tmp)
@@ -971,7 +1053,7 @@ silc_server_command_whowas_send_reply(SilcServerCommandContext cmd,
     /* We will take only clients that are not valid anymore. They are the
        ones that are not registered anymore but still have a ID. They
        have disconnected us, and thus valid for WHOWAS. */
-    if (entry->data.registered == TRUE)
+    if (entry->data.status & SILC_IDLIST_STATUS_REGISTERED)
       continue;
     if (entry->id == NULL)
       continue;
@@ -1143,12 +1225,9 @@ silc_server_command_whowas_process(SilcServerCommandContext cmd)
   silc_server_command_whowas_send_reply(cmd, clients, clients_count);
 
  out:
-  if (clients)
-    silc_free(clients);
-  if (nick)
-    silc_free(nick);
-  if (server_name)
-    silc_free(server_name);
+  silc_free(clients);
+  silc_free(nick);
+  silc_free(server_name);
 
   return ret;
 }
@@ -1210,15 +1289,7 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd,
       char *nick = NULL;
       char *nick_server = NULL;
 
-      if (strchr(tmp, '@')) {
-       len = strcspn(tmp, "@");
-       nick = silc_calloc(len + 1, sizeof(char));
-       memcpy(nick, tmp, len);
-       nick_server = silc_calloc(strlen(tmp) - len, sizeof(char));
-       memcpy(nick_server, tmp + len + 1, strlen(tmp) - len - 1);
-      } else {
-       nick = strdup(tmp);
-      }
+      silc_parse_userfqdn(tmp, &nick, &nick_server);
 
       if (!silc_idlist_get_clients_by_hash(server->local_list, 
                                           nick, server->md5hash,
@@ -1408,51 +1479,125 @@ silc_server_command_identify_check_client(SilcServerCommandContext cmd,
                                          uint32 clients_count)
 {
   SilcServer server = cmd->server;
-  int i;
   SilcClientEntry entry;
+  SilcServerResolveContext resolve = NULL, r = NULL;
+  uint32 resolve_count = 0;
+  int i, k;
 
   for (i = 0; i < clients_count; i++) {
     entry = clients[i];
 
-    if (!entry || entry->data.registered == FALSE)
+    if (!entry || entry->nickname || 
+       !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED) ||
+       !entry->router)
       continue;
 
-    if (!entry->nickname) {
-      SilcBuffer tmpbuf;
-      uint16 old_ident;
-      
-      if (!entry->router)
-       continue;
-      
-      old_ident = silc_command_get_ident(cmd->payload);
-      silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
-      silc_command_set_command(cmd->payload, SILC_COMMAND_WHOIS);
-      tmpbuf = silc_command_payload_encode_payload(cmd->payload);
-      
-      /* Send WHOIS request. We send WHOIS since we're doing the requesting
-        now anyway so make it a good one. */
-      silc_server_packet_send(server, entry->router->connection,
-                             SILC_PACKET_COMMAND, cmd->packet->flags,
-                             tmpbuf->data, tmpbuf->len, TRUE);
-      
-      /* Reprocess this packet after received reply */
-      silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
-                                 silc_command_get_ident(cmd->payload),
+    /* We need to resolve this entry since it is not complete */
+
+    if (!cmd->pending && entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
+      /* The entry is being resolved (and we are not the resolver) so attach
+        to the command reply and we're done with this one. */
+      silc_server_command_pending(server, SILC_COMMAND_NONE, 
+                                 entry->resolve_cmd_ident,
                                  silc_server_command_destructor,
                                  silc_server_command_identify,
                                  silc_server_command_dup(cmd));
+    } else {
+      if (entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
+       /* We've resolved this and it still is not ready.  We'll return
+          and are that this will be handled again after it is resolved. */
+       for (i = 0; i < resolve_count; i++) {
+         for (k = 0; k < r->res_argc; k++)
+           silc_free(r->res_argv[k]);
+         silc_free(r->res_argv);
+         silc_free(r->res_argv_lens);
+         silc_free(r->res_argv_types);
+       }
+       silc_free(resolve);
+       return FALSE;
+      } else {
+       /* We'll resolve this client */
+       SilcBuffer idp;
+
+       r = NULL;
+       for (k = 0; k < resolve_count; k++) {
+         if (resolve[k].router == entry->router) {
+           r = &resolve[k];
+           break;
+         }
+       }
 
-      cmd->pending = TRUE;
-      
-      /* Put old data back to the Command Payload we just changed */
-      silc_command_set_ident(cmd->payload, old_ident);
-      silc_command_set_command(cmd->payload, SILC_COMMAND_IDENTIFY);
+       if (!r) {
+         resolve = silc_realloc(resolve, sizeof(*resolve) * 
+                                (resolve_count + 1));
+         r = &resolve[resolve_count];
+         memset(r, 0, sizeof(*r));
+         r->router = entry->router;
+         r->ident = ++server->cmd_ident;
+         resolve_count++;
+       }
 
-      silc_buffer_free(tmpbuf);
-      return FALSE;
+       r->res_argv = silc_realloc(r->res_argv, sizeof(*r->res_argv) *
+                                  (r->res_argc + 1));
+       r->res_argv_lens = silc_realloc(r->res_argv_lens, 
+                                       sizeof(*r->res_argv_lens) *
+                                       (r->res_argc + 1));
+       r->res_argv_types = silc_realloc(r->res_argv_types, 
+                                        sizeof(*r->res_argv_types) *
+                                        (r->res_argc + 1));
+       idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
+       r->res_argv[r->res_argc] = silc_calloc(idp->len, 
+                                              sizeof(**r->res_argv));
+       memcpy(r->res_argv[r->res_argc], idp->data, idp->len);
+       r->res_argv_lens[r->res_argc] = idp->len;
+       r->res_argv_types[r->res_argc] = r->res_argc + 3;
+       r->res_argc++;
+       silc_buffer_free(idp);
+
+       entry->resolve_cmd_ident = r->ident;
+       entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
+       entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
+      }
     }
   }
 
+  /* Do the resolving */
+  for (i = 0; i < resolve_count; i++) {
+    SilcBuffer res_cmd;
+
+    r = &resolve[i];
+
+    /* Send WHOIS request. We send WHOIS since we're doing the requesting
+       now anyway so make it a good one. */
+    res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
+                                         r->res_argc, r->res_argv, 
+                                         r->res_argv_lens,
+                                         r->res_argv_types, 
+                                         r->ident);
+    silc_server_packet_send(server, r->router->connection,
+                           SILC_PACKET_COMMAND, cmd->packet->flags,
+                           res_cmd->data, res_cmd->len, TRUE);
+
+    /* Reprocess this packet after received reply */
+    silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
+                               r->ident,
+                               silc_server_command_destructor,
+                               silc_server_command_identify,
+                               silc_server_command_dup(cmd));
+    cmd->pending = TRUE;
+
+    silc_buffer_free(res_cmd);
+    for (k = 0; k < r->res_argc; k++)
+      silc_free(r->res_argv[k]);
+    silc_free(r->res_argv);
+    silc_free(r->res_argv_lens);
+    silc_free(r->res_argv_types);
+  }
+  silc_free(resolve);
+
+  if (resolve_count)
+    return FALSE;
+
   return TRUE;
 }
 
@@ -1481,7 +1626,7 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
 
     len = 0;
     for (i = 0; i < clients_count; i++)
-      if (clients[i]->data.registered)
+      if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED)
        len++;
 
     if (len > 1)
@@ -1490,7 +1635,7 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
     for (i = 0, k = 0; i < clients_count; i++) {
       entry = clients[i];
       
-      if (entry->data.registered == FALSE) {
+      if (!(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
        if (clients_count == 1) {
          SilcBuffer idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
          silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
index 7d884e169c84c1853dc7c1df79e94a55c6d8584a..da7a3ea737b96775ae255265838a5e3acce104a7 100644 (file)
@@ -96,18 +96,22 @@ void silc_server_command_##func(void *context, void *context2)
 /* Executed pending command. The first argument to the callback function
    is the user specified context. The second argument is always the
    SilcServerCommandReply context. */
-#define SILC_SERVER_PENDING_EXEC(ctx, cmd)     \
-do {                                           \
-  if (ctx->callback)                           \
-    (*ctx->callback)(ctx->context, ctx);       \
+#define SILC_SERVER_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); \
 } while(0)
 
 /* Execute destructor for pending command */
-#define SILC_SERVER_PENDING_DESTRUCTOR(ctx, cmd)                       \
-do {                                                                   \
-  silc_server_command_pending_del(ctx->server, cmd, ctx->ident);       \
-  if (ctx->destructor)                                                 \
-    (*ctx->destructor)(ctx->context);                                  \
+#define SILC_SERVER_PENDING_DESTRUCTOR(ctx, cmd)                          \
+do {                                                                      \
+  int _i;                                                                 \
+  silc_server_command_pending_del(ctx->server, cmd, ctx->ident);          \
+  for (_i = 0; _i < ctx->callbacks_count; _i++)                                   \
+    if (ctx->callbacks[_i].destructor)                                    \
+      (*ctx->callbacks[_i].destructor)(ctx->callbacks[_i].context);       \
 } while(0)
 
 /* Prototypes */
@@ -127,10 +131,12 @@ void silc_server_command_pending(SilcServer server,
 void silc_server_command_pending_del(SilcServer server,
                                     SilcCommand reply_cmd,
                                     uint16 ident);
-int silc_server_command_pending_check(SilcServer server,
-                                     SilcServerCommandReplyContext ctx,
-                                     SilcCommand command, 
-                                     uint16 ident);
+SilcServerCommandPendingCallbacks
+silc_server_command_pending_check(SilcServer server,
+                                 SilcServerCommandReplyContext ctx,
+                                 SilcCommand command, 
+                                 uint16 ident,
+                                 uint32 *callbacks_count);
 SILC_SERVER_CMD_FUNC(whois);
 SILC_SERVER_CMD_FUNC(whowas);
 SILC_SERVER_CMD_FUNC(identify);
index 6ecc3ad03e15b5874f975dac393b97a650841d08..cb124b426389e937c302554f6e68862c2e407f7c 100644 (file)
@@ -93,8 +93,10 @@ void silc_server_command_reply_process(SilcServer server,
   ident = silc_command_get_ident(ctx->payload);
       
   /* Check for pending commands and mark to be exeucted */
-  silc_server_command_pending_check(server, ctx, 
-                                   silc_command_get(ctx->payload), ident);
+  ctx->callbacks = 
+    silc_server_command_pending_check(server, ctx, 
+                                     silc_command_get(ctx->payload), 
+                                     ident, &ctx->callbacks_count);
 
   /* Execute command reply */
   command = silc_command_get(ctx->payload);
@@ -118,6 +120,7 @@ void silc_server_command_reply_free(SilcServerCommandReplyContext cmd)
     silc_command_payload_free(cmd->payload);
     if (cmd->sock)
       silc_socket_free(cmd->sock); /* Decrease the reference counter */
+    silc_free(cmd->callbacks);
     silc_free(cmd);
   }
 }
@@ -173,15 +176,7 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
       return FALSE;
 
     /* Take hostname out of nick string if it includes it. */
-    if (strchr(nickname, '@')) {
-      int len = strcspn(nickname, "@");
-      nick = silc_calloc(len + 1, sizeof(char));
-      servername = silc_calloc((strlen(nickname) - len) + 1, sizeof(char));
-      memcpy(nick, nickname, len);
-      memcpy(servername, nickname + len + 1, strlen(nickname) - len);
-    } else {
-      nick = strdup(nickname);
-    }
+    silc_parse_userfqdn(nickname, &nick, &servername);
 
     /* We don't have that client anywhere, add it. The client is added
        to global list since server didn't have it in the lists so it must be 
@@ -195,7 +190,9 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
       return FALSE;
     }
 
-    client->data.registered = TRUE;
+    client->data.status |= 
+      (SILC_IDLIST_STATUS_REGISTERED | SILC_IDLIST_STATUS_RESOLVED);
+    client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
     client->mode = mode;
     client->servername = servername;
   } else {
@@ -204,32 +201,26 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
     SILC_LOG_DEBUG(("Updating client data"));
 
     /* Take hostname out of nick string if it includes it. */
-    if (strchr(nickname, '@')) {
-      int len = strcspn(nickname, "@");
-      nick = silc_calloc(len + 1, sizeof(char));
-      servername = silc_calloc((strlen(nickname) - len) + 1, sizeof(char));
-      memcpy(nick, nickname, len);
-      memcpy(servername, nickname + len + 1, strlen(nickname) - len);
-    } else {
-      nick = strdup(nickname);
-    }
+    silc_parse_userfqdn(nickname, &nick, &servername);
 
-    if (client->nickname)
-      silc_free(client->nickname);
-    if (client->username)
-      silc_free(client->username);
-    if (client->userinfo)
-      silc_free(client->userinfo);
+    /* Remove the old cache entry  */
+    silc_idcache_del_by_context(global ? server->global_list->clients :
+                               server->local_list->clients, client);
+
+    silc_free(client->nickname);
+    silc_free(client->username);
+    silc_free(client->userinfo);
+    silc_free(client->servername);
     
     client->nickname = nick;
     client->username = strdup(username);
     client->userinfo = strdup(realname);
-    client->mode = mode;
     client->servername = servername;
+    client->mode = mode;
+    client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
+    client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
 
-    /* Remove the old cache entry and create a new one */
-    silc_idcache_del_by_context(global ? server->global_list->clients :
-                               server->local_list->clients, client);
+    /* Create new cache entry */
     silc_idcache_add(global ? server->global_list->clients :
                     server->local_list->clients, nick, client->id, 
                     client, FALSE);
@@ -312,15 +303,7 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
       return FALSE;
 
     /* Take hostname out of nick string if it includes it. */
-    if (strchr(nickname, '@')) {
-      int len = strcspn(nickname, "@");
-      nick = silc_calloc(len + 1, sizeof(char));
-      servername = silc_calloc((strlen(nickname) - len) + 1, sizeof(char));
-      memcpy(nick, nickname, len);
-      memcpy(servername, nickname + len + 1, strlen(nickname) - len);
-    } else {
-      nick = strdup(nickname);
-    }
+    silc_parse_userfqdn(nickname, &nick, &servername);
 
     /* We don't have that client anywhere, add it. The client is added
        to global list since server didn't have it in the lists so it must be 
@@ -334,7 +317,7 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
       return FALSE;
     }
 
-    client->data.registered = FALSE;
+    client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED; 
     client = silc_idlist_find_client_by_id(server->global_list, 
                                           client_id, TRUE, &cache);
     cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
@@ -343,20 +326,10 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
     /* We have the client already, update the data */
 
     /* Take hostname out of nick string if it includes it. */
-    if (strchr(nickname, '@')) {
-      int len = strcspn(nickname, "@");
-      nick = silc_calloc(len + 1, sizeof(char));
-      servername = silc_calloc((strlen(nickname) - len) + 1, sizeof(char));
-      memcpy(nick, nickname, len);
-      memcpy(servername, nickname + len + 1, strlen(nickname) - len);
-    } else {
-      nick = strdup(nickname);
-    }
+    silc_parse_userfqdn(nickname, &nick, &servername);
 
-    if (client->nickname)
-      silc_free(client->nickname);
-    if (client->username)
-      silc_free(client->username);
+    silc_free(client->nickname);
+    silc_free(client->username);
     
     client->nickname = nick;
     client->username = strdup(username);
@@ -453,17 +426,10 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
         be bogus client or some router in the net is buggy. */
       if (server->server_type == SILC_ROUTER)
        goto error;
-      
-      /* Take hostname out of nick string if it includes it. */
-      if (name) {
-       if (strchr(name, '@')) {
-         int len = strcspn(name, "@");
-         nick = silc_calloc(len + 1, sizeof(char));
-         memcpy(nick, name, len);
-       } else {
-         nick = strdup(name);
-       }
-      }
+
+      /* Take nickname */
+      if (name)
+       silc_parse_userfqdn(name, &nick, NULL);
 
       /* We don't have that client anywhere, add it. The client is added
         to global list since server didn't have it in the lists so it must be 
@@ -475,38 +441,36 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
        SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
        goto error;
       }
-      client->data.registered = TRUE;
+      client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
+      client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
+      client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
     } else {
       /* We have the client already, update the data */
       
       SILC_LOG_DEBUG(("Updating client data"));
       
-      /* Take hostname out of nick string if it includes it. */
+      /* Take nickname */
       if (name) {
-       if (strchr(name, '@')) {
-         int len = strcspn(name, "@");
-         nick = silc_calloc(len + 1, sizeof(char));
-         memcpy(nick, name, len);
-       } else {
-         nick = strdup(name);
-       }
-      }
-      
-      if (name && client->nickname)
+       silc_parse_userfqdn(name, &nick, NULL);
+
+       /* Remove the old cache entry */
+       silc_idcache_del_by_context(global ? server->global_list->clients :
+                                   server->local_list->clients, client);
+
        silc_free(client->nickname);
-      
-      if (nick)
        client->nickname = nick;
+      }
       
-      if (info && client->username) {
+      if (info) {
        silc_free(client->username);
        client->username = strdup(info);
       }
+
+      client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
+      client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
       
-      /* Remove the old cache entry and create a new one */
       if (name) {
-       silc_idcache_del_by_context(global ? server->global_list->clients :
-                                   server->local_list->clients, client);
+       /* Add new cache entry */
        silc_idcache_add(global ? server->global_list->clients :
                         server->local_list->clients, nick, client->id, 
                         client, FALSE);
@@ -543,7 +507,9 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
        silc_free(server_id);
        goto error;
       }
-      server_entry->data.registered = TRUE;
+      server_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
+      server_entry->data.status |= SILC_IDLIST_STATUS_RESOLVED;
+      server_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
       server_id = NULL;
     }
 
@@ -661,7 +627,7 @@ SILC_SERVER_CMD_REPLY_FUNC(info)
        silc_free(server_id);
        goto out;
       }
-      entry->data.registered = TRUE;
+      entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
     }
   }
 
index 75be5094ea0232dbf6c5c132821a6835ddb06c03..eb5b53d48553b81a5a6718387e3469aa0c9941bb 100644 (file)
@@ -32,6 +32,13 @@ typedef struct {
 /* All server command replys */
 extern SilcServerCommandReply silc_command_reply_list[];
 
+/* Context holding pending command callbacks. */
+typedef struct {
+  SilcServerPendingDestructor destructor;
+  SilcCommandCb callback;
+  void *context;
+} *SilcServerCommandPendingCallbacks;
+
 /* Context sent as argument to all command reply functions */
 typedef struct {
   SilcServer server;
@@ -40,9 +47,8 @@ typedef struct {
   SilcArgumentPayload args;
 
   /* If defined this executes the pending command. */
-  SilcServerPendingDestructor destructor;
-  SilcCommandCb callback;
-  void *context;
+  SilcServerCommandPendingCallbacks callbacks;
+  uint32 callbacks_count;
   uint16 ident;
 } *SilcServerCommandReplyContext;
 
index cb18b18b559dbf596477061e1abf02ea7fa27372..0360ad3713ea19887d1f7fc6482d83fcab5b9e32 100644 (file)
@@ -43,7 +43,7 @@ void silc_idlist_add_data(void *entry, SilcIDListData idata)
   data->public_key = idata->public_key;
   data->last_receive = idata->last_receive;
   data->last_sent = idata->last_sent;
-  data->registered = idata->registered;
+  data->status = idata->status;
 }
 
 /* Free's all data in the common ID entry data structure. */
@@ -144,7 +144,8 @@ silc_idlist_find_server_by_id(SilcIDList id_list, SilcServerID *id,
   if (ret_entry)
     *ret_entry = id_cache;
 
-  if (server && registered && !server->data.registered)
+  if (server && registered && 
+      !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
     return NULL;
 
   SILC_LOG_DEBUG(("Found"));
@@ -171,7 +172,8 @@ silc_idlist_find_server_by_name(SilcIDList id_list, char *name,
   if (ret_entry)
     *ret_entry = id_cache;
 
-  if (server && registered && !server->data.registered)
+  if (server && registered &&
+      !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
     return NULL;
 
   SILC_LOG_DEBUG(("Found"));
@@ -222,7 +224,8 @@ silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname,
   if (ret_entry)
     *ret_entry = id_cache;
 
-  if (server && registered && !server->data.registered)
+  if (server && registered &&
+      !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
     return NULL;
 
   SILC_LOG_DEBUG(("Found"));
@@ -377,7 +380,6 @@ int silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
 {
   SilcIDCacheList list = NULL;
   SilcIDCacheEntry id_cache = NULL;
-  int i;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -388,18 +390,15 @@ int silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
                          (silc_idcache_list_count(list) + *clients_count) * 
                          sizeof(**clients));
 
-  i = 0;
   silc_idcache_list_first(list, &id_cache);
-  (*clients)[i++] = (SilcClientEntry)id_cache->context;
+  (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
 
   while (silc_idcache_list_next(list, &id_cache))
-    (*clients)[i++] = (SilcClientEntry)id_cache->context;
+    (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
   
   silc_idcache_list_free(list);
   
-  *clients_count += i;
-
-  SILC_LOG_DEBUG(("Found %d clients", *clients_count));
+  SILC_LOG_DEBUG(("Found total %d clients", *clients_count));
 
   return TRUE;
 }
@@ -415,7 +414,6 @@ int silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname,
   SilcIDCacheList list = NULL;
   SilcIDCacheEntry id_cache = NULL;
   unsigned char hash[32];
-  int i;
   SilcClientID client_id;
 
   SILC_LOG_DEBUG(("Start"));
@@ -435,18 +433,15 @@ int silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname,
                          (silc_idcache_list_count(list) + *clients_count) * 
                          sizeof(**clients));
 
-  i = 0;
   silc_idcache_list_first(list, &id_cache);
-  (*clients)[i++] = (SilcClientEntry)id_cache->context;
+  (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
 
   while (silc_idcache_list_next(list, &id_cache))
-    (*clients)[i++] = (SilcClientEntry)id_cache->context;
+    (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
   
   silc_idcache_list_free(list);
   
-  *clients_count += i;
-
-  SILC_LOG_DEBUG(("Found %d clients", *clients_count));
+  SILC_LOG_DEBUG(("Found total %d clients", *clients_count));
 
   return TRUE;
 }
@@ -481,7 +476,8 @@ silc_idlist_find_client_by_id(SilcIDList id_list, SilcClientID *id,
   if (ret_entry)
     *ret_entry = id_cache;
 
-  if (client && registered && !client->data.registered)
+  if (client && registered &&
+      !(client->data.status & SILC_IDLIST_STATUS_REGISTERED))
     return NULL;
 
   SILC_LOG_DEBUG(("Found"));
@@ -522,8 +518,7 @@ silc_idlist_replace_client_id(SilcIDList id_list, SilcClientID *old_id,
   silc_free(client->id);
   client->id = new_id;
 
-  silc_idcache_add(id_list->clients, client->nickname, client->id, 
-                  client, FALSE);
+  silc_idcache_add(id_list->clients, NULL, client->id, client, FALSE);
 
   SILC_LOG_DEBUG(("Replaced"));
 
index 5a11125d562e3a556a14ec28a28ffaef6c29b19e..10bf4e32748cce2972ba3866b7d439f9d01bd2ac 100644 (file)
@@ -52,15 +52,23 @@ typedef struct {
   void *context;
 } *SilcServerRekey;
 
+/* ID List Entry status type and all the types. */
+typedef uint8 SilcIDListStatus;
+#define SILC_IDLIST_STATUS_NONE         0x00    /* No status */
+#define SILC_IDLIST_STATUS_REGISTERED   0x01    /* Entry is registered */
+#define SILC_IDLIST_STATUS_RESOLVED     0x02    /* Entry info is resolved */
+#define SILC_IDLIST_STATUS_RESOLVING    0x04    /* Entry is being resolved
+                                                  with WHOIS or IDENTIFY */
+
 /*
    Generic ID list data structure.
 
    This structure is included in all ID list entries and it includes data
    pointers that are common to all ID entries.  This structure is always
    defined to the first field in the ID entries and is used to explicitly
-   cast to this type without first explicitly casting to correct ID entry
-   type.  Hence, the ID list entry is casted to this type to get this data
-   from the ID entry (which is usually opaque pointer).
+   type cast to this type without first explicitly casting to correct ID
+   entry type.  Hence, the ID list entry is type casted to this type to
+   get this data from the ID entry (which is usually opaque pointer).
 
    Note that some of the fields may be NULL.
 
@@ -83,9 +91,10 @@ typedef struct {
   /* Public key */
   SilcPublicKey public_key;
 
-  long last_receive;         /* Time last received data */
-  long last_sent;           /* Time last sent data */
-  bool registered;           /* Boolean whether connection is registered */
+  long last_receive;           /* Time last received data */
+  long last_sent;              /* Time last sent data */
+
+  SilcIDListStatus status;     /* Status mask of the entry */
 } *SilcIDListData, SilcIDListDataStruct;
 
 /* 
@@ -301,6 +310,14 @@ typedef struct SilcChannelClientEntryStruct {
        but as just said, this is usually pointer to the socket connection
        list.
 
+   uint16 resolve_cmd_ident
+
+       Command identifier for the entry when the entry's data.status
+       is SILC_IDLIST_STATUS_RESOLVING.  If this entry is asked to be
+       resolved when the status is set then the resolver may attach to
+       this command identifier and handle the process after the resolving
+       is over.
+
 */
 struct SilcClientEntryStruct {
   /* Generic data structure. DO NOT add anything before this! */
@@ -324,6 +341,10 @@ struct SilcClientEntryStruct {
 
   /* Connection data */
   void *connection;
+
+  /* data.status is RESOLVING and this includes the resolving command 
+     reply identifier. */
+  uint16 resolve_cmd_ident;
 };
 
 /* 
index d88d05464e5872f1742d0306c381ced3d65272ac..28563a5550eb14c6ad14ab7c8d4b66a49f7285f5 100644 (file)
@@ -162,12 +162,12 @@ void silc_server_notify(SilcServer server,
          goto out;
        }
 
-       client->data.registered = TRUE;
+       client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
       }
     }
 
     /* Do not process the notify if the client is not registered */
-    if (client->data.registered == FALSE)
+    if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED))
       break;
 
     /* Do not add client to channel if it is there already */
@@ -184,6 +184,12 @@ void silc_server_notify(SilcServer server,
     chl = silc_calloc(1, sizeof(*chl));
     chl->client = client;
     chl->channel = channel;
+
+    /* If this is the first one on the channel then it is the founder off
+       the channel. */
+    if (!silc_hash_table_count(channel->user_list))
+      chl->mode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
+
     silc_hash_table_add(channel->user_list, client, chl);
     silc_hash_table_add(client->channels, channel, chl);
     silc_free(client_id);
@@ -283,7 +289,7 @@ void silc_server_notify(SilcServer server,
     /* Remove the client from all channels. */
     silc_server_remove_from_channels(server, NULL, client, TRUE, tmp, FALSE);
 
-    client->data.registered = FALSE;
+    client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
     cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
     server->stat.clients--;
     if (server->server_type == SILC_ROUTER)
@@ -1449,7 +1455,7 @@ SilcClientEntry silc_server_new_client(SilcServer server,
   }
 
   /* Update client entry */
-  idata->registered = TRUE;
+  idata->status |= SILC_IDLIST_STATUS_REGISTERED;
   client->nickname = nickname;
   client->username = username;
   client->userinfo = realname ? realname : strdup(" ");
@@ -1600,7 +1606,7 @@ SilcServerEntry silc_server_new_server(SilcServer server,
   silc_free(id_string);
 
   /* Update server entry */
-  idata->registered = TRUE;
+  idata->status |= SILC_IDLIST_STATUS_REGISTERED;
   new_server->server_name = server_name;
   new_server->id = server_id;
 
@@ -1720,7 +1726,7 @@ static void silc_server_new_id_real(SilcServer server,
        goto out;
       }
       entry->nickname = NULL;
-      entry->data.registered = TRUE;
+      entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
 
       if (sock->type == SILC_SOCKET_TYPE_SERVER)
        server->stat.cell_clients++;
@@ -1737,6 +1743,12 @@ static void silc_server_new_id_real(SilcServer server,
        SILC_LOG_DEBUG(("Ignoring my own ID as new ID"));
        break;
       }
+
+      /* If the ID is the sender's ID, ignore it (we have it already) */
+      if (SILC_ID_SERVER_COMPARE(id, router->id)) {
+       SILC_LOG_DEBUG(("Ignoring sender's own ID"));
+       break;
+      }
       
       SILC_LOG_DEBUG(("New server id(%s) from [%s] %s",
                      silc_id_render(id, SILC_ID_SERVER),
@@ -1752,7 +1764,7 @@ static void silc_server_new_id_real(SilcServer server,
        SILC_LOG_ERROR(("Could not add new server to the ID Cache"));
        goto out;
       }
-      entry->data.registered = TRUE;
+      entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
       
       if (sock->type == SILC_SOCKET_TYPE_SERVER)
        server->stat.cell_servers++;
index 522423860637c864e4cc1c9811365831db8d41f4..6f66e32c8fdd552fbfa681bfba2b91a2bb076413 100644 (file)
@@ -245,7 +245,7 @@ int silc_server_init(SilcServer server)
       SILC_LOG_ERROR(("Could not add ourselves to cache"));
       goto err0;
     }
-    id_entry->data.registered = TRUE;
+    id_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
     
     /* Add ourselves also to the socket table. The entry allocated above
        is sent as argument for fast referencing in the future. */
@@ -889,7 +889,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
   server->id_entry->router = id_entry;
   server->router = id_entry;
   idata = (SilcIDListData)sock->user_data;
-  idata->registered = TRUE;
+  idata->status |= SILC_IDLIST_STATUS_REGISTERED;
 
   /* Perform keepalive. The `hb_context' will be freed automatically
      when finally calling the silc_socket_free function. XXX hardcoded 
@@ -2239,7 +2239,7 @@ void silc_server_free_client_data(SilcServer server,
                     silc_server_free_client_data_timeout,
                     (void *)i, 300, 0,
                     SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
-  client->data.registered = FALSE;
+  client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
   client->router = NULL;
   client->connection = NULL;
 
@@ -2464,7 +2464,7 @@ int silc_server_remove_clients_by_server(SilcServer server,
     if (silc_idcache_list_first(list, &id_cache)) {
       while (id_cache) {
        client = (SilcClientEntry)id_cache->context;
-       if (client->data.registered == FALSE) {
+       if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
          if (!silc_idcache_list_next(list, &id_cache))
            break;
          else
@@ -2516,7 +2516,7 @@ int silc_server_remove_clients_by_server(SilcServer server,
     if (silc_idcache_list_first(list, &id_cache)) {
       while (id_cache) {
        client = (SilcClientEntry)id_cache->context;
-       if (client->data.registered == FALSE) {
+       if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
          if (!silc_idcache_list_next(list, &id_cache))
            break;
          else
@@ -3275,6 +3275,7 @@ void silc_server_perform_heartbeat(SilcSocketConnection sock,
    form is dictated by the New ID payload. */
 
 static void silc_server_announce_get_servers(SilcServer server,
+                                            SilcServerEntry remote,
                                             SilcIDList id_list,
                                             SilcBuffer *servers)
 {
@@ -3289,6 +3290,14 @@ static void silc_server_announce_get_servers(SilcServer server,
       while (id_cache) {
        entry = (SilcServerEntry)id_cache->context;
 
+       /* Do not announce the one we've sending our announcments and
+          do not announce ourself. */
+       if (entry == remote || entry == server->id_entry) {
+         if (!silc_idcache_list_next(list, &id_cache))
+           break;
+         continue;
+       }
+
        idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
 
        *servers = silc_buffer_realloc(*servers, 
@@ -3319,10 +3328,12 @@ void silc_server_announce_servers(SilcServer server)
   SILC_LOG_DEBUG(("Announcing servers"));
 
   /* Get servers in local list */
-  silc_server_announce_get_servers(server, server->local_list, &servers);
+  silc_server_announce_get_servers(server, server->router,
+                                  server->local_list, &servers);
 
   /* Get servers in global list */
-  silc_server_announce_get_servers(server, server->global_list, &servers);
+  silc_server_announce_get_servers(server, server->router,
+                                  server->global_list, &servers);
 
   if (servers) {
     silc_buffer_push(servers, servers->data - servers->head);
@@ -3764,7 +3775,7 @@ void silc_server_save_users_on_channel(SilcServer server,
        continue;
       }
 
-      client->data.registered = TRUE;
+      client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
     }
 
     silc_free(client_id);
@@ -3933,9 +3944,13 @@ SilcClientEntry silc_server_get_client_resolve(SilcServer server,
   if (!client || !client->nickname || !client->username) {
     SilcBuffer buffer, idp;
 
+    client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
+    client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
+    client->resolve_cmd_ident = ++server->cmd_ident;
+
     idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
     buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
-                                           ++server->cmd_ident, 1,
+                                           server->cmd_ident, 1,
                                            3, idp->data, idp->len);
     silc_server_packet_send(server, client ? client->router->connection :
                            server->router->connection,
index 02ed07e07ba4fe39ce16b76a8685e507d8b9ae3f..245e4dfb1c40e49334d9480fe17d5dc90862cc22 100644 (file)
@@ -238,7 +238,8 @@ bool silc_idcache_del_by_id_ext(SilcIDCache cache, void *id,
     ret = silc_hash_table_del(cache->context_table, c->context);
   if (c->id)
     ret = silc_hash_table_del_ext(cache->id_table, c->id, hash,
-                                 hash_context, compare, compare_context);
+                                 hash_context, compare, compare_context,
+                                 NULL, NULL);
 
   return ret;
 }
@@ -276,6 +277,12 @@ bool silc_idcache_del_all(SilcIDCache cache)
   return TRUE;
 }
 
+static void silc_idcache_destructor_dummy(void *key, void *context,
+                                         void *user_context)
+{
+  /* Dummy - nothing */
+}
+
 /* Foreach callback fro silc_idcache_purge. */
 
 static void silc_idcache_purge_foreach(void *key, void *context,
@@ -286,12 +293,22 @@ static void silc_idcache_purge_foreach(void *key, void *context,
   SilcIDCacheEntry c = (SilcIDCacheEntry)context;
 
   if (c->expire && c->expire < curtime) {
+    /* Remove the entry from the hash tables */
+    if (c->name)
+      silc_hash_table_del_by_context(cache->name_table, c->name, c);
+    if (c->context)
+      silc_hash_table_del(cache->context_table, c->context);
+    if (c->id)
+      silc_hash_table_del_by_context_ext(cache->id_table, c->id, c,
+                                        NULL, NULL, NULL, NULL, 
+                                        silc_idcache_destructor_dummy, NULL);
+
     /* Call the destructor */
     if (cache->destructor)
       cache->destructor(cache, c);
 
-    /* Delete the entry */
-    silc_idcache_del(cache, c);
+    /* Free the entry, it has been deleted from the hash tables */
+    silc_free(c);
   }
 }
 
@@ -308,24 +325,30 @@ bool silc_idcache_purge(SilcIDCache cache)
 
 bool silc_idcache_purge_by_context(SilcIDCache cache, void *context)
 {
-  SilcIDCacheEntry entry;
+  SilcIDCacheEntry c;
   bool ret = FALSE;
 
   if (!silc_hash_table_find(cache->context_table, context, NULL, 
-                           (void *)&entry))
+                           (void *)&c))
     return FALSE;
 
+    /* Remove the entry from the hash tables */
+  if (c->name)
+    ret = silc_hash_table_del_by_context(cache->name_table, c->name, c);
+  if (c->context)
+    ret = silc_hash_table_del(cache->context_table, c->context);
+  if (c->id)
+    ret =
+      silc_hash_table_del_by_context_ext(cache->id_table, c->id, c,
+                                        NULL, NULL, NULL, NULL, 
+                                        silc_idcache_destructor_dummy, NULL);
+  
   /* Call the destructor */
   if (cache->destructor)
-    cache->destructor(cache, entry);
-  
-  if (entry->name)
-    ret = silc_hash_table_del_by_context(cache->name_table, entry->name, 
-                                        entry);
-  if (entry->context)
-    ret = silc_hash_table_del(cache->context_table, entry->context);
-  if (entry->id)
-    ret = silc_hash_table_del_by_context(cache->id_table, entry->id, entry);
+    cache->destructor(cache, c);
+
+  /* Free the entry, it has been deleted from the hash tables */
+  silc_free(c);
 
   return ret;
 }
index 03e2a905044364fcd3820d993e9636bae9ba0f8f..130d9fa72e4a3b80d90b1b372ad57d1bc7077e2e 100644 (file)
@@ -2,7 +2,7 @@
 
   silchashtable.c
 
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+  Author: Pekka Riikonen <priikone@silcnet.org>
 
   Copyright (C) 2001 Pekka Riikonen
 
@@ -472,7 +472,9 @@ bool silc_hash_table_del_ext(SilcHashTable ht, void *key,
                             SilcHashFunction hash, 
                             void *hash_user_context,
                             SilcHashCompare compare, 
-                            void *compare_user_context)
+                            void *compare_user_context,
+                            SilcHashDestructor destructor,
+                            void *destructor_user_context)
 {
   SilcHashTableEntry *entry, prev, e;
 
@@ -498,8 +500,12 @@ bool silc_hash_table_del_ext(SilcHashTable ht, void *key,
   if (prev && e->next)
     prev->next = e->next;
 
-  if (ht->destructor)
-    ht->destructor(e->key, e->context, ht->destructor_user_context);
+  if (destructor) {
+    destructor(e->key, e->context, destructor_user_context);
+  } else {
+    if (ht->destructor)
+      ht->destructor(e->key, e->context, ht->destructor_user_context);
+  }
   silc_free(e);
 
   ht->entry_count--;
@@ -558,7 +564,9 @@ bool silc_hash_table_del_by_context_ext(SilcHashTable ht, void *key,
                                        SilcHashFunction hash, 
                                        void *hash_user_context,
                                        SilcHashCompare compare, 
-                                       void *compare_user_context)
+                                       void *compare_user_context,
+                                       SilcHashDestructor destructor,
+                                       void *destructor_user_context)
 {
   SilcHashTableEntry *entry, prev, e;
 
@@ -586,8 +594,12 @@ bool silc_hash_table_del_by_context_ext(SilcHashTable ht, void *key,
   if (prev && e->next)
     prev->next = e->next;
 
-  if (ht->destructor)
-    ht->destructor(e->key, e->context, ht->destructor_user_context);
+  if (destructor) {
+    destructor(e->key, e->context, destructor_user_context);
+  } else {
+    if (ht->destructor)
+      ht->destructor(e->key, e->context, ht->destructor_user_context);
+  }
   silc_free(e);
 
   ht->entry_count--;
index 7ee44c165ae8e84d11045431ededdf23b227bd41..bdee0e10c69ffdf6c70c8e360612b611993f7b33 100644 (file)
@@ -462,7 +462,9 @@ void silc_hash_table_replace_ext(SilcHashTable ht, void *key, void *context,
  *                                 SilcHashFunction hash, 
  *                                 void *hash_user_context,
  *                                 SilcHashCompare compare, 
- *                                 void *compare_user_context);
+ *                                 void *compare_user_context,
+ *                                 SilcHashDestructor destructor,
+ *                                 void *destructor_user_context);
  *
  * DESCRIPTION
  *
@@ -474,13 +476,17 @@ void silc_hash_table_replace_ext(SilcHashTable ht, void *key, void *context,
  *    function. If not provided the hash table's default is used.
  *    The `compare' and `compare_user_context' are application specified
  *    comparing function. If not provided the hash table's default is used.
+ *    The `destructor' and `destructor_user_context' are application
+ *    specific destructor function.
  *
  ***/
 bool silc_hash_table_del_ext(SilcHashTable ht, void *key,
                             SilcHashFunction hash, 
                             void *hash_user_context,
                             SilcHashCompare compare, 
-                            void *compare_user_context);
+                            void *compare_user_context,
+                            SilcHashDestructor destructor,
+                            void *destructor_user_context);
 
 /****f* silcutil/SilcHashTableAPI/silc_hash_table_del_by_context_ext
  *
@@ -491,7 +497,9 @@ bool silc_hash_table_del_ext(SilcHashTable ht, void *key,
  *                                            SilcHashFunction hash, 
  *                                            void *hash_user_context,
  *                                            SilcHashCompare compare, 
- *                                            void *compare_user_context);
+ *                                            void *compare_user_context,
+ *                                            SilcHashDestructor destructor,
+ *                                            void *destructor_user_context);
  *
  * DESCRIPTION
  *
@@ -504,6 +512,8 @@ bool silc_hash_table_del_ext(SilcHashTable ht, void *key,
  *    function. If not provided the hash table's default is used.
  *    The `compare' and `compare_user_context' are application specified
  *    comparing function. If not provided the hash table's default is used.
+ *    The `destructor' and `destructor_user_context' are application
+ *    specific destructor function.
  *
  ***/
 bool silc_hash_table_del_by_context_ext(SilcHashTable ht, void *key, 
@@ -511,7 +521,9 @@ bool silc_hash_table_del_by_context_ext(SilcHashTable ht, void *key,
                                        SilcHashFunction hash, 
                                        void *hash_user_context,
                                        SilcHashCompare compare, 
-                                       void *compare_user_context);
+                                       void *compare_user_context,
+                                       SilcHashDestructor destructor,
+                                       void *destructor_user_context);
 
 /****f* silcutil/SilcHashTableAPI/silc_hash_table_find_ext
  *