updates
authorPekka Riikonen <priikone@silcnet.org>
Fri, 15 Dec 2000 15:04:46 +0000 (15:04 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Fri, 15 Dec 2000 15:04:46 +0000 (15:04 +0000)
apps/silcd/command.c
apps/silcd/packet_receive.c
lib/silcclient/command_reply.c

index e25d6ea81316c914a2cf396d1686710335275894..7bc6d692d9a11ee15c78927bbee3f756bdf059a4 100644 (file)
@@ -304,6 +304,12 @@ silc_server_command_send_status_data(SilcServerCommandContext cmd,
   silc_buffer_free(buffer);
 }
 
+/******************************************************************************
+
+                              WHOIS Functions
+
+******************************************************************************/
+
 static int
 silc_server_command_whois_parse(SilcServerCommandContext cmd,
                                SilcClientID **client_id,
@@ -373,14 +379,14 @@ silc_server_command_whois_check(SilcServerCommandContext cmd,
 
     if (!entry->nickname || !entry->username || !entry->userinfo) {
       SilcBuffer tmpbuf;
+      unsigned short old_ident;
       
+      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);
 
-      /* Send WHOIS command to fastest route for the client ID */
-      silc_server_packet_send(server,
-                             silc_server_route_get(server, entry->id, 
-                                                   SILC_ID_CLIENT),
+      /* Send WHOIS command */
+      silc_server_packet_send(server, entry->router->connection,
                              SILC_PACKET_COMMAND, cmd->packet->flags,
                              tmpbuf->data, tmpbuf->len, TRUE);
       
@@ -390,6 +396,8 @@ silc_server_command_whois_check(SilcServerCommandContext cmd,
                                  silc_server_command_whois, (void *)cmd);
       cmd->pending = TRUE;
       
+      silc_command_set_ident(cmd->payload, old_ident);
+
       silc_buffer_free(tmpbuf);
       return FALSE;
     }
@@ -409,6 +417,7 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
   SilcBuffer packet, idp;
   SilcClientEntry entry;
   SilcCommandStatus status;
+  unsigned short ident = silc_command_get_ident(cmd->payload);
 
   status = SILC_STATUS_OK;
   if (clients_count > 1)
@@ -431,7 +440,7 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
     tmp = silc_argument_get_first_arg(cmd->args, NULL);
     
     /* XXX */
-    if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
+    {
       char nh[256], uh[256];
       unsigned char idle[4];
       SilcSocketConnection hsock;
@@ -440,17 +449,21 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
       memset(nh, 0, sizeof(nh));
       
       strncat(nh, entry->nickname, strlen(entry->nickname));
-      strncat(nh, "@", 1);
-      len = entry->router ? strlen(entry->router->server_name) :
-       strlen(server->server_name);
-      strncat(nh, entry->router ? entry->router->server_name :
-             server->server_name, len);
+      if (!strchr(entry->nickname, '@')) {
+       strncat(nh, "@", 1);
+       len = entry->router ? strlen(entry->router->server_name) :
+         strlen(server->server_name);
+       strncat(nh, entry->router ? entry->router->server_name :
+               server->server_name, len);
+      }
       
       strncat(uh, entry->username, strlen(entry->username));
-      strncat(uh, "@", 1);
-      hsock = (SilcSocketConnection)entry->connection;
-      len = hsock->hostname ? strlen(hsock->hostname) : strlen(hsock->ip);
-      strncat(uh, hsock->hostname ? hsock->hostname : hsock->ip, len);
+      if (!strchr(entry->username, '@')) {
+       strncat(uh, "@", 1);
+       hsock = (SilcSocketConnection)entry->connection;
+       len = hsock->hostname ? strlen(hsock->hostname) : strlen(hsock->ip);
+       strncat(uh, hsock->hostname ? hsock->hostname : hsock->ip, len);
+      }
       
       SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
       
@@ -458,7 +471,7 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
       if (entry->userinfo)
        packet = 
          silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
-                                              status, 0, 5, 
+                                              status, ident, 5, 
                                               2, idp->data, idp->len,
                                               3, nh, strlen(nh),
                                               4, uh, strlen(uh),
@@ -468,22 +481,13 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
       else
        packet = 
          silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
-                                              status, 0, 4, 
+                                              status, ident, 4, 
                                               2, idp->data, idp->len,
                                               3, nh, strlen(nh),
                                               4, uh, strlen(uh),
                                               7, idle, 4);
-      
-    } else {
-      /* XXX */
-      packet = 
-       silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS, 
-                                            status, 0, 3, 
-                                            2, idp->data, idp->len,
-                                            3, entry->nickname, 
-                                            strlen(entry->nickname),
-                                            4, tmp, strlen(tmp)); /* XXX */
     }
+    
     silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
                            0, packet->data, packet->len, FALSE);
     
@@ -514,7 +518,9 @@ silc_server_command_whois_from_client(SilcServerCommandContext cmd)
   if (server->server_type == SILC_SERVER && 
       !cmd->pending && !server->standalone) {
     SilcBuffer tmpbuf;
+    unsigned short old_ident;
 
+    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);
 
@@ -530,6 +536,8 @@ silc_server_command_whois_from_client(SilcServerCommandContext cmd)
                                silc_server_command_whois, (void *)cmd);
     cmd->pending = TRUE;
 
+    silc_command_set_ident(cmd->payload, old_ident);
+
     silc_buffer_free(tmpbuf);
     ret = -1;
     goto out;
@@ -540,7 +548,7 @@ silc_server_command_whois_from_client(SilcServerCommandContext cmd)
 
   /* Get all clients matching that ID or nickname from local list */
   if (client_id) {
-    entry = silc_idlist_find_client_by_id(server->local_list, client_id);
+    entry = silc_idlist_find_client_by_id(server->local_list, client_id, NULL);
     if (entry) {
       clients = silc_calloc(1, sizeof(*clients));
       clients[0] = entry;
@@ -552,10 +560,11 @@ silc_server_command_whois_from_client(SilcServerCommandContext cmd)
                                                  &clients_count);
   }
   
-  /* If we are router we will check our global list as well. */
-  if (!clients && server->server_type == SILC_ROUTER) {
+  /* Check global list as well */
+  if (!clients) {
     if (client_id) {
-      entry = silc_idlist_find_client_by_id(server->global_list, client_id);
+      entry = silc_idlist_find_client_by_id(server->global_list, 
+                                           client_id, NULL);
       if (entry) {
        clients = silc_calloc(1, sizeof(*clients));
        clients[0] = entry;
@@ -622,7 +631,7 @@ silc_server_command_whois_from_server(SilcServerCommandContext cmd)
      send reply to the requesting server. */
 
   if (client_id) {
-    entry = silc_idlist_find_client_by_id(server->local_list, client_id);
+    entry = silc_idlist_find_client_by_id(server->local_list, client_id, NULL);
     if (entry) {
       clients = silc_calloc(1, sizeof(*clients));
       clients[0] = entry;
@@ -632,12 +641,17 @@ silc_server_command_whois_from_server(SilcServerCommandContext cmd)
     clients = silc_idlist_get_clients_by_nickname(server->local_list, 
                                                  nick, server_name,
                                                  &clients_count);
+    if (!clients)
+      clients = silc_idlist_get_clients_by_hash(server->local_list, 
+                                               nick, server->md5hash,
+                                               &clients_count);
   }
   
   /* If we are router we will check our global list as well. */
   if (!clients && server->server_type == SILC_ROUTER) {
     if (client_id) {
-      entry = silc_idlist_find_client_by_id(server->global_list, client_id);
+      entry = silc_idlist_find_client_by_id(server->global_list, 
+                                           client_id, NULL);
       if (entry) {
        clients = silc_calloc(1, sizeof(*clients));
        clients[0] = entry;
@@ -647,6 +661,10 @@ silc_server_command_whois_from_server(SilcServerCommandContext cmd)
       clients = silc_idlist_get_clients_by_nickname(server->global_list, 
                                                    nick, server_name,
                                                    &clients_count);
+      if (!clients)
+       clients = silc_idlist_get_clients_by_hash(server->global_list, 
+                                                 nick, server->md5hash,
+                                                 &clients_count);
     }
   }
 
@@ -708,56 +726,46 @@ SILC_SERVER_CMD_FUNC(whowas)
 {
 }
 
-SILC_SERVER_CMD_FUNC(identify)
-{
-  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
-  SilcServer server = cmd->server;
-  char *tmp, *nick = NULL, *server_name = NULL;
-  unsigned int argc, count = 0, len;
-  int use_id = FALSE;
-  SilcClientID *client_id = NULL;
-  SilcClientEntry entry;
-  SilcBuffer packet, idp;
+/******************************************************************************
 
-  SILC_LOG_DEBUG(("Start"));
+                              IDENTIFY Functions
 
-  argc = silc_argument_get_arg_num(cmd->args);
-  if (argc < 1) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
-                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-  if (argc > 3) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
-                                         SILC_STATUS_ERR_TOO_MANY_PARAMS);
-    goto out;
-  }
+******************************************************************************/
+
+static int
+silc_server_command_identify_parse(SilcServerCommandContext cmd,
+                                  SilcClientID **client_id,
+                                  char **nickname,
+                                  char **server_name,
+                                  int *count)
+{
+  unsigned char *tmp;
+  unsigned int len;
+  unsigned int argc = silc_argument_get_arg_num(cmd->args);
 
   /* If client ID is in the command it must be used instead of nickname */
   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
   if (!tmp) {
-
-    /* Get the nickname@server string and parse it. */
+    /* 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, "@");
-       nick = silc_calloc(len + 1, sizeof(char));
-       memcpy(nick, tmp, len);
-       server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
-       memcpy(server_name, tmp + len + 1, strlen(tmp) - len - 1);
+       *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 {
-       nick = strdup(tmp);
+       *nickname = strdup(tmp);
       }
     } else {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
                                            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-      goto out;
+      return FALSE;
     }
   } else {
     /* Command includes ID, use that */
-    client_id = silc_id_payload_parse_id(tmp, len);
-    use_id = TRUE;
+    *client_id = silc_id_payload_parse_id(tmp, len);
   }
 
   /* Get the max count of reply messages allowed */
@@ -766,84 +774,298 @@ SILC_SERVER_CMD_FUNC(identify)
     if (!tmp) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
                                            SILC_STATUS_ERR_TOO_MANY_PARAMS);
-      goto out;
+      if (*nickname)
+       silc_free(*nickname);
+      if (*server_name)
+       silc_free(*server_name);
+
+      return FALSE;
     }
-    count = atoi(tmp);
+    *count = atoi(tmp);
   }
 
-  /* Find client */
-  if (!use_id) {
-    entry = silc_idlist_find_client_by_nickname(server->local_list,
-                                               nick, NULL);
-    if (!entry)
-      entry = silc_idlist_find_client_by_hash(server->global_list,
-                                             nick, server->md5hash);
-  } else {
-    entry = silc_idlist_find_client_by_id(server->local_list, client_id);
-  }
+  return TRUE;
+}
 
-  /* If client was not found and if we are normal server and are connected
-     to a router we will make global query from the router. */
-  if (!entry && server->server_type == SILC_SERVER && !server->standalone &&
-      !cmd->pending) {
-    SilcBuffer buffer = cmd->packet->buffer;
-    
-    SILC_LOG_DEBUG(("Requesting identify from router"));
+static void
+silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
+                                       SilcClientEntry *clients,
+                                       unsigned int clients_count)
+{
+  SilcServer server = cmd->server;
+  char *tmp;
+  int i, count = 0, len;
+  SilcBuffer packet, idp;
+  SilcClientEntry entry;
+  SilcCommandStatus status;
+  unsigned short ident = silc_command_get_ident(cmd->payload);
+
+  status = SILC_STATUS_OK;
+  if (clients_count > 1)
+    status = SILC_STATUS_LIST_START;
+
+  for (i = 0; i < clients_count; i++) {
+    entry = clients[i];
+
+    if (count && i - 1 == count)
+      break;
+
+    if (clients_count > 2)
+      status = SILC_STATUS_LIST_ITEM;
+
+    if (clients_count > 1 && i == clients_count - 1)
+      status = SILC_STATUS_LIST_END;
+
+    /* Send IDENTIFY reply */
+    idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
+    tmp = silc_argument_get_first_arg(cmd->args, NULL);
     
+    /* XXX */
+    {
+      char nh[256], uh[256];
+      SilcSocketConnection hsock;
+
+      memset(uh, 0, sizeof(uh));
+      memset(nh, 0, sizeof(nh));
+      
+      strncat(nh, entry->nickname, strlen(entry->nickname));
+      if (!strchr(entry->nickname, '@')) {
+       strncat(nh, "@", 1);
+       len = entry->router ? strlen(entry->router->server_name) :
+         strlen(server->server_name);
+       strncat(nh, entry->router ? entry->router->server_name :
+               server->server_name, len);
+      }
+      
+      if (!entry->username) {
+       packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
+                                                     SILC_STATUS_OK, ident, 2,
+                                                     2, idp->data, idp->len, 
+                                                     3, nh, strlen(nh));
+      } else {
+       strncat(uh, entry->username, strlen(entry->username));
+       if (!strchr(entry->username, '@')) {
+         strncat(uh, "@", 1);
+         hsock = (SilcSocketConnection)entry->connection;
+         len = hsock->hostname ? strlen(hsock->hostname) : strlen(hsock->ip);
+         strncat(uh, hsock->hostname ? hsock->hostname : hsock->ip, len);
+       }
+      
+       packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
+                                                     SILC_STATUS_OK, ident, 3,
+                                                     2, idp->data, idp->len, 
+                                                     3, nh, strlen(nh),
+                                                     4, uh, strlen(uh));
+      }
+      
+      silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
+                             0, packet->data, packet->len, FALSE);
+      
+      silc_buffer_free(packet);
+      silc_buffer_free(idp);
+    }
+  }
+}
+
+static int
+silc_server_command_identify_from_client(SilcServerCommandContext cmd)
+{
+  SilcServer server = cmd->server;
+  char *nick = NULL, *server_name = NULL;
+  int count = 0, clients_count;
+  SilcClientID *client_id = NULL;
+  SilcClientEntry *clients = NULL, entry;
+  int ret = 0;
+
+  /* Parse the IDENTIFY request */
+  if (!silc_server_command_identify_parse(cmd, &client_id, &nick, 
+                                         &server_name, &count))
+    return 0;
+
+  /* Protocol dictates that we must always send the received IDENTIFY request
+     to our router if we are normal server, so let's do it now unless we
+     are standalone. We will not send any replies to the client until we
+     have received reply from the router. */
+  if (server->server_type == SILC_SERVER && 
+      !cmd->pending && !server->standalone) {
+    SilcBuffer tmpbuf;
+    unsigned short old_ident;
+
+    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);
+
     /* Send IDENTIFY command to our router */
-    silc_buffer_push(buffer, buffer->data - buffer->head);
-    silc_server_packet_forward(server, (SilcSocketConnection)
-                              server->router->connection,
-                              buffer->data, buffer->len, TRUE);
-    return;
+    silc_server_packet_send(server, (SilcSocketConnection)
+                           server->router->connection,
+                           SILC_PACKET_COMMAND, cmd->packet->flags,
+                           tmpbuf->data, tmpbuf->len, TRUE);
+
+    /* Reprocess this packet after received reply from router */
+    silc_server_command_pending(server, SILC_COMMAND_IDENTIFY, 
+                               silc_command_get_ident(cmd->payload),
+                               silc_server_command_identify, (void *)cmd);
+    cmd->pending = TRUE;
+
+    silc_command_set_ident(cmd->payload, old_ident);
+
+    silc_buffer_free(tmpbuf);
+    ret = -1;
+    goto out;
   }
 
-  /* If we are router we have checked our local list by nickname and our
-     global list by hash so far. It is possible that the client is still not
-     found and we'll check it from local list by hash. */
-  if (!entry && server->server_type == SILC_ROUTER)
-    entry = silc_idlist_find_client_by_hash(server->local_list,
-                                           nick, server->md5hash);
+  /* We are ready to process the command request. Let's search for the
+     requested client and send reply to the requesting client. */
 
-  if (!entry) {
-    /* The client definitely does not exist */
+  /* Get all clients matching that ID or nickname from local list */
+  if (client_id) {
+    entry = silc_idlist_find_client_by_id(server->local_list, client_id, NULL);
+    if (entry) {
+      clients = silc_calloc(1, sizeof(*clients));
+      clients[0] = entry;
+      clients_count = 1;
+    }
+  } else {
+    clients = silc_idlist_get_clients_by_nickname(server->local_list, 
+                                                 nick, server_name,
+                                                 &clients_count);
+  }
+  
+  /* Check global list as well */
+  if (!clients) {
+    if (client_id) {
+      entry = silc_idlist_find_client_by_id(server->global_list, 
+                                           client_id, NULL);
+      if (entry) {
+       clients = silc_calloc(1, sizeof(*clients));
+       clients[0] = entry;
+       clients_count = 1;
+      }
+    } else {
+      clients = silc_idlist_get_clients_by_nickname(server->global_list, 
+                                                   nick, server_name,
+                                                   &clients_count);
+    }
+  }
+  
+  if (!clients) {
+    /* Such a client really does not exist in the SILC network. */
     silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
                                         SILC_STATUS_ERR_NO_SUCH_NICK,
-                                        3, tmp, strlen(tmp));
+                                        3, nick, strlen(nick));
     goto out;
   }
 
-  /* Send IDENTIFY reply */
-  idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
-  tmp = silc_argument_get_first_arg(cmd->args, NULL);
-  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
-                                               SILC_STATUS_OK, 0, 2,
-                                               2, idp->data, idp->len, 
-                                               3, nick, strlen(nick));
-  if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
-    void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
-    silc_server_packet_send_dest(server, cmd->sock, 
-                                SILC_PACKET_COMMAND_REPLY, 0,
-                                id, cmd->packet->src_id_type,
-                                packet->data, packet->len, FALSE);
-    silc_free(id);
-  } else {
-    silc_server_packet_send(server, cmd->sock, 
-                           SILC_PACKET_COMMAND_REPLY, 0, 
-                           packet->data, packet->len, FALSE);
-  }
+  /* Send the command reply to the client */
+  silc_server_command_identify_send_reply(cmd, clients, clients_count);
 
-  silc_buffer_free(packet);
-  silc_buffer_free(idp);
+ out:
+  if (clients)
+    silc_free(clients);
   if (client_id)
     silc_free(client_id);
+  if (nick)
+    silc_free(nick);
+  if (server_name)
+    silc_free(server_name);
+
+  return ret;
+}
+
+static int
+silc_server_command_identify_from_server(SilcServerCommandContext cmd)
+{
+  SilcServer server = cmd->server;
+  char *nick = NULL, *server_name = NULL;
+  int count = 0, clients_count;
+  SilcClientID *client_id = NULL;
+  SilcClientEntry *clients = NULL, entry;
+  int ret = 0;
+
+  /* Parse the IDENTIFY request */
+  if (!silc_server_command_identify_parse(cmd, &client_id, &nick, 
+                                         &server_name, &count))
+    return 0;
+
+  /* Process the command request. Let's search for the requested client and
+     send reply to the requesting server. */
+
+  if (client_id) {
+    entry = silc_idlist_find_client_by_id(server->local_list, client_id, NULL);
+    if (entry) {
+      clients = silc_calloc(1, sizeof(*clients));
+      clients[0] = entry;
+      clients_count = 1;
+    }
+  } else {
+    clients = silc_idlist_get_clients_by_nickname(server->local_list, 
+                                                 nick, server_name,
+                                                 &clients_count);
+    if (!clients)
+      clients = silc_idlist_get_clients_by_hash(server->local_list, 
+                                               nick, server->md5hash,
+                                               &clients_count);
+  }
+  
+  /* If we are router we will check our global list as well. */
+  if (!clients && server->server_type == SILC_ROUTER) {
+    if (client_id) {
+      entry = silc_idlist_find_client_by_id(server->global_list, 
+                                           client_id, NULL);
+      if (entry) {
+       clients = silc_calloc(1, sizeof(*clients));
+       clients[0] = entry;
+       clients_count = 1;
+      }
+    } else {
+      clients = silc_idlist_get_clients_by_nickname(server->global_list, 
+                                                   nick, server_name,
+                                                   &clients_count);
+      if (!clients)
+       clients = silc_idlist_get_clients_by_hash(server->global_list, 
+                                                 nick, server->md5hash,
+                                                 &clients_count);
+    }
+  }
+
+  if (!clients) {
+    /* Such a client really does not exist in the SILC network. */
+    silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+                                        SILC_STATUS_ERR_NO_SUCH_NICK,
+                                        3, nick, strlen(nick));
+    goto out;
+  }
+
+  /* Send the command reply to the client */
+  silc_server_command_identify_send_reply(cmd, clients, clients_count);
 
  out:
+  if (clients)
+    silc_free(clients);
+  if (client_id)
+    silc_free(client_id);
   if (nick)
     silc_free(nick);
   if (server_name)
     silc_free(server_name);
-  silc_server_command_free(cmd);
+
+  return ret;
+}
+
+SILC_SERVER_CMD_FUNC(identify)
+{
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+  int ret;
+
+  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_IDENTIFY, cmd, 1, 3);
+
+  if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
+    ret = silc_server_command_identify_from_client(cmd);
+  else
+    ret = silc_server_command_identify_from_server(cmd);
+
+  if (!ret)
+    silc_server_command_free(cmd);
 }
 
 /* Checks string for bad characters and returns TRUE if they are found. */
@@ -995,7 +1217,8 @@ SILC_SERVER_CMD_FUNC(topic)
   channel_id = silc_id_payload_parse_id(tmp, tmp_len);
 
   /* Check whether the channel exists */
-  channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
+  channel = silc_idlist_find_channel_by_id(server->local_list, 
+                                          channel_id, NULL);
   if (!channel) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
                                          SILC_STATUS_ERR_NO_SUCH_CHANNEL);
@@ -1116,7 +1339,8 @@ SILC_SERVER_CMD_FUNC(invite)
   channel_id = silc_id_payload_parse_id(tmp, len);
 
   /* Check whether the channel exists */
-  channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
+  channel = silc_idlist_find_channel_by_id(server->local_list, 
+                                          channel_id, NULL);
   if (!channel) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
                                          SILC_STATUS_ERR_NO_SUCH_CHANNEL);
@@ -1141,7 +1365,7 @@ SILC_SERVER_CMD_FUNC(invite)
       if (chl->client == sender) {
        if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
          silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
-                                               SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+                                       SILC_STATUS_ERR_NO_CHANNEL_PRIV);
          goto out;
        }
        break;
@@ -1150,7 +1374,7 @@ SILC_SERVER_CMD_FUNC(invite)
 
   /* Find the connection data for the destination. If it is local we will
      send it directly otherwise we will send it to router for routing. */
-  dest = silc_idlist_find_client_by_id(server->local_list, dest_id);
+  dest = silc_idlist_find_client_by_id(server->local_list, dest_id, NULL);
   if (dest)
     dest_sock = (SilcSocketConnection)dest->connection;
   else
@@ -1441,7 +1665,8 @@ SILC_SERVER_CMD_FUNC(add_to_channel)
   client = (SilcClientEntry)cmd->sock->user_data;
 
   /* Get channel entry */
-  channel = silc_idlist_find_channel_by_name(server->local_list, channel_name);
+  channel = silc_idlist_find_channel_by_name(server->local_list, 
+                                            channel_name, NULL);
   if (channel) {
     /* Join the client to the channel by adding it to channel's user list.
        Add also the channel to client entry's channels list for fast cross-
@@ -1534,7 +1759,7 @@ static void silc_server_command_join_channel(SilcServer server,
      real easy. */
   if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
     void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
-    client = silc_idlist_find_client_by_id(server->local_list, id);
+    client = silc_idlist_find_client_by_id(server->local_list, id, NULL);
     if (!client) {
       /* XXX */
       SILC_LOG_ERROR(("Forwarded join command did not find the client who "
@@ -1665,26 +1890,13 @@ SILC_SERVER_CMD_FUNC(join)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  int argc, tmp_len;
+  int tmp_len;
   char *tmp, *channel_name = NULL, *cipher = NULL;
   SilcChannelEntry channel;
   unsigned int umode = 0;
   int created = FALSE;
 
-  SILC_LOG_DEBUG(("Start"));
-
-  /* Check number of parameters */
-  argc = silc_argument_get_arg_num(cmd->args);
-  if (argc < 1) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
-                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-  if (argc > 3) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
-                                         SILC_STATUS_ERR_TOO_MANY_PARAMS);
-    goto out;
-  }
+  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_JOIN, cmd, 1, 3);
 
   /* Get channel name */
   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
@@ -1706,7 +1918,8 @@ SILC_SERVER_CMD_FUNC(join)
   cipher = silc_argument_get_arg_type(cmd->args, 3, NULL);
 
   /* See if the channel exists */
-  channel = silc_idlist_find_channel_by_name(server->local_list, channel_name);
+  channel = silc_idlist_find_channel_by_name(server->local_list, 
+                                            channel_name, NULL);
   if (!channel) {
     /* Channel not found */
 
@@ -1747,7 +1960,7 @@ SILC_SERVER_CMD_FUNC(join)
       /* We are router and the channel does not seem exist so we will check
         our global list as well for the channel. */
       channel = silc_idlist_find_channel_by_name(server->global_list, 
-                                                channel_name);
+                                                channel_name, NULL);
       if (!channel) {
        /* Channel really does not exist, create it */
        channel = silc_server_create_new_channel(server, server->id, cipher, 
@@ -1922,7 +2135,8 @@ SILC_SERVER_CMD_FUNC(cmode)
   SILC_GET32_MSB(mode_mask, tmp_mask);
 
   /* Get channel entry */
-  channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
+  channel = silc_idlist_find_channel_by_id(server->local_list, 
+                                          channel_id, NULL);
   if (!channel) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
                                          SILC_STATUS_ERR_NO_SUCH_CHANNEL);
@@ -2278,7 +2492,8 @@ SILC_SERVER_CMD_FUNC(cumode)
   channel_id = silc_id_payload_parse_id(tmp_id, tmp_len);
 
   /* Get channel entry */
-  channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
+  channel = silc_idlist_find_channel_by_id(server->local_list, 
+                                          channel_id, NULL);
   if (!channel) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
                                          SILC_STATUS_ERR_NO_SUCH_CHANNEL);
@@ -2327,7 +2542,8 @@ SILC_SERVER_CMD_FUNC(cumode)
   client_id = silc_id_payload_parse_id(tmp_id, tmp_len);
 
   /* Get target client's entry */
-  target_client = silc_idlist_find_client_by_id(server->local_list, client_id);
+  target_client = silc_idlist_find_client_by_id(server->local_list, 
+                                               client_id, NULL);
   if (!target_client) {
     /* XXX If target client is not one of mine send to primary route */
   }
@@ -2476,7 +2692,7 @@ SILC_SERVER_CMD_FUNC(leave)
   id = silc_id_payload_parse_id(tmp, len);
 
   /* Get channel entry */
-  channel = silc_idlist_find_channel_by_id(server->local_list, id);
+  channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
   if (!channel) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
                                          SILC_STATUS_ERR_NO_SUCH_CHANNEL);
@@ -2587,7 +2803,7 @@ SILC_SERVER_CMD_FUNC(names)
   /* Check whether the channel exists. If we are normal server and the
      channel does not exist we will send this same command to our router
      which will know if the channel exists. */
-  channel = silc_idlist_find_channel_by_id(server->local_list, id);
+  channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
   if (!channel) {
     if (server->server_type == SILC_SERVER && !server->standalone) {
       /* XXX Send names command */
index e8583b015ecc25a3d38c38e6b186183bc2a111f7..a89124f370f63d5c14ff84ee70a9463f847cf184 100644 (file)
@@ -59,7 +59,7 @@ void silc_server_private_message(SilcServer server,
 
   /* If the destination belongs to our server we don't have to route
      the message anywhere but to send it to the local destination. */
-  client = silc_idlist_find_client_by_id(server->local_list, id);
+  client = silc_idlist_find_client_by_id(server->local_list, id, NULL);
   if (client) {
     /* It exists, now deliver the message to the destination */
     dst_sock = (SilcSocketConnection)client->connection;
@@ -125,21 +125,19 @@ void silc_server_private_message(SilcServer server,
                         "No such nickname: Private message not sent");
 }
 
-/* Relays received command reply packet to the correct destination. The
-   destination must be one of our locally connected client or the packet
-   will be ignored. This is called when server has forwarded one of
-   client's command request to router and router has now replied to the 
-   command. */
+/* Processes incoming command reply packet. The command reply packet may
+   be destined to one of our clients or it may directly for us. We will 
+   call the command reply routine after processing the packet. */
 
-void silc_server_packet_relay_command_reply(SilcServer server,
-                                           SilcSocketConnection sock,
-                                           SilcPacketContext *packet)
+void silc_server_command_reply(SilcServer server,
+                              SilcSocketConnection sock,
+                              SilcPacketContext *packet)
 {
   SilcBuffer buffer = packet->buffer;
-  SilcClientEntry client;
-  SilcClientID *id;
+  SilcClientEntry client = NULL;
   SilcSocketConnection dst_sock;
   SilcIDListData idata;
+  SilcClientID *id = NULL;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -148,42 +146,52 @@ void silc_server_packet_relay_command_reply(SilcServer server,
       sock->type != SILC_SOCKET_TYPE_ROUTER)
     return;
 
-  /* Destination must be client */
-  if (packet->dst_id_type != SILC_ID_CLIENT)
+  if (packet->dst_id_type == SILC_ID_CHANNEL)
     return;
 
-  /* Execute command reply locally for the command */
-  silc_server_command_reply_process(server, sock, buffer);
-
-  id = silc_id_str2id(packet->dst_id, SILC_ID_CLIENT);
-
-  /* Destination must be one of ours */
-  client = silc_idlist_find_client_by_id(server->local_list, id);
-  if (!client) {
-    SILC_LOG_ERROR(("Cannot relay command reply to unknown client"));
-    silc_free(id);
-    return;
+  if (packet->dst_id_type == SILC_ID_CLIENT) {
+    /* Destination must be one of ours */
+    id = silc_id_str2id(packet->dst_id, SILC_ID_CLIENT);
+    client = silc_idlist_find_client_by_id(server->local_list, id, NULL);
+    if (!client) {
+      SILC_LOG_ERROR(("Cannot process command reply to unknown client"));
+      silc_free(id);
+      return;
+    }
   }
 
-  /* Relay the packet to the client */
-
-  dst_sock = (SilcSocketConnection)client->connection;
-  silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len 
-                  + packet->dst_id_len + packet->padlen);
-
-  silc_packet_send_prepare(dst_sock, 0, 0, buffer->len);
-  silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
+  if (packet->dst_id_type == SILC_ID_SERVER) {
+    /* For now this must be for us */
+    if (SILC_ID_SERVER_COMPARE(packet->dst_id, server->id_string)) {
+      SILC_LOG_ERROR(("Cannot process command reply to unknown server"));
+      return;
+    }
+  }
 
-  idata = (SilcIDListData)client;
+  /* Execute command reply locally for the command */
+  silc_server_command_reply_process(server, sock, buffer);
 
-  /* Encrypt packet */
-  silc_packet_encrypt(idata->send_key, idata->hmac, dst_sock->outbuf, 
-                     buffer->len);
+  if (packet->dst_id_type == SILC_ID_CLIENT && client && id) {
+    /* Relay the packet to the client */
+    
+    dst_sock = (SilcSocketConnection)client->connection;
+    silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len 
+                    + packet->dst_id_len + packet->padlen);
+    
+    silc_packet_send_prepare(dst_sock, 0, 0, buffer->len);
+    silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
+    
+    idata = (SilcIDListData)client;
     
-  /* Send the packet */
-  silc_server_packet_send_real(server, dst_sock, TRUE);
+    /* Encrypt packet */
+    silc_packet_encrypt(idata->send_key, idata->hmac, dst_sock->outbuf, 
+                       buffer->len);
+    
+    /* Send the packet */
+    silc_server_packet_send_real(server, dst_sock, TRUE);
 
-  silc_free(id);
+    silc_free(id);
+  }
 }
 
 /* Process received channel message. The message can be originated from
@@ -209,7 +217,7 @@ void silc_server_channel_message(SilcServer server,
 
   /* Find channel entry */
   id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
-  channel = silc_idlist_find_channel_by_id(server->local_list, id);
+  channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
   if (!channel) {
     SILC_LOG_DEBUG(("Could not find channel"));
     goto out;
@@ -279,7 +287,7 @@ void silc_server_channel_key(SilcServer server,
     goto out;
 
   /* Get the channel entry */
-  channel = silc_idlist_find_channel_by_id(server->local_list, id);
+  channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
   if (!channel) {
     SILC_LOG_ERROR(("Received key for non-existent channel"));
     goto out;
@@ -598,6 +606,7 @@ void silc_server_new_id(SilcServer server, SilcSocketConnection sock,
   SilcSocketConnection router_sock;
   SilcIDPayload idp;
   SilcIdType id_type;
+  unsigned char *hash = NULL;
   void *id, *tmpid;
 
   SILC_LOG_DEBUG(("Processing new ID"));
@@ -669,15 +678,30 @@ void silc_server_new_id(SilcServer server, SilcSocketConnection sock,
                    sock->type == SILC_SOCKET_TYPE_SERVER ?
                    "Server" : "Router", sock->hostname));
     
-    /* Add the client to our local list. We are router and we keep
-       cell specific local database of all clients in the cell. */
-    silc_idlist_add_client(id_list, NULL, NULL, NULL, id, router, router_sock);
+    /* As a router we keep information of all global information in our global
+       list. Cell wide information however is kept in the local list. The
+       client is put to global list and we will take the hash value of the
+       Client ID and save it to the ID Cache system for fast searching in the 
+       future. */
+    hash = silc_calloc(sizeof(((SilcClientID *)id)->hash), 
+                      sizeof(unsigned char));
+    memcpy(hash, ((SilcClientID *)id)->hash, 
+          sizeof(((SilcClientID *)id)->hash));
+    silc_idlist_add_client(id_list, hash, NULL, NULL, id, router, router_sock);
 
+#if 0
+    /* XXX Adding two ID's with same IP number replaces the old entry thus
+       gives wrong route. Thus, now disabled until figured out a better way
+       to do this or when removed the whole thing. This could be removed
+       because entry->router->connection gives always the most optimal route
+       for the ID anyway (unless new routes (faster perhaps) are established
+       after receiving this ID, this we don't know however). */
     /* Add route cache for this ID */
     silc_server_route_add(silc_server_route_hash(
                          ((SilcClientID *)id)->ip.s_addr,
                          server->id->port), ((SilcClientID *)id)->ip.s_addr,
                          router);
+#endif
     break;
 
   case SILC_ID_SERVER:
@@ -686,16 +710,18 @@ void silc_server_new_id(SilcServer server, SilcSocketConnection sock,
                    sock->type == SILC_SOCKET_TYPE_SERVER ?
                    "Server" : "Router", sock->hostname));
     
-    /* Add the server to our local list. We are router and we keep
-       cell specific local database of all servers in the cell. */
+    /* As a router we keep information of all global information in our global
+       list. Cell wide information however is kept in the local list. */
     silc_idlist_add_server(id_list, NULL, 0, id, router, router_sock);
 
+#if 0
     /* Add route cache for this ID */
     silc_server_route_add(silc_server_route_hash(
                          ((SilcServerID *)id)->ip.s_addr,
                          ((SilcServerID *)id)->port), 
                          ((SilcServerID *)id)->ip.s_addr,
                          router);
+#endif
     break;
 
   case SILC_ID_CHANNEL:
@@ -760,13 +786,14 @@ void silc_server_remove_channel_user(SilcServer server,
 
   /* XXX routers should check server->global_list as well */
   /* Get channel entry */
-  channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
+  channel = silc_idlist_find_channel_by_id(server->local_list, 
+                                          channel_id, NULL);
   if (!channel)
     goto out;
   
   /* XXX routers should check server->global_list as well */
   /* Get client entry */
-  client = silc_idlist_find_client_by_id(server->local_list, client_id);
+  client = silc_idlist_find_client_by_id(server->local_list, client_id, NULL);
   if (!client)
     goto out;
 
@@ -877,7 +904,8 @@ void silc_server_notify(SilcServer server,
       goto out;
 
     /* Get channel entry */
-    channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
+    channel = silc_idlist_find_channel_by_id(server->local_list, 
+                                            channel_id, NULL);
     if (!channel) {
       silc_free(channel_id);
       goto out;
@@ -981,7 +1009,7 @@ void silc_server_new_channel_user(SilcServer server,
   silc_free(tmpid);
 
   /* Find the channel */
-  channel = silc_idlist_find_channel_by_id(id_list, channel_id);
+  channel = silc_idlist_find_channel_by_id(id_list, channel_id, NULL);
   if (!channel) {
     SILC_LOG_ERROR(("Received channel user for non-existent channel"));
     goto out;
@@ -998,7 +1026,7 @@ void silc_server_new_channel_user(SilcServer server,
   }
 
   /* Get client entry */
-  client = silc_idlist_find_client_by_id(id_list, client_id);
+  client = silc_idlist_find_client_by_id(id_list, client_id, NULL);
   if (!client) {
     /* This is new client to us, add entry to ID list */
     client = silc_idlist_add_client(id_list, NULL, NULL, NULL, 
index 80cee3bac93afe6668c32b7cd92bc0e11440ecad..481eb97580036d8870b3007074962e47aebdcb05 100644 (file)
@@ -271,8 +271,8 @@ silc_client_command_reply_whois_print(SilcClientCommandReplyContext cmd,
     cmd->client->ops->say(cmd->client, conn, "%s", buf);
 
   /* Notify application */
-  COMMAND_REPLY((ARGS, client_entry, nickname, 
-                username, realname, NULL, NULL));
+  COMMAND_REPLY((ARGS, client_entry, nickname, username, realname, 
+                NULL, NULL));
 }
 
 /* Received reply for WHOIS command. This maybe called several times