updates.
[silc.git] / apps / silcd / command_reply.c
index 88211f55beec9d53ce02f99865534dcdf4ea1b58..4717e3b77a440fa071f208cd6882a4fd84dc432d 100644 (file)
@@ -56,6 +56,7 @@ SilcServerCommandReply silc_command_reply_list[] =
   SILC_SERVER_CMD_REPLY(motd, MOTD),
   SILC_SERVER_CMD_REPLY(join, JOIN),
   SILC_SERVER_CMD_REPLY(users, USERS),
+  SILC_SERVER_CMD_REPLY(getkey, GETKEY),
 
   { NULL, 0 },
 };
@@ -70,7 +71,7 @@ void silc_server_command_reply_process(SilcServer server,
   SilcServerCommandReplyContext ctx;
   SilcCommandPayload payload;
   SilcCommand command;
-  unsigned short ident;
+  uint16 ident;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -114,7 +115,7 @@ void silc_server_command_reply_process(SilcServer server,
 void silc_server_command_reply_free(SilcServerCommandReplyContext cmd)
 {
   if (cmd) {
-    silc_command_free_payload(cmd->payload);
+    silc_command_payload_free(cmd->payload);
     if (cmd->sock)
       silc_socket_free(cmd->sock); /* Decrease the reference counter */
     silc_free(cmd);
@@ -127,15 +128,13 @@ static char
 silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
 {
   SilcServer server = cmd->server;
-  int len, id_len;
   unsigned char *tmp, *id_data;
-  char *nickname, *username, *realname;
+  char *nickname, *username, *realname, *servername = NULL;
   SilcClientID *client_id;
   SilcClientEntry client;
-  SilcIDCacheEntry cache = NULL;
   char global = FALSE;
   char *nick;
-  unsigned int mode = 0;
+  uint32 mode = 0, len, id_len;
 
   id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
   nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
@@ -159,11 +158,10 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
 
   /* Check if we have this client cached already. */
 
-  client = silc_idlist_find_client_by_id(server->local_list, client_id,
-                                        &cache);
+  client = silc_idlist_find_client_by_id(server->local_list, client_id, NULL);
   if (!client) {
-    client = silc_idlist_find_client_by_id(server->global_list, 
-                                          client_id, &cache);
+    client = silc_idlist_find_client_by_id(server->global_list, client_id, 
+                                          NULL);
     global = TRUE;
   }
 
@@ -177,7 +175,9 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
     if (strchr(nickname, '@')) {
       int len = strcspn(nickname, "@");
       nick = silc_calloc(len + 1, sizeof(char));
+      servername = silc_calloc((strlen(nickname) - len) + 1, sizeof(char));
       memcpy(nick, nickname, len);
+      memcpy(servername, nickname + len + 1, strlen(nickname) - len);
     } else {
       nick = strdup(nickname);
     }
@@ -185,7 +185,7 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
     /* We don't have that client anywhere, add it. The client is added
        to global list since server didn't have it in the lists so it must be 
        global. */
-    client = silc_idlist_add_client(server->global_list, nick, strlen(nick),
+    client = silc_idlist_add_client(server->global_list, nick, 
                                    strdup(username), 
                                    strdup(realname), client_id, 
                                    cmd->sock->user_data, NULL);
@@ -194,6 +194,7 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
 
     client->data.registered = TRUE;
     client->mode = mode;
+    client->servername = servername;
   } else {
     /* We have the client already, update the data */
 
@@ -203,7 +204,9 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
     if (strchr(nickname, '@')) {
       int len = strcspn(nickname, "@");
       nick = silc_calloc(len + 1, sizeof(char));
+      servername = silc_calloc((strlen(nickname) - len) + 1, sizeof(char));
       memcpy(nick, nickname, len);
+      memcpy(servername, nickname + len + 1, strlen(nickname) - len);
     } else {
       nick = strdup(nickname);
     }
@@ -219,14 +222,14 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
     client->username = strdup(username);
     client->userinfo = strdup(realname);
     client->mode = mode;
-
-    if (cache) {
-      cache->data = nick;
-      cache->data_len = strlen(nick);
-      silc_idcache_sort_by_data(global ? server->global_list->clients : 
-                               server->local_list->clients);
-    }
-
+    client->servername = servername;
+
+    /* Remove the old cache entry and create a new one */
+    silc_idcache_del_by_context(global ? server->global_list->clients :
+                               server->local_list->clients, client);
+    silc_idcache_add(global ? server->global_list->clients :
+                    server->local_list->clients, nick, client->id, 
+                    client, FALSE);
     silc_free(client_id);
   }
 
@@ -268,9 +271,9 @@ static char
 silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
 {
   SilcServer server = cmd->server;
-  int len, id_len;
+  uint32 len, id_len;
   unsigned char *id_data;
-  char *nickname, *username, *realname;
+  char *nickname, *username, *realname, *servername = NULL;
   SilcClientID *client_id;
   SilcClientEntry client;
   SilcIDCacheEntry cache = NULL;
@@ -309,7 +312,9 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
     if (strchr(nickname, '@')) {
       int len = strcspn(nickname, "@");
       nick = silc_calloc(len + 1, sizeof(char));
+      servername = silc_calloc((strlen(nickname) - len) + 1, sizeof(char));
       memcpy(nick, nickname, len);
+      memcpy(servername, nickname + len + 1, strlen(nickname) - len);
     } else {
       nick = strdup(nickname);
     }
@@ -317,7 +322,7 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
     /* We don't have that client anywhere, add it. The client is added
        to global list since server didn't have it in the lists so it must be 
        global. */
-    client = silc_idlist_add_client(server->global_list, nick, strlen(nick),
+    client = silc_idlist_add_client(server->global_list, nick,
                                    strdup(username), strdup(realname), 
                                    silc_id_dup(client_id, SILC_ID_CLIENT), 
                                    cmd->sock->user_data, NULL);
@@ -328,6 +333,7 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
     client = silc_idlist_find_client_by_id(server->global_list, 
                                           client_id, &cache);
     cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
+    client->servername = servername;
   } else {
     /* We have the client already, update the data */
 
@@ -335,7 +341,9 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
     if (strchr(nickname, '@')) {
       int len = strcspn(nickname, "@");
       nick = silc_calloc(len + 1, sizeof(char));
+      servername = silc_calloc((strlen(nickname) - len) + 1, sizeof(char));
       memcpy(nick, nickname, len);
+      memcpy(servername, nickname + len + 1, strlen(nickname) - len);
     } else {
       nick = strdup(nickname);
     }
@@ -347,13 +355,14 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
     
     client->nickname = nick;
     client->username = strdup(username);
-
-    if (cache) {
-      cache->data = nick;
-      cache->data_len = strlen(nick);
-      silc_idcache_sort_by_data(global ? server->global_list->clients : 
-                               server->local_list->clients);
-    }
+    client->servername = servername;
+
+    /* Remove the old cache entry and create a new one */
+    silc_idcache_del_by_context(global ? server->global_list->clients :
+                               server->local_list->clients, client);
+    silc_idcache_add(global ? server->global_list->clients :
+                    server->local_list->clients, nick, client->id, 
+                    client, FALSE);
   }
 
   silc_free(client_id);
@@ -393,12 +402,11 @@ static char
 silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
 {
   SilcServer server = cmd->server;
-  int len, id_len;
+  uint32 len, id_len;
   unsigned char *id_data;
   char *nickname, *username;
   SilcClientID *client_id;
   SilcClientEntry client;
-  SilcIDCacheEntry cache = NULL;
   char global = FALSE;
   char *nick = NULL;
 
@@ -414,11 +422,10 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
 
   /* Check if we have this client cached already. */
 
-  client = silc_idlist_find_client_by_id(server->local_list, client_id,
-                                        &cache);
+  client = silc_idlist_find_client_by_id(server->local_list, client_id, NULL);
   if (!client) {
-    client = silc_idlist_find_client_by_id(server->global_list, 
-                                          client_id, &cache);
+    client = silc_idlist_find_client_by_id(server->global_list, client_id,
+                                          NULL);
     global = TRUE;
   }
 
@@ -442,7 +449,7 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
     /* We don't have that client anywhere, add it. The client is added
        to global list since server didn't have it in the lists so it must be 
        global. */
-    client = silc_idlist_add_client(server->global_list, nick, strlen(nick),
+    client = silc_idlist_add_client(server->global_list, nick, 
                                    username ? strdup(username) : NULL, NULL,
                                    client_id, cmd->sock->user_data, NULL);
     client->data.registered = TRUE;
@@ -473,13 +480,14 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
       client->username = strdup(username);
     }
 
-    if (nickname && cache) {
-      cache->data = nick;
-      cache->data_len = strlen(nick);
-      silc_idcache_sort_by_data(global ? server->global_list->clients : 
-                               server->local_list->clients);
+    /* Remove the old cache entry and create a new one */
+    if (nickname) {
+      silc_idcache_del_by_context(global ? server->global_list->clients :
+                                 server->local_list->clients, client);
+      silc_idcache_add(global ? server->global_list->clients :
+                      server->local_list->clients, nick, client->id, 
+                      client, FALSE);
     }
-
     silc_free(client_id);
   }
 
@@ -523,7 +531,7 @@ SILC_SERVER_CMD_REPLY_FUNC(info)
   SilcCommandStatus status;
   SilcServerEntry entry;
   SilcServerID *server_id;
-  unsigned int tmp_len;
+  uint32 tmp_len;
   unsigned char *tmp, *name;
 
   COMMAND_CHECK_STATUS;
@@ -579,7 +587,7 @@ SILC_SERVER_CMD_REPLY_FUNC(motd)
   SilcCommandStatus status;
   SilcServerEntry entry = NULL;
   SilcServerID *server_id;
-  unsigned int tmp_len;
+  uint32 tmp_len;
   unsigned char *tmp;
 
   COMMAND_CHECK_STATUS;
@@ -630,10 +638,10 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
   SilcClientID *client_id = NULL;
   SilcChannelEntry entry;
   SilcHmac hmac = NULL;
-  unsigned int id_len, len, list_count;
+  uint32 id_len, len, list_count;
   unsigned char *id_string;
   char *channel_name, *tmp;
-  unsigned int mode, created;
+  uint32 mode, created;
   SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
 
   COMMAND_CHECK_STATUS;
@@ -828,8 +836,8 @@ SILC_SERVER_CMD_REPLY_FUNC(users)
   SilcBuffer client_id_list;
   SilcBuffer client_mode_list;
   unsigned char *tmp;
-  unsigned int tmp_len;
-  unsigned int list_count;
+  uint32 tmp_len;
+  uint32 list_count;
 
   COMMAND_CHECK_STATUS;
 
@@ -886,7 +894,92 @@ SILC_SERVER_CMD_REPLY_FUNC(users)
  out:
   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
   SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
-  if (channel_id)
-    silc_free(channel_id);
+  silc_free(channel_id);
+  silc_server_command_reply_free(cmd);
+}
+
+SILC_SERVER_CMD_REPLY_FUNC(getkey)
+{
+  SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
+  SilcServer server = cmd->server;
+  SilcCommandStatus status;
+  SilcClientEntry client = NULL;
+  SilcServerEntry server_entry = NULL;
+  SilcClientID *client_id = NULL;
+  SilcServerID *server_id = NULL;
+  SilcSKEPKType type;
+  unsigned char *tmp, *pk;
+  uint32 len;
+  uint16 pk_len;
+  SilcIDPayload idp = NULL;
+  SilcIdType id_type;
+  SilcPublicKey public_key = NULL;
+
+  COMMAND_CHECK_STATUS;
+
+  tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+  if (!tmp)
+    goto out;
+  idp = silc_id_payload_parse_data(tmp, len);
+  if (!idp)
+    goto out;
+
+  /* Get the public key payload */
+  tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
+  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))
+    goto out;
+
+  id_type = silc_id_payload_get_type(idp);
+  if (id_type == SILC_ID_CLIENT) {
+    client_id = silc_id_payload_get_id(idp);
+
+    client = silc_idlist_find_client_by_id(server->local_list, client_id,
+                                          NULL);
+    if (!client) {
+      client = silc_idlist_find_client_by_id(server->global_list, 
+                                            client_id, NULL);
+      if (!client)
+       goto out;
+    }
+
+    client->data.public_key = public_key;
+  } else if (id_type == SILC_ID_SERVER) {
+    server_id = silc_id_payload_get_id(idp);
+
+    server_entry = silc_idlist_find_server_by_id(server->local_list, server_id,
+                                                NULL);
+    if (!server_entry) {
+      server_entry = silc_idlist_find_server_by_id(server->global_list, 
+                                                  server_id, NULL);
+      if (!server_entry)
+       goto out;
+    }
+
+    server_entry->data.public_key = public_key;
+  } else {
+    goto out;
+  }
+
+ out:
+  SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
+  SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
+  if (idp)
+    silc_id_payload_free(idp);
+  silc_free(client_id);
+  silc_free(server_id);
+  if (public_key)
+    silc_pkcs_public_key_free(public_key);
   silc_server_command_reply_free(cmd);
 }