updates.
[silc.git] / apps / silcd / command.c
index b260c141524f0dc96c8631f6bf8e71b6dc345b32..48033266a4e0eb5f7ced7b97007340b52f18e0f3 100644 (file)
@@ -249,7 +249,7 @@ void silc_server_command_free(SilcServerCommandContext ctx)
                  ctx->users));
   if (ctx->users < 1) {
     if (ctx->payload)
-      silc_command_free_payload(ctx->payload);
+      silc_command_payload_free(ctx->payload);
     if (ctx->packet)
       silc_packet_context_free(ctx->packet);
     if (ctx->sock)
@@ -537,7 +537,7 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
   SilcClientEntry entry;
   SilcCommandStatus status;
   uint16 ident = silc_command_get_ident(cmd->payload);
-  char nh[128], uh[128];
+  char nh[256], uh[256];
   unsigned char idle[4], mode[4];
   SilcSocketConnection hsock;
 
@@ -555,11 +555,18 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
 
     if (entry->data.registered == FALSE) {
       if (clients_count == 1) {
-       SilcBuffer idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
-       silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
-                                            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
-                                            2, idp->data, idp->len);
-       silc_buffer_free(idp);
+       if (entry->nickname) {
+         silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
+                                              SILC_STATUS_ERR_NO_SUCH_NICK,
+                                              3, entry->nickname, 
+                                              strlen(entry->nickname));
+       } else {
+         SilcBuffer idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
+         silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
+                                    SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
+                                              2, idp->data, idp->len);
+         silc_buffer_free(idp);
+       }
       }
       continue;
     }
@@ -1764,7 +1771,7 @@ SILC_SERVER_CMD_FUNC(nick)
                                        new_id);
 
   /* Remove old cache entry */
-  silc_idcache_del_by_id(server->local_list->clients, client->id);
+  silc_idcache_del_by_context(server->local_list->clients, client);
 
   oidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
 
@@ -1781,8 +1788,7 @@ SILC_SERVER_CMD_FUNC(nick)
 
   /* Update client cache */
   silc_idcache_add(server->local_list->clients, client->nickname, 
-                  strlen(client->nickname), client->id, 
-                  (void *)client, FALSE);
+                  client->id, (void *)client, FALSE);
 
   nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
 
@@ -1858,7 +1864,7 @@ silc_server_command_list_send_reply(SilcServerCommandContext cmd,
       memset(usercount, 0, sizeof(usercount));
     } else {
       topic = entry->topic;
-      users = silc_list_count(entry->user_list);
+      users = silc_hash_table_count(entry->user_list);
       SILC_PUT32_MSB(users, usercount);
     }
 
@@ -1909,7 +1915,7 @@ silc_server_command_list_send_reply(SilcServerCommandContext cmd,
       memset(usercount, 0, sizeof(usercount));
     } else {
       topic = entry->topic;
-      users = silc_list_count(entry->user_list);
+      users = silc_hash_table_count(entry->user_list);
       SILC_PUT32_MSB(users, usercount);
     }
 
@@ -2044,11 +2050,13 @@ SILC_SERVER_CMD_FUNC(topic)
       goto out;
     }
 
-    /* See whether has rights to change topic */
-    silc_list_start(channel->user_list);
-    while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
-      if (chl->client == client)
-       break;
+    /* See whether the client is on channel and has rights to change topic */
+    if (!silc_hash_table_find(channel->user_list, client, NULL, 
+                             (void *)&chl)) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
+                                           SILC_STATUS_ERR_NOT_ON_CHANNEL);
+      goto out;
+    }
 
     if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
       if (channel->mode & SILC_CHANNEL_MODE_TOPIC) {
@@ -2162,16 +2170,12 @@ SILC_SERVER_CMD_FUNC(invite)
   /* Check whether the channel is invite-only channel. If yes then the
      sender of this command must be at least channel operator. */
   if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
-    silc_list_start(channel->user_list);
-    while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
-      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);
-         goto out;
-       }
-       break;
-      }
+    silc_hash_table_find(channel->user_list, sender, NULL, (void *)&chl);
+    if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+                                           SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+      goto out;
+    }
   }
 
   /* Get destination client ID */
@@ -2217,6 +2221,11 @@ SILC_SERVER_CMD_FUNC(invite)
     
     /* Get route to the client */
     dest_sock = silc_server_get_client_route(server, NULL, 0, dest_id, &idata);
+    if (!dest_sock) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+                                           SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
+      goto out;
+    }
 
     memset(invite, 0, sizeof(invite));
     strncat(invite, dest->nickname, strlen(dest->nickname));
@@ -2303,13 +2312,20 @@ SILC_SERVER_CMD_FUNC(invite)
 
   /* Send command reply */
   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
-  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INVITE,
-                                               SILC_STATUS_OK, ident, 2,
-                                               2, tmp, len,
-                                               3, channel->invite_list,
-                                               channel->invite_list ?
-                                               strlen(channel->invite_list) :
-                                               0);
+
+  if (add || del)
+    packet = 
+      silc_command_reply_payload_encode_va(SILC_COMMAND_INVITE,
+                                          SILC_STATUS_OK, ident, 2,
+                                          2, tmp, len,
+                                          3, channel->invite_list,
+                                          channel->invite_list ?
+                                          strlen(channel->invite_list) : 0);
+  else
+    packet = 
+      silc_command_reply_payload_encode_va(SILC_COMMAND_INVITE,
+                                          SILC_STATUS_OK, ident, 1,
+                                          2, tmp, len);
   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
                          packet->data, packet->len, FALSE);
   silc_buffer_free(packet);
@@ -2442,6 +2458,12 @@ SILC_SERVER_CMD_FUNC(kill)
     }
   }
 
+  if (remote_client->data.registered == FALSE) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
+                                         SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
+    goto out;
+  }
+
   /* Get comment */
   comment = silc_argument_get_arg_type(cmd->args, 2, &tmp_len2);
   if (tmp_len2 > 128)
@@ -2638,13 +2660,20 @@ SILC_SERVER_CMD_FUNC(info)
   server_name = entry->server_name;
 
   /* Send the reply */
-  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
-                                               SILC_STATUS_OK, ident, 3,
-                                               2, idp->data, idp->len,
-                                               3, server_name, 
-                                               strlen(server_name),
-                                               4, server_info, 
-                                               strlen(server_info));
+  if (server_info)
+    packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
+                                                 SILC_STATUS_OK, ident, 3,
+                                                 2, idp->data, idp->len,
+                                                 3, server_name, 
+                                                 strlen(server_name),
+                                                 4, server_info, 
+                                                 strlen(server_info));
+  else
+    packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
+                                                 SILC_STATUS_OK, ident, 2,
+                                                 2, idp->data, idp->len,
+                                                 3, server_name, 
+                                                 strlen(server_name));
   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
                          packet->data, packet->len, FALSE);
     
@@ -2794,7 +2823,7 @@ static void silc_server_command_join_channel(SilcServer server,
 
   /* Check user count limit if set. */
   if (channel->mode & SILC_CHANNEL_MODE_ULIMIT) {
-    if (silc_list_count(channel->user_list) + 1 > 
+    if (silc_hash_table_count(channel->user_list) + 1 > 
        channel->user_limit) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
                                            SILC_STATUS_ERR_CHANNEL_IS_FULL);
@@ -2814,7 +2843,7 @@ static void silc_server_command_join_channel(SilcServer server,
   }
 
   /* Generate new channel key as protocol dictates */
-  if ((!created && silc_list_count(channel->user_list) > 0) || 
+  if ((!created && silc_hash_table_count(channel->user_list) > 0) || 
       !channel->channel_key)
     silc_server_create_channel_key(server, channel, 0);
 
@@ -2832,8 +2861,8 @@ static void silc_server_command_join_channel(SilcServer server,
   chl->mode = umode;
   chl->client = client;
   chl->channel = channel;
-  silc_list_add(channel->user_list, chl);
-  silc_list_add(client->channels, chl);
+  silc_hash_table_add(channel->user_list, client, chl);
+  silc_hash_table_add(client->channels, channel, chl);
 
   /* Get users on the channel */
   silc_server_get_users_on_channel(server, channel, &user_list, &mode_list,
@@ -3084,7 +3113,7 @@ SILC_SERVER_CMD_FUNC(join)
   /* If the channel does not have global users and is also empty it means the
      channel was created globally (by our router) and the client will be the
      channel founder and operator. */
-  if (!channel->global_users && silc_list_count(channel->user_list) == 0) {
+  if (!channel->global_users && !silc_hash_table_count(channel->user_list)) {
     umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
     created = TRUE;            /* Created globally by our router */
   }
@@ -3452,10 +3481,7 @@ SILC_SERVER_CMD_FUNC(cmode)
   }
 
   /* Get entry to the channel user list */
-  silc_list_start(channel->user_list);
-  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
-    if (chl->client == client)
-      break;
+  silc_hash_table_find(channel->user_list, client, NULL, (void *)&chl);
 
   /* Check that client has rights to change any requested channel modes */
   if (!silc_server_check_cmode_rights(channel, chl, mode_mask)) {
@@ -3792,13 +3818,8 @@ SILC_SERVER_CMD_FUNC(cumode)
   }
 
   /* Check that client has rights to change other's rights */
-  silc_list_start(channel->user_list);
-  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
-    if (chl->client == client) {
-      sender_mask = chl->mode;
-      break;
-    }
-  }
+  silc_hash_table_find(channel->user_list, client, NULL, (void *)&chl);
+  sender_mask = chl->mode;
   
   /* Get the target client's channel mode mask */
   tmp_mask = silc_argument_get_arg_type(cmd->args, 2, NULL);
@@ -3848,10 +3869,8 @@ SILC_SERVER_CMD_FUNC(cumode)
     }
 
     /* Get entry to the channel user list */
-    silc_list_start(channel->user_list);
-    while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
-      if (chl->client == target_client)
-       break;
+    silc_hash_table_find(channel->user_list, target_client, NULL, 
+                        (void *)&chl);
   }
 
   /* 
@@ -4040,16 +4059,11 @@ SILC_SERVER_CMD_FUNC(kick)
   }
 
   /* Check that the kicker is channel operator or channel founder */
-  silc_list_start(channel->user_list);
-  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
-    if (chl->client == client) {
-      if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
-       silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
-                                             SILC_STATUS_ERR_NO_CHANNEL_PRIV);
-       goto out;
-      }
-      break;
-    }
+  silc_hash_table_find(channel->user_list, client, NULL, (void *)&chl);
+  if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
+                                         SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+    goto out;
   }
   
   /* Get target Client ID */
@@ -4076,16 +4090,11 @@ SILC_SERVER_CMD_FUNC(kick)
 
   /* Check that the target client is not channel founder. Channel founder
      cannot be kicked from the channel. */
-  silc_list_start(channel->user_list);
-  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
-    if (chl->client == target_client) {
-      if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
-       silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
-                                 SILC_STATUS_ERR_NO_CHANNEL_FOPRIV);
-       goto out;
-      }
-      break;
-    }
+  silc_hash_table_find(channel->user_list, target_client, NULL, (void *)&chl);
+  if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
+                                         SILC_STATUS_ERR_NO_CHANNEL_FOPRIV);
+    goto out;
   }
   
   /* Check whether target client is on the channel */
@@ -4399,10 +4408,7 @@ SILC_SERVER_CMD_FUNC(ban)
   }
 
   /* Get entry to the channel user list */
-  silc_list_start(channel->user_list);
-  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
-    if (chl->client == client)
-      break;
+  silc_hash_table_find(channel->user_list, client, NULL, (void *)&chl);
 
   /* The client must be at least channel operator. */
   if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
@@ -4776,6 +4782,8 @@ SILC_SERVER_CMD_FUNC(getkey)
   SilcBuffer pk;
   SilcIdType id_type;
 
+  SILC_LOG_DEBUG(("Start"));
+
   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
   if (!tmp) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY,
@@ -4797,9 +4805,15 @@ SILC_SERVER_CMD_FUNC(getkey)
        would be locally connected client so send the command further. */
     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 && !cmd->pending && !server->standalone) ||
-       (client && !client->connection)) {
+       (client && !client->connection && !cmd->pending && 
+        !server->standalone) ||
+       (client && !client->data.public_key && !cmd->pending &&
+        !server->standalone)) {
       SilcBuffer tmpbuf;
       uint16 old_ident;
       SilcSocketConnection dest_sock;
@@ -4855,9 +4869,15 @@ SILC_SERVER_CMD_FUNC(getkey)
        would be locally connected server so send the command further. */
     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 && !cmd->pending && !server->standalone) ||
-       (server_entry && !server_entry->connection)) {
+       (server_entry && !server_entry->connection && !cmd->pending &&
+        !server->standalone) ||
+       (server_entry && !server_entry->data.public_key && !cmd->pending &&
+        !server->standalone)) {
       SilcBuffer tmpbuf;
       uint16 old_ident;