Renamed silc_server_get_client_resolve to silc_server_query_client,
authorPekka Riikonen <priikone@silcnet.org>
Thu, 19 Sep 2002 11:58:40 +0000 (11:58 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Thu, 19 Sep 2002 11:58:40 +0000 (11:58 +0000)
added server_query.[ch].

apps/silcd/Makefile.am
apps/silcd/command.c
apps/silcd/packet_receive.c
apps/silcd/server.c
apps/silcd/server.h
apps/silcd/server_query.c [new file with mode: 0644]
apps/silcd/server_query.h [new file with mode: 0644]
apps/silcd/serverincludes.h

index 3322c946c71ce69a95d1a4e0a521a8a4f75f8768..f0c3d8fe7b3480a00226ff2b58887f3910ccaa17 100644 (file)
@@ -33,6 +33,7 @@ silcd_SOURCES = \
        server_util.c \
        server_backup.c \
        serverconfig.c \
+       server_query.c \
        serverid.c \
        server_version.c
 
index d5353d81579bce89bd25763b054245d0ef17f3e3..eba9368cb30df7d0fdcab6313e2c47622a57dd19 100644 (file)
@@ -8,8 +8,7 @@
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
+  the Free Software Foundation; version 2 of the License.
   
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -1182,11 +1181,10 @@ silc_server_command_whois_process(SilcServerCommandContext cmd)
 SILC_SERVER_CMD_FUNC(whois)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
-  int ret = 0;
 
-  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WHOIS, cmd, 1, 3328);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WHOIS, cmd, 1, 256);
 
-  ret = silc_server_command_whois_process(cmd);
+  silc_server_command_whois_process(cmd);
   silc_server_command_free(cmd);
 }
 
@@ -2183,7 +2181,7 @@ SILC_SERVER_CMD_FUNC(identify)
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   int ret = 0;
 
-  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_IDENTIFY, cmd, 1, 3328);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_IDENTIFY, cmd, 1, 256);
 
   ret = silc_server_command_identify_process(cmd);
   silc_server_command_free(cmd);
@@ -2693,7 +2691,7 @@ SILC_SERVER_CMD_FUNC(invite)
     }
 
     /* Get the client entry */
-    dest = silc_server_get_client_resolve(server, dest_id, FALSE, &resolve);
+    dest = silc_server_query_client(server, dest_id, FALSE, &resolve);
     if (!dest) {
       if (server->server_type != SILC_SERVER || !resolve) {
        silc_server_command_send_status_reply(
@@ -3325,8 +3323,8 @@ static void silc_server_command_join_channel(SilcServer server,
     if (!client)
       return;
   } else {
-    client = silc_server_get_client_resolve(server, client_id, FALSE, 
-                                           &resolve);
+    client = silc_server_query_client(server, client_id, FALSE, 
+                                     &resolve);
     if (!client) {
       if (cmd->pending)
        goto out;
index bb362fe88ec9628a499d123ec13fe53b7b0f32ca..4589ab7c0c6b25d02a58cee8101c8df081c3fcc8 100644 (file)
@@ -3463,8 +3463,8 @@ void silc_server_resume_client(SilcServer server,
     idata = (SilcIDListData)client;
 
     /* Get entry to the client, and resolve it if we don't have it. */
-    detached_client = silc_server_get_client_resolve(server, client_id, FALSE,
-                                                    &resolved);
+    detached_client = silc_server_query_client(server, client_id, FALSE,
+                                              &resolved);
     if (!detached_client) {
       if (resolved) {
        /* The client info is being resolved. Reprocess this packet after
@@ -3508,7 +3508,7 @@ void silc_server_resume_client(SilcServer server,
        /* The client info is being resolved. Reprocess this packet after
           receiving the reply to the query. */
        SILC_LOG_DEBUG(("Resolving client info"));
-       silc_server_get_client_resolve(server, client_id, TRUE, NULL);
+       silc_server_query_client(server, client_id, TRUE, NULL);
        r = silc_calloc(1, sizeof(*r));
        if (!r)
          return;
index fa1d8d252a4bab97df1393ea137ff78641d4cc13..6c8156c0ee9ed8b9c168911783fb777a9bd9f82b 100644 (file)
@@ -4935,61 +4935,6 @@ SilcBuffer silc_server_get_client_channel_list(SilcServer server,
   return buffer;
 }
 
-/* Finds client entry by Client ID and if it is not found then resolves
-   it using WHOIS command. */
-
-SilcClientEntry silc_server_get_client_resolve(SilcServer server,
-                                              SilcClientID *client_id,
-                                              bool always_resolve,
-                                              bool *resolved)
-{
-  SilcClientEntry client;
-
-  if (resolved)
-    *resolved = FALSE;
-
-  client = silc_idlist_find_client_by_id(server->local_list, client_id,
-                                        TRUE, NULL);
-  if (!client) {
-    client = silc_idlist_find_client_by_id(server->global_list,
-                                          client_id, TRUE, NULL);
-    if (!client && server->server_type == SILC_ROUTER)
-      return NULL;
-  }
-
-  if (!client && server->standalone)
-    return NULL;
-
-  if (!client || !client->nickname || !client->username ||
-      always_resolve) {
-    SilcBuffer buffer, idp;
-
-    if (client) {
-      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,
-                                           4, idp->data, idp->len);
-    silc_server_packet_send(server, client ? client->router->connection :
-                           SILC_PRIMARY_ROUTE(server),
-                           SILC_PACKET_COMMAND, 0,
-                           buffer->data, buffer->len, FALSE);
-    silc_buffer_free(idp);
-    silc_buffer_free(buffer);
-
-    if (resolved)
-      *resolved = TRUE;
-
-    return NULL;
-  }
-
-  return client;
-}
-
 /* A timeout callback for the re-key. We will be the initiator of the
    re-key protocol. */
 
index 5757fefc31f488b45f5027f649d8cf7be7c1d5de..7694b528867c9dcb97280713c491be68b4ba0bf9 100644 (file)
@@ -233,10 +233,6 @@ SilcBuffer silc_server_get_client_channel_list(SilcServer server,
                                               bool get_private,
                                               bool get_secret,
                                               SilcBuffer *user_mode_list);
-SilcClientEntry silc_server_get_client_resolve(SilcServer server,
-                                              SilcClientID *client_id,
-                                              bool always_resolve,
-                                              bool *resolved);
 void silc_server_stderr(char *message);
 
 #endif
diff --git a/apps/silcd/server_query.c b/apps/silcd/server_query.c
new file mode 100644 (file)
index 0000000..f285baa
--- /dev/null
@@ -0,0 +1,679 @@
+/*
+
+  server_query.c
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 2002 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/* $Id$ */
+
+#include "serverincludes.h"
+#include "server_internal.h"
+
+typedef struct {
+  void *id;
+  SilcIdType id_type;
+} *SilcServerQueryID;
+
+typedef struct {
+  SilcUInt32 index;                /* Index to IDs */
+  bool from_cmd;                   /* TRUE if `index' is from command args,
+                                      otherwise from query->ids */
+  SilcStatus error;                /* The actual error */
+} *SilcServerQueryError;
+
+typedef struct {
+  SilcCommand querycmd;                    /* Query command */
+  SilcServerCommandContext cmd;            /* Command context for query */
+
+  char *nickname;                  /* Queried nickname */
+  char *nick_server;               /* Queried nickname's server */
+  char *server_name;               /* Queried server name */
+  char *channel_name;              /* Queried channel name */
+  SilcServerQueryID ids;           /* Queried IDs */
+  SilcUInt32 ids_count;                    /* number of queried IDs */
+  SilcUInt32 reply_count;          /* Requested reply count */
+  SilcDList attrs;                 /* Requested Attributes in WHOIS */
+
+  SilcServerQueryError errors;     /* Query errors */
+  SilcUInt32 errors_count;         /* number of errors */
+} *SilcServerQuery;
+
+void silc_server_query_free(SilcServerQuery query);
+bool silc_server_query_check_error(SilcServer server,
+                                  SilcServerQuery query,
+                                  SilcServerCommandReplyContext cmdr);
+void silc_server_query_send_error(SilcServer server,
+                                 SilcServerQuery query,
+                                 SilcStatus error, ...);
+void silc_server_query_add_error(SilcServer server,
+                                SilcServerQuery query,
+                                bool from_cmd,
+                                SilcUInt32 index,
+                                SilcStatus error);
+void silc_server_query_send_router(SilcServer server, SilcServerQuery query);
+void silc_server_query_send_router_reply(void *context, void *reply);
+void silc_server_query_parse(SilcServer server, SilcServerQuery query);
+void silc_server_query_process(SilcServer server, SilcServerQuery query);
+
+
+/* Free the query context structure and all allocated resources. */
+
+void silc_server_query_free(SilcServerQuery query)
+{
+  int i;
+
+  silc_server_command_free(query->cmd);
+
+  silc_free(query->nickname);
+  silc_free(query->nick_server);
+  silc_free(query->server_name);
+  silc_free(query->channel_name);
+
+  for (i = 0; i < query->ids_count; i++)
+    silc_free(query->ids[i].id);
+  silc_free(query->ids);
+
+  if (query->attrs)
+    silc_attribute_payload_list_free(query->attrs);
+
+  silc_free(query->errors);
+
+  memset(query, 'F', sizeof(*query));
+  silc_free(query);
+}
+
+/* Check whether command reply contained error, and reply the error to
+   the original sender if it occurred. */
+
+bool silc_server_query_check_error(SilcServer server,
+                                  SilcServerQuery query,
+                                  SilcServerCommandReplyContext cmdr)
+{
+  if (!cmdr)
+    return FALSE;
+
+  if (!silc_command_get_status(cmdr->payload, NULL, NULL)) {
+    SilcBuffer buffer;
+
+    /* Send the same command reply payload which contains the error */
+    silc_command_set_command(cmdr->payload, query->querycmd);
+    silc_command_set_ident(cmdr->payload,
+                          silc_command_get_ident(query->cmd->payload));
+    buffer = silc_command_payload_encode_payload(cmdr->payload);
+    silc_server_packet_send(server, query->cmd->sock,
+                           SILC_PACKET_COMMAND_REPLY, 0, 
+                           buffer->data, buffer->len, FALSE);
+    silc_buffer_free(buffer);
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+/* Send error reply indicated by the `error' to the original sender of
+   the query. */
+
+void silc_server_query_send_error(SilcServer server,
+                                 SilcServerQuery query,
+                                 SilcStatus error, ...)
+{
+  va_list va;
+  SilcBuffer packet;
+  unsigned char *data = NULL;
+  SilcUInt32 data_len = 0, data_type = 0, argc = 0;
+
+  va_start(va, error);
+  data_type = va_arg(va, SilcUInt32);
+  if (data_type) {
+    argc = 1;
+    data = va_arg(va, unsigned char *);
+    data_len = va_arg(va, SilcUInt32);
+  }
+
+  /* Send the command reply with error */
+  packet = silc_command_reply_payload_encode_va(
+                              query->querycmd, error, 0,
+                              silc_command_get_ident(query->cmd->payload),
+                              argc, data_type, data, data_len);
+  silc_server_packet_send(server, query->cmd->sock,
+                         SILC_PACKET_COMMAND_REPLY, 0, 
+                         packet->data, packet->len, FALSE);
+
+  silc_buffer_free(packet);
+  va_end(va);
+}
+
+/* Add error to error list.  Multiple errors may occur during the query
+   processing and this function can be used to add one error.  The
+   `type_index' is the index to the command context which includes the
+   argument which caused the error. */
+
+void silc_server_query_add_error(SilcServer server,
+                                SilcServerQuery query,
+                                bool from_cmd,
+                                SilcUInt32 index,
+                                SilcStatus error)
+{
+  query->errors = silc_realloc(query->errors, sizeof(*query->errors) *
+                              (query->errors_count + 1));
+  if (!query->errors)
+    return;
+  query->errors[query->errors_count].index = index;
+  query->errors[query->errors_count].from_cmd = from_cmd;
+  query->errors[query->errors_count].error = error;
+  query->errors_count++;
+}
+
+/* Processes query as command.  The `query' is the command that is
+   being processed indicated by the `cmd'.  The `query' can be one of
+   the following: SILC_COMMAND_WHOIS, SILC_COMMAND_WHOWAS or
+   SILC_COMMAND_IDENTIFY.  This function handles the reply sending
+   to the entity who sent this query to us automatically.  Returns
+   TRUE if the query is being processed or FALSE on error. */
+
+bool silc_server_query_command(SilcServer server, SilcCommand querycmd,
+                              SilcServerCommandContext cmd)
+{
+  SilcServerQuery query;
+
+  switch (querycmd) {
+
+  case SILC_COMMAND_WHOIS:
+    {
+      query = silc_calloc(1, sizeof(*query));
+      query->querycmd = querycmd;
+      query->cmd = silc_server_command_dup(cmd);
+
+      /* If we are normal server and query contains nickname, send it
+        directly to router. */
+      if (server->server_type == SILC_SERVER && !server->standalone &&
+         silc_argument_get_arg_type(cmd->args, 1, NULL)) {
+       silc_server_query_send_router(server, query);
+       break;
+      }
+
+      /* Now parse the WHOIS query */
+      silc_server_query_parse(server, query);
+    }
+    break;
+
+  case SILC_COMMAND_WHOWAS:
+    {
+      query = silc_calloc(1, sizeof(*query));
+      query->querycmd = querycmd;
+      query->cmd = silc_server_command_dup(cmd);
+
+      /* WHOWAS query is always sent to router if we are normal server */
+      if (server->server_type == SILC_SERVER && !server->standalone) {
+       silc_server_query_send_router(server, query);
+       break;
+      }
+
+      /* Now parse the WHOWAS query */
+      silc_server_query_parse(server, query);
+    }
+    break;
+
+  case SILC_COMMAND_IDENTIFY:
+    {
+      query = silc_calloc(1, sizeof(*query));
+      query->querycmd = querycmd;
+      query->cmd = silc_server_command_dup(cmd);
+
+      /* If we are normal server and query does not contain IDs, send it
+        directly to router (it contains nickname, server name or channel
+        name). */
+      if (server->server_type == SILC_SERVER && !server->standalone &&
+         !silc_argument_get_arg_type(cmd->args, 5, NULL)) {
+       silc_server_query_send_router(server, query);
+       break;
+      }
+
+      /* Now parse the IDENTIFY query */
+      silc_server_query_parse(server, query);
+    }
+    break;
+
+  default:
+    SILC_LOG_ERROR(("Bad query using %d command", querycmd));
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/* Send the received query to our primary router since we could not
+   handle the query directly.  We will reprocess the query after our
+   router replies back. */
+
+void silc_server_query_send_router(SilcServer server, SilcServerQuery query)
+{
+  SilcBuffer tmpbuf;
+  SilcUInt16 old_ident;
+
+  /* Send WHOIS command to our router */
+  old_ident = silc_command_get_ident(query->cmd->payload);
+  silc_command_set_ident(query->cmd->payload, ++server->cmd_ident);
+  tmpbuf = silc_command_payload_encode_payload(query->cmd->payload);
+  silc_server_packet_send(server, 
+                         SILC_PRIMARY_ROUTE(server),
+                         SILC_PACKET_COMMAND, 0,
+                         tmpbuf->data, tmpbuf->len, TRUE);
+  silc_command_set_ident(query->cmd->payload, old_ident);
+  silc_buffer_free(tmpbuf);
+
+  /* Continue parsing the query after received reply from router */
+  silc_server_command_pending(server, query->querycmd, server->cmd_ident,
+                             silc_server_query_send_router_reply, query);
+}
+
+/* Reply callback called after primary router has replied to our initial
+   sending of the query to it.  We will proceed the query in this function. */
+
+void silc_server_query_send_router_reply(void *context, void *reply)
+{
+  SilcServerQuery query = context;
+  SilcServer server = query->cmd->server;
+
+  /* Check if router sent error reply */
+  if (!silc_server_query_check_error(server, query, reply)) {
+    silc_server_query_free(query);
+    return;
+  }
+
+  /* Continue with parsing */
+  silc_server_query_parse(server, query);
+}
+
+/* Parse the command query and start processing the queries in detail. */
+
+void silc_server_query_parse(SilcServer server, SilcServerQuery query)
+{
+  SilcServerCommandContext cmd = query->cmd;
+  unsigned char *tmp;
+  SilcUInt32 tmp_len, argc = silc_argument_get_arg_num(cmd->args);
+  void *id;
+  SilcIdType id_type;
+  int i;
+
+  switch (query->querycmd) {
+
+  case SILC_COMMAND_WHOIS:
+    {
+      /* Get Client IDs if present. Take IDs always instead of nickname. */
+      tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
+      if (!tmp) {
+
+       /* Get nickname */
+       tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+       if (!tmp) {
+         silc_server_query_send_error(server, query,
+                                      SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
+         silc_server_query_free(query);
+         return;
+       }
+
+       /* Get the nickname@server string and parse it */
+       if (!silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server)) {
+         silc_server_query_send_error(server, query,
+                                      SILC_STATUS_ERR_BAD_NICKNAME, 0);
+         silc_server_query_free(query);
+         return;
+       }
+
+      } else {
+       /* Parse the IDs included in the query */
+       query->ids = silc_calloc(argc, sizeof(*query->ids));
+
+       for (i = 0; i < argc; i++) {
+         tmp = silc_argument_get_arg_type(cmd->args, i + 4, &tmp_len);
+         if (!tmp)
+           continue;
+
+         id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+         if (!id) {
+           silc_server_query_add_error(server, query, TRUE, i + 4,
+                                       SILC_STATUS_ERR_BAD_CLIENT_ID);
+           continue;
+         }
+
+         query->ids[query->ids_count].id = id;
+         query->ids[query->ids_count].id_type = SILC_ID_CLIENT;
+         query->ids_count++;
+       }
+      }
+
+      /* Get the max count of reply messages allowed */
+      tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+      if (tmp && tmp_len == sizeof(SilcUInt32))
+       SILC_GET32_MSB(query->reply_count, tmp);
+
+      /* Get requested attributes if set */
+      tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
+      if (tmp)
+       query->attrs = silc_attribute_payload_parse_list(tmp, tmp_len);
+    }
+    break;
+
+  case SILC_COMMAND_WHOWAS:
+    {
+      /* Get nickname */
+      tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+      if (!tmp) {
+       silc_server_query_send_error(server, query,
+                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
+       silc_server_query_free(query);
+       return;
+      }
+
+      /* Get the nickname@server string and parse it */
+      if (!silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server)) {
+       silc_server_query_send_error(server, query,
+                                    SILC_STATUS_ERR_BAD_NICKNAME, 0);
+       silc_server_query_free(query);
+       return;
+      }
+
+      /* Get the max count of reply messages allowed */
+      tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+      if (tmp && tmp_len == sizeof(SilcUInt32))
+       SILC_GET32_MSB(query->reply_count, tmp);
+    }
+    break;
+
+  case SILC_COMMAND_IDENTIFY:
+    {
+      /* Get IDs if present. Take IDs always instead of names. */
+      tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
+      if (!tmp) {
+
+       /* Try get nickname */
+       tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+       if (tmp) {
+         /* Get the nickname@server string and parse it */
+         if (!silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server))
+           silc_server_query_add_error(server, query, TRUE, 1,
+                                       SILC_STATUS_ERR_BAD_NICKNAME);
+       }
+
+       /* Try get server name */
+       tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+       if (tmp)
+         query->server_name = silc_memdup(tmp, tmp_len);
+
+       /* Get channel name */
+       tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
+       if (tmp)
+         query->channel_name = silc_memdup(tmp, tmp_len);
+
+      } else {
+       /* Parse the IDs included in the query */
+       query->ids = silc_calloc(argc, sizeof(*query->ids));
+
+       for (i = 0; i < argc; i++) {
+         tmp = silc_argument_get_arg_type(cmd->args, i + 5, &tmp_len);
+         if (!tmp)
+           continue;
+
+         id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
+         if (!id) {
+           silc_server_query_add_error(server, query, TRUE, i + 5,
+                                       SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+           continue;
+         }
+
+         query->ids[query->ids_count].id = id;
+         query->ids[query->ids_count].id_type = id_type;
+         query->ids_count++;
+       }
+      }
+
+      /* Get the max count of reply messages allowed */
+      tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
+      if (tmp && tmp_len == sizeof(SilcUInt32))
+       SILC_GET32_MSB(query->reply_count, tmp);
+    }
+    break;
+  }
+
+  /* Start processing the query information */
+  silc_server_query_process(server, query);
+}
+
+/* Processes the parsed query.  This does the actual finding of the
+   queried information and prepares for sending reply to the original
+   sender of the query command.  It is guaranteed that this function
+   (which may be slow) is called only once for entire query. */
+
+void silc_server_query_process(SilcServer server, SilcServerQuery query)
+{
+  SilcServerCommandContext cmd = query->cmd;
+  bool check_global = FALSE;
+  void *entry;
+  SilcClientEntry *clients = NULL;
+  SilcChannelEntry *channels = NULL;
+  SilcServerEntry *servers = NULL;
+  SilcUInt32 clients_count = 0, channels_count = 0, servers_count = 0;
+  int i;
+
+  /* Check global lists if query is coming from client or we are not
+     normal server (we know global information). */
+  if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
+    check_global = TRUE;
+  else if (server->server_type != SILC_SERVER)
+    check_global = TRUE;
+
+  if (query->nickname) {
+    /* Get all clients matching nickname from local list */
+    if (!silc_idlist_get_clients_by_hash(server->local_list, 
+                                        query->nickname, server->md5hash,
+                                        &clients, &clients_count))
+      silc_idlist_get_clients_by_nickname(server->local_list, 
+                                         query->nickname,
+                                         query->nick_server,
+                                         &clients, &clients_count);
+
+    /* Check global list as well */
+    if (check_global) {
+      if (!silc_idlist_get_clients_by_hash(server->global_list, 
+                                          query->nickname, server->md5hash,
+                                          &clients, &clients_count))
+       silc_idlist_get_clients_by_nickname(server->global_list, 
+                                           query->nickname,
+                                           query->nick_server,
+                                           &clients, &clients_count);
+    }
+
+    if (!clients)
+      silc_server_query_add_error(server, query, TRUE, 1,
+                                 SILC_STATUS_ERR_NO_SUCH_NICK);
+  }
+
+  if (query->server_name) {
+    /* Find server by name */
+    entry = silc_idlist_find_server_by_name(server->local_list,
+                                           query->server_name, TRUE, NULL);
+    if (!entry && check_global)
+      entry = silc_idlist_find_server_by_name(server->global_list,
+                                             query->server_name, TRUE, NULL);
+    if (entry) {
+      servers = silc_realloc(servers, sizeof(*servers) * (servers_count + 1));
+      servers[servers_count++] = (SilcServerEntry)entry;
+    }
+
+    if (!servers)
+      silc_server_query_add_error(server, query, TRUE, 2,
+                                 SILC_STATUS_ERR_NO_SUCH_SERVER);
+  }
+
+  if (query->channel_name) {
+    /* Find channel by name */
+    entry = silc_idlist_find_channel_by_name(server->local_list,
+                                            query->channel_name, NULL);
+    if (!entry && check_global)
+      entry = silc_idlist_find_channel_by_name(server->global_list,
+                                              query->channel_name, NULL);
+    if (entry) {
+      channels = silc_realloc(channels, sizeof(*channels) * 
+                             (channels_count + 1));
+      channels[channels_count++] = (SilcChannelEntry)entry;
+    }
+
+    if (!channels)
+      silc_server_query_add_error(server, query, TRUE, 3,
+                                 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
+  }
+
+  if (query->ids_count) {
+    /* Find entries by the queried IDs */
+    for (i = 0; i < query->ids_count; i++) {
+      void *id = query->ids[i].id;
+      if (!id)
+       continue;
+
+      switch (query->ids[i].id_type) {
+
+      case SILC_ID_CLIENT:
+       /* Get client entry */
+       entry = silc_idlist_find_client_by_id(server->local_list, 
+                                             id, TRUE, NULL);
+       if (!entry && check_global)
+         entry = silc_idlist_find_client_by_id(server->global_list, 
+                                               id, TRUE, NULL);
+       if (!entry) {
+         silc_server_query_add_error(server, query, FALSE, i,
+                                     SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
+         continue;
+       }
+
+       clients = silc_realloc(clients, sizeof(*clients) * 
+                              (clients_count + 1));
+       clients[clients_count++] = (SilcClientEntry)entry;
+       break;
+
+      case SILC_ID_SERVER:
+       /* Get server entry */
+       entry = silc_idlist_find_server_by_id(server->local_list, 
+                                             id, TRUE, NULL);
+       if (!entry && check_global)
+         entry = silc_idlist_find_server_by_id(server->global_list, 
+                                               id, TRUE, NULL);
+       if (!entry) {
+         silc_server_query_add_error(server, query, FALSE, i,
+                                     SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
+         continue;
+       }
+
+       servers = silc_realloc(servers, sizeof(*servers) * 
+                              (servers_count + 1));
+       servers[servers_count++] = (SilcServerEntry)entry;
+       break;
+
+      case SILC_ID_CHANNEL:
+       /* Get channel entry */
+       entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
+       if (!entry && check_global)
+         entry = silc_idlist_find_channel_by_id(server->global_list, id,
+                                                NULL);
+       if (!entry) {
+         silc_server_query_add_error(server, query, FALSE, i,
+                                     SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
+         continue;
+       }
+
+       channels = silc_realloc(channels, sizeof(*channels) * 
+                               (channels_count + 1));
+       channels[channels_count++] = (SilcChannelEntry)entry;
+       break;
+
+      default:
+       break;
+      }
+    }
+  }
+
+  /* If nothing was found, then just send the errors */
+  if (!clients && !channels && !servers) {
+
+    silc_server_query_free(query);
+    return;
+  }
+
+  /* Now process all found information and if necessary do some more
+     querying. */
+
+}
+
+/* Find client by the Client ID indicated by the `client_id', and if not
+   found then query it by using WHOIS command.  The client information
+   is also resolved if the cached information is incomplete or if the
+   `always_resolve' is set to TRUE.  The indication whether requested
+   client was being resolved is saved into `resolved'.  If the client
+   is not being resolved its entry is returned by this function.  NULL
+   is returned if client is resolved. */
+
+SilcClientEntry silc_server_query_client(SilcServer server,
+                                        const SilcClientID *client_id,
+                                        bool always_resolve,
+                                        bool *resolved)
+{
+  SilcClientEntry client;
+
+  if (resolved)
+    *resolved = FALSE;
+
+  client = silc_idlist_find_client_by_id(server->local_list,
+                                        (SilcClientID *)client_id,
+                                        TRUE, NULL);
+  if (!client) {
+    client = silc_idlist_find_client_by_id(server->global_list,
+                                          (SilcClientID *)client_id,
+                                          TRUE, NULL);
+    if (!client && server->server_type == SILC_ROUTER)
+      return NULL;
+  }
+
+  if (!client && server->standalone)
+    return NULL;
+
+  if (!client || !client->nickname || !client->username ||
+      always_resolve) {
+    SilcBuffer buffer, idp;
+
+    if (client) {
+      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,
+                                           4, idp->data, idp->len);
+    silc_server_packet_send(server, client ? client->router->connection :
+                           SILC_PRIMARY_ROUTE(server),
+                           SILC_PACKET_COMMAND, 0,
+                           buffer->data, buffer->len, FALSE);
+    silc_buffer_free(idp);
+    silc_buffer_free(buffer);
+
+    if (resolved)
+      *resolved = TRUE;
+
+    return NULL;
+  }
+
+  return client;
+}
diff --git a/apps/silcd/server_query.h b/apps/silcd/server_query.h
new file mode 100644 (file)
index 0000000..4c0c868
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+
+  server_query.c
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 2002 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SERVER_QUERY_H
+#define SERVER_QUERY_H
+
+/* Processes query as command.  The `query' is the command that is
+   being processed indicated by the `cmd'.  The `query' can be one of
+   the following: SILC_COMMAND_WHOIS, SILC_COMMAND_WHOWAS or
+   SILC_COMMAND_IDENTIFY.  This function handles the reply sending
+   to the entity who sent this query to us automatically.  Returns
+   TRUE if the query is being processed or FALSE on error. */
+bool silc_server_query_command(SilcServer server, SilcCommand querycmd,
+                              SilcServerCommandContext cmd);
+
+/* Find client by the Client ID indicated by the `client_id', and if not
+   found then query it by using WHOIS command.  The client information
+   is also resolved if the cached information is incomplete or if the
+   `always_resolve' is set to TRUE.  The indication whether requested
+   client was being resolved is saved into `resolved'.  If the client
+   is not being resolved its entry is returned by this function.  NULL
+   is returned if client is resolved.  If the client was resovled the
+   caller may attach to the query by using silc_server_command_pending
+   function.  The server->cmd_ident includes the query identifier. */
+SilcClientEntry silc_server_query_client(SilcServer server,
+                                        const SilcClientID *client_id,
+                                        bool always_resolve,
+                                        bool *resolved);
+
+#endif /* SERVER_QUERY_H */
index accbba71f5eaaafa90780ead5b47e2c9d9b4ff2f..fede33164e63d5a84f82b158b3c85f90858e5960 100644 (file)
@@ -41,6 +41,7 @@ typedef struct SilcServerStruct *SilcServer;
 #include "protocol.h"
 #include "command.h"
 #include "command_reply.h"
+#include "server_query.h"
 #include "silcd.h"
 #include "server_backup.h"