Merged from silc_1_0_branch.
[silc.git] / apps / silcd / command_reply.c
index 64ca3abaa2f346835581670ffc80f00322d5e4b6..a72e6c206a8ccdef7d0f727f6fe7ec6fbbd94fba 100644 (file)
@@ -52,6 +52,7 @@ SilcServerCommandReply silc_command_reply_list[] =
   SILC_SERVER_CMD_REPLY(users, USERS),
   SILC_SERVER_CMD_REPLY(getkey, GETKEY),
   SILC_SERVER_CMD_REPLY(list, LIST),
+  SILC_SERVER_CMD_REPLY(watch, WATCH),
 
   { NULL, 0 },
 };
@@ -66,7 +67,6 @@ void silc_server_command_reply_process(SilcServer server,
   SilcServerCommandReplyContext ctx;
   SilcCommandPayload payload;
   SilcCommand command;
-  SilcUInt16 ident;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -85,16 +85,22 @@ void silc_server_command_reply_process(SilcServer server,
   ctx->sock = silc_socket_dup(sock);
   ctx->payload = payload;
   ctx->args = silc_command_get_args(ctx->payload);
-  ident = silc_command_get_ident(ctx->payload);
+  ctx->ident = silc_command_get_ident(ctx->payload);
+  command = silc_command_get(ctx->payload);
+
+  /* Client is not allowed to send reply to all commands */
+  if (sock->type == SILC_SOCKET_TYPE_CLIENT &&
+      command != SILC_COMMAND_WHOIS) {
+    silc_server_command_reply_free(ctx);
+    return;
+  }
       
   /* Check for pending commands and mark to be exeucted */
   ctx->callbacks = 
-    silc_server_command_pending_check(server, ctx, 
-                                     silc_command_get(ctx->payload), 
-                                     ident, &ctx->callbacks_count);
+    silc_server_command_pending_check(server, command,
+                                     ctx->ident, &ctx->callbacks_count);
 
   /* Execute command reply */
-  command = silc_command_get(ctx->payload);
   for (cmd = silc_command_reply_list; cmd->cb; cmd++)
     if (cmd->cmd == command)
       break;
@@ -142,7 +148,7 @@ silc_server_command_process_error(SilcServerCommandReplyContext cmd,
                                               client_id, FALSE, NULL);
        if (client) {
          silc_server_remove_from_channels(server, NULL, client, TRUE, 
-                                          NULL, TRUE);
+                                          NULL, TRUE, FALSE);
          silc_idlist_del_data(client);
          silc_idlist_del_client(server->global_list, client);
        }
@@ -282,6 +288,36 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
   if (fingerprint && flen == sizeof(client->data.fingerprint))
     memcpy(client->data.fingerprint, fingerprint, flen);
 
+  /* Take Requested Attributes if set. */
+  tmp = silc_argument_get_arg_type(cmd->args, 11, &len);
+  if (tmp) {
+    silc_free(client->attrs);
+    client->attrs = silc_memdup(tmp, len);
+    client->attrs_len = len;
+  }
+
+  return TRUE;
+}
+
+/* Handle requested attributes reply in WHOIS from client */
+
+static char
+silc_server_command_reply_whois_save_client(SilcServerCommandReplyContext cmd)
+{
+  unsigned char *tmp;
+  SilcUInt32 len;
+  SilcClientEntry client = cmd->sock->user_data;
+
+  /* Take Requested Attributes if set. */
+  tmp = silc_argument_get_arg_type(cmd->args, 11, &len);
+  if (tmp && client) {
+    silc_free(client->attrs);
+    client->attrs = silc_memdup(tmp, len);
+    client->attrs_len = len;
+  }
+
+  client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
+
   return TRUE;
 }
 
@@ -298,8 +334,13 @@ SILC_SERVER_CMD_REPLY_FUNC(whois)
 
   COMMAND_CHECK_STATUS;
 
-  if (!silc_server_command_reply_whois_save(cmd))
-    goto out;
+  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT) {
+    if (!silc_server_command_reply_whois_save(cmd))
+      goto out;
+  } else {
+    if (!silc_server_command_reply_whois_save_client(cmd))
+      goto out;
+  }
 
   /* Pending callbacks are not executed if this was an list entry */
   if (status != SILC_STATUS_OK &&
@@ -378,6 +419,8 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
       return FALSE;
     }
 
+    client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
+    client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
     client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED; 
     client->servername = servername;
   } else {
@@ -388,10 +431,13 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
 
     silc_free(client->nickname);
     silc_free(client->username);
+    silc_free(client->servername);
     
     client->nickname = nick;
     client->username = strdup(username);
     client->servername = servername;
+    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 :
@@ -401,6 +447,17 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
                     client, 0, NULL);
   }
 
+  /* If client is global and is not on any channel then add that we'll
+     expire the entry after a while. */
+  if (global) {
+    silc_idlist_find_client_by_id(server->global_list, client->id,
+                                 FALSE, &cache);
+    if (!silc_hash_table_count(client->channels))
+      cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
+    else
+      cache->expire = 0;
+  }
+
   silc_free(client_id);
 
   return TRUE;
@@ -427,8 +484,13 @@ SILC_SERVER_CMD_REPLY_FUNC(whowas)
   }
 
  out:
+  silc_server_command_process_error(cmd, error);
   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
+  silc_server_command_reply_free(cmd);
+  return;
+
  err:
+  silc_server_command_process_error(cmd, error);
   silc_server_command_reply_free(cmd);
 }
 
@@ -877,7 +939,7 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
   /* Get founder key */
   tmp = silc_argument_get_arg_type(cmd->args, 15, &len);
   if (tmp)
-    silc_pkcs_public_key_decode(tmp, len, &founder_key);
+    silc_pkcs_public_key_payload_decode(tmp, len, &founder_key);
 
   /* See whether we already have the channel. */
   entry = silc_idlist_find_channel_by_name(server->local_list, 
@@ -904,6 +966,7 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
       silc_free(id);
       goto out;
     }
+    hmac = NULL;
     server->stat.my_channels++;
     server->stat.channels++;
   } else {
@@ -930,23 +993,53 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
     founder_key = NULL;
   }
 
-  if (entry->hmac_name && hmac) {
+  if (entry->hmac_name && (hmac || (!hmac && entry->hmac))) {
     silc_free(entry->hmac_name);
-    entry->hmac_name = strdup(silc_hmac_get_name(hmac));
+    entry->hmac_name = strdup(silc_hmac_get_name(hmac ? hmac : entry->hmac));
   }
 
   /* Get the ban list */
   tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
-  if (tmp) {
-    silc_free(entry->ban_list);
-    entry->ban_list = silc_memdup(tmp, len);
+  if (tmp && len > 2) {
+    SilcArgumentPayload iargs;
+    SilcUInt16 iargc;
+    SILC_GET16_MSB(iargc, tmp);
+    iargs = silc_argument_payload_parse(tmp + 2, len - 2, iargc);
+    if (iargs) {
+      /* Delete old ban list */
+      if (entry->ban_list)
+       silc_hash_table_free(entry->ban_list);
+      entry->ban_list =
+       silc_hash_table_alloc(0, silc_hash_ptr,
+                             NULL, NULL, NULL,
+                             silc_server_inviteban_destruct, entry, TRUE);
+
+      /* Add new ban list */
+      silc_server_inviteban_process(server, entry->ban_list, 0, iargs);
+      silc_argument_payload_free(iargs);
+    }
   }
 
   /* Get the invite list */
   tmp = silc_argument_get_arg_type(cmd->args, 9, &len);
-  if (tmp) {
-    silc_free(entry->invite_list);
-    entry->invite_list = silc_memdup(tmp, len);
+  if (tmp && len > 2) {
+    SilcArgumentPayload iargs;
+    SilcUInt16 iargc;
+    SILC_GET16_MSB(iargc, tmp);
+    iargs = silc_argument_payload_parse(tmp + 2, len - 2, iargc);
+    if (iargs) {
+      /* Delete old invite list */
+      if (entry->invite_list)
+       silc_hash_table_free(entry->invite_list);
+      entry->invite_list =
+       silc_hash_table_alloc(0, silc_hash_ptr,
+                             NULL, NULL, NULL,
+                             silc_server_inviteban_destruct, entry, TRUE);
+
+      /* Add new invite list */
+      silc_server_inviteban_process(server, entry->invite_list, 0, iargs);
+      silc_argument_payload_free(iargs);
+    }
   }
 
   /* Get the topic */
@@ -986,6 +1079,8 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
  out:
   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
  err:
+  if (hmac)
+    silc_hmac_free(hmac);
   silc_free(client_id);
   silc_server_command_reply_free(cmd);
 
@@ -1011,7 +1106,7 @@ SILC_SERVER_CMD_REPLY_FUNC(stats)
 
   /* Get statistics structure */
   tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
-  if (server->server_type == SILC_SERVER && tmp) {
+  if (server->server_type != SILC_ROUTER && tmp) {
     silc_buffer_set(&buf, tmp, tmp_len);
     silc_buffer_unformat(&buf,
                         SILC_STR_UI_INT(NULL),
@@ -1140,10 +1235,8 @@ SILC_SERVER_CMD_REPLY_FUNC(getkey)
   SilcServerEntry server_entry = NULL;
   SilcClientID *client_id = NULL;
   SilcServerID *server_id = NULL;
-  SilcSKEPKType type;
-  unsigned char *tmp, *pk;
+  unsigned char *tmp;
   SilcUInt32 len;
-  SilcUInt16 pk_len;
   SilcIDPayload idp = NULL;
   SilcIdType id_type;
   SilcPublicKey public_key = NULL;
@@ -1162,16 +1255,8 @@ SILC_SERVER_CMD_REPLY_FUNC(getkey)
   if (!tmp)
     goto out;
 
-  /* Decode the public key */
-
-  SILC_GET16_MSB(pk_len, tmp);
-  SILC_GET16_MSB(type, tmp + 2);
-  pk = tmp + 4;
-
-  if (type != SILC_SKE_PK_TYPE_SILC)
-    goto out;
-
-  if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
+  /* Decode the public key payload */
+  if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key))
     goto out;
 
   id_type = silc_id_payload_get_type(idp);