updates
[runtime.git] / apps / silcd / command_reply.c
index 48e906cdeb2a6a1843646065104a96d974e86416..853a52ff79dd3c372d188be634ac140c3a30b280 100644 (file)
 #include "server_internal.h"
 #include "command_reply.h"
 
+#define COMMAND_CHECK_STATUS                                             \
+do {                                                                     \
+  SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); \
+  if (status != SILC_STATUS_OK) {                                        \
+    silc_server_command_reply_free(cmd);                                 \
+    return;                                                              \
+  }                                                                      \
+} while(0)
+
+#define COMMAND_CHECK_STATUS_LIST                                        \
+do {                                                                     \
+  SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); \
+  if (status != SILC_STATUS_OK &&                                        \
+      status != SILC_STATUS_LIST_START &&                                \
+      status != SILC_STATUS_LIST_ITEM &&                                 \
+      status != SILC_STATUS_LIST_END) {                                          \
+    silc_server_command_reply_free(cmd);                                 \
+    return;                                                              \
+  }                                                                      \
+} while(0)
+
 /* Server command reply list. Not all commands have reply function as
    they are never sent by server. More maybe added later if need appears. */
 SilcServerCommandReply silc_command_reply_list[] =
 {
   SILC_SERVER_CMD_REPLY(join, JOIN),
+  SILC_SERVER_CMD_REPLY(identify, WHOIS),
   SILC_SERVER_CMD_REPLY(identify, IDENTIFY),
 
   { NULL, 0 },
@@ -39,8 +61,11 @@ void silc_server_command_reply_process(SilcServer server,
                                       SilcSocketConnection sock,
                                       SilcBuffer buffer)
 {
+  SilcServerCommandReply *cmd;
   SilcServerCommandReplyContext ctx;
   SilcCommandPayload payload;
+  SilcCommand command;
+  unsigned short ident;
 
   /* Get command reply payload from packet */
   payload = silc_command_payload_parse(buffer);
@@ -57,12 +82,24 @@ void silc_server_command_reply_process(SilcServer server,
   ctx->sock = sock;
   ctx->payload = payload;
   ctx->args = silc_command_get_args(ctx->payload);
+  ident = silc_command_get_ident(ctx->payload);
       
   /* Check for pending commands and mark to be exeucted */
-  SILC_SERVER_COMMAND_CHECK_PENDING(ctx);
-  
+  silc_server_command_pending_check(ctx, silc_command_get(ctx->payload),
+                                   ident);
+
   /* Execute command reply */
-  SILC_SERVER_COMMAND_REPLY_EXEC(ctx);
+  command = silc_command_get(ctx->payload);
+  for (cmd = silc_command_reply_list; cmd->cb; cmd++)
+    if (cmd->cmd == command)
+      break;
+
+  if (cmd == NULL) {
+    silc_free(ctx);
+    return;
+  }
+
+  cmd->cb(ctx);
 }
 
 /* Free command reply context and its internals. */
@@ -75,56 +112,69 @@ void silc_server_command_reply_free(SilcServerCommandReplyContext cmd)
   }
 }
 
-/* Received reply for forwarded JOIN command. Router has created or joined
-   the client to the channel. We save some channel information locally
-   for future use. */
+/* Caches the received WHOIS information. If we are normal server currently
+   we cache global information only for short period of time.  If we are
+   router we want to cache them a bit longer since we can receive information
+   if any of the information becomes invalid. Normal server cannot receive
+   that information. Returns FALSE if something was wrong with the reply. */
 
-SILC_SERVER_CMD_REPLY_FUNC(join)
+static char
+silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
+{
+  int len, id_len;
+  unsigned char *id_data;
+  char *nickname, *username, *realname;
+  SilcClientID *client_id;
+
+  id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
+  nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
+  username = silc_argument_get_arg_type(cmd->args, 4, &len);
+  realname = silc_argument_get_arg_type(cmd->args, 5, &len);
+  if (!id_data || !nickname || !username || !realname) 
+    return FALSE;
+
+  client_id = silc_id_payload_parse_id(id_data, id_len);
+
+
+  return TRUE;
+}
+
+/* Reiceved reply for WHOIS command. We sent the whois request to our
+   primary router, if we are normal server, and thus has now received reply
+   to the command. We will figure out what client originally sent us the
+   command and will send the reply to it.  If we are router we will figure
+   out who server sent us the command and send reply to that one. */
+
+SILC_SERVER_CMD_REPLY_FUNC(whois)
 {
   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
   SilcServer server = cmd->server;
   SilcCommandStatus status;
-  SilcChannelID *id;
-  SilcChannelEntry entry;
-  unsigned int len;
-  unsigned char *id_string;
-  char *channel_name, *tmp;
 
   SILC_LOG_DEBUG(("Start"));
 
-  tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
-  SILC_GET16_MSB(status, tmp);
-  if (status != SILC_STATUS_OK)
-    goto out;
+  COMMAND_CHECK_STATUS_LIST;
 
-  /* Get channel name */
-  tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
-  if (!tmp)
-    goto out;
+  /* Process one identify reply */
+  if (status == SILC_STATUS_OK) {
 
-  /* Get channel ID */
-  id_string = silc_argument_get_arg_type(cmd->args, 3, &len);
-  if (!id_string)
-    goto out;
+  }
 
-  channel_name = strdup(tmp);
+  if (status == SILC_STATUS_LIST_START) {
 
-  /* Add the channel to our local list. */
-  id = silc_id_payload_parse_id(id_string, len);
-  entry = silc_idlist_add_channel(server->local_list, channel_name, 
-                                 SILC_CHANNEL_MODE_NONE, id, 
-                                 server->id_entry->router, NULL);
-  if (!entry) {
-    silc_free(channel_name);
-    silc_free(id);
-    goto out;
   }
 
-  entry->global_users = TRUE;
+  if (status == SILC_STATUS_LIST_ITEM) {
 
-  /* Execute pending JOIN command so that the client who originally
-     wanted to join the channel will be joined after all. */
-  SILC_SERVER_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_JOIN);
+  }
+
+  if (status == SILC_STATUS_LIST_END) {
+
+  }
+
+  /* Execute pending IDENTIFY command so that the client who originally
+     requested the identify information will get it after all. */
+  SILC_SERVER_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_IDENTIFY);
 
  out:
   silc_server_command_reply_free(cmd);
@@ -143,9 +193,7 @@ SILC_SERVER_CMD_REPLY_FUNC(identify)
 
   SILC_LOG_DEBUG(("Start"));
 
-  SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
-  if (status != SILC_STATUS_OK)
-    goto out;
+  COMMAND_CHECK_STATUS_LIST;
 
   /* Process one identify reply */
   if (status == SILC_STATUS_OK) {
@@ -173,6 +221,10 @@ SILC_SERVER_CMD_REPLY_FUNC(identify)
 
   }
 
+  if (status == SILC_STATUS_LIST_ITEM) {
+
+  }
+
   if (status == SILC_STATUS_LIST_END) {
 
   }
@@ -184,3 +236,55 @@ SILC_SERVER_CMD_REPLY_FUNC(identify)
  out:
   silc_server_command_reply_free(cmd);
 }
+
+/* Received reply for forwarded JOIN command. Router has created or joined
+   the client to the channel. We save some channel information locally
+   for future use. */
+
+SILC_SERVER_CMD_REPLY_FUNC(join)
+{
+  SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
+  SilcServer server = cmd->server;
+  SilcCommandStatus status;
+  SilcChannelID *id;
+  SilcChannelEntry entry;
+  unsigned int len;
+  unsigned char *id_string;
+  char *channel_name, *tmp;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  COMMAND_CHECK_STATUS;
+
+  /* Get channel name */
+  tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
+  if (!tmp)
+    goto out;
+
+  /* Get channel ID */
+  id_string = silc_argument_get_arg_type(cmd->args, 3, &len);
+  if (!id_string)
+    goto out;
+
+  channel_name = strdup(tmp);
+
+  /* Add the channel to our local list. */
+  id = silc_id_payload_parse_id(id_string, len);
+  entry = silc_idlist_add_channel(server->local_list, channel_name, 
+                                 SILC_CHANNEL_MODE_NONE, id, 
+                                 server->id_entry->router, NULL);
+  if (!entry) {
+    silc_free(channel_name);
+    silc_free(id);
+    goto out;
+  }
+
+  entry->global_users = TRUE;
+
+  /* Execute pending JOIN command so that the client who originally
+     wanted to join the channel will be joined after all. */
+  SILC_SERVER_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_JOIN);
+
+ out:
+  silc_server_command_reply_free(cmd);
+}