Improved UTF-8 encoding and decoding, improved toolkit doc,
[silc.git] / apps / silcd / command.c
index 6efee9d02707634c254677a072275c7db0a653ff..1a5c7c5faebe1ff6b555adc9cd8f5b3f19209b5e 100644 (file)
@@ -97,15 +97,15 @@ SilcServerCommand silc_command_list[] =
 do {                                                                        \
   SilcUInt32 _argc;                                                         \
                                                                             \
-  SILC_LOG_DEBUG(("Start"));                                                \
-                                                                            \
   if (silc_server_command_pending_error_check(cmd, context2, command)) {     \
+    SILC_LOG_DEBUG(("Error occurred in command reply, command not called")); \
     silc_server_command_free(cmd);                                          \
     return;                                                                 \
   }                                                                         \
                                                                             \
   _argc = silc_argument_get_arg_num(cmd->args);                                     \
   if (_argc < min) {                                                        \
+    SILC_LOG_DEBUG(("Not enough parameters in command"));                   \
     silc_server_command_send_status_reply(cmd, command,                             \
                                          SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, \
                                          0);                                \
@@ -113,6 +113,7 @@ do {                                                                             \
     return;                                                                 \
   }                                                                         \
   if (_argc > max) {                                                        \
+    SILC_LOG_DEBUG(("Too many parameters in command"));                             \
     silc_server_command_send_status_reply(cmd, command,                             \
                                          SILC_STATUS_ERR_TOO_MANY_PARAMS,   \
                                          0);                                \
@@ -157,6 +158,7 @@ SILC_TASK_CALLBACK(silc_server_command_process_timeout)
   SilcClientEntry client = (SilcClientEntry)timeout->ctx->sock->user_data;
 
   if (!client) {
+    SILC_LOG_DEBUG(("Client entry is invalid"));
     silc_server_command_free(timeout->ctx);
     silc_free(timeout);
   }
@@ -164,15 +166,21 @@ SILC_TASK_CALLBACK(silc_server_command_process_timeout)
   /* Update access time */
   client->last_command = time(NULL);
 
-  if (!(timeout->cmd->flags & SILC_CF_REG))
+  if (!(timeout->cmd->flags & SILC_CF_REG)) {
+    SILC_LOG_DEBUG(("Calling %s command",
+                   silc_get_command_name(timeout->cmd->cmd)));
     timeout->cmd->cb(timeout->ctx, NULL);
-  else if (silc_server_is_registered(timeout->ctx->server, 
-                                    timeout->ctx->sock, 
-                                    timeout->ctx, 
-                                    timeout->cmd->cmd))
+  } else if (silc_server_is_registered(timeout->ctx->server, 
+                                      timeout->ctx->sock, 
+                                      timeout->ctx, 
+                                      timeout->cmd->cmd)) {
+    SILC_LOG_DEBUG(("Calling %s command",
+                   silc_get_command_name(timeout->cmd->cmd)));
     timeout->cmd->cb(timeout->ctx, NULL);
-  else
+  } else {
+    SILC_LOG_DEBUG(("Client is not registered"));
     silc_server_command_free(timeout->ctx);
+  }
 
   silc_free(timeout);
 }
@@ -187,8 +195,6 @@ void silc_server_command_process(SilcServer server,
   SilcServerCommand *cmd;
   SilcCommand command;
 
-  SILC_LOG_DEBUG(("Start"));
-
   /* Allocate command context. This must be free'd by the
      command routine receiving it. */
   ctx = silc_server_command_alloc();
@@ -215,6 +221,7 @@ void silc_server_command_process(SilcServer server,
       break;
 
   if (!cmd || !cmd->cb) {
+    SILC_LOG_DEBUG(("Unknown command %d", command));
     silc_server_command_send_status_reply(ctx, command,
                                          SILC_STATUS_ERR_UNKNOWN_COMMAND, 0);
     silc_server_command_free(ctx);
@@ -261,12 +268,16 @@ void silc_server_command_process(SilcServer server,
 
   /* Execute for server */
 
-  if (!(cmd->flags & SILC_CF_REG))
+  if (!(cmd->flags & SILC_CF_REG)) {
+    SILC_LOG_DEBUG(("Calling %s command", silc_get_command_name(cmd->cmd)));
     cmd->cb(ctx, NULL);
-  else if (silc_server_is_registered(server, sock, ctx, cmd->cmd))
+  } else if (silc_server_is_registered(server, sock, ctx, cmd->cmd)) {
+    SILC_LOG_DEBUG(("Calling %s command", silc_get_command_name(cmd->cmd)));
     cmd->cb(ctx, NULL);
-  else
+  } else {
+    SILC_LOG_DEBUG(("Server is not registered"));
     silc_server_command_free(ctx);
+  }
 }
 
 /* Allocate Command Context */
@@ -3178,7 +3189,7 @@ static void silc_server_command_join_channel(SilcServer server,
   unsigned char *fkey = NULL;
   SilcUInt32 fkey_len = 0;
 
-  SILC_LOG_DEBUG(("Start"));
+  SILC_LOG_DEBUG(("Joining client to channel"));
 
   if (!channel)
     return;
@@ -3220,6 +3231,8 @@ static void silc_server_command_join_channel(SilcServer server,
    */
   if (auth && auth_len && channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
     SilcIDListData idata = (SilcIDListData)client;
+    SilcChannelClientEntry chl2;
+    SilcHashTableList htl;
 
     if (channel->founder_key && idata->public_key &&
        silc_pkcs_public_key_compare(channel->founder_key, 
@@ -3228,6 +3241,19 @@ static void silc_server_command_join_channel(SilcServer server,
       if (silc_auth_verify_data(auth, auth_len, SILC_AUTH_PUBLIC_KEY,
                                channel->founder_key, 0, server->sha1hash,
                                client->id, SILC_ID_CLIENT)) {
+
+       /* There cannot be anyone else as founder on the channel now.  This
+          client is definitely the founder due to this authentication */
+       silc_hash_table_list(channel->user_list, &htl);
+       while (silc_hash_table_get(&htl, NULL, (void *)&chl2))
+         if (chl2->mode & SILC_CHANNEL_UMODE_CHANFO) {
+           chl2->mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+           silc_server_force_cumode_change(server, NULL, channel, chl2,
+                                           chl2->mode);
+           break;
+         }
+       silc_hash_table_list_reset(&htl);
+
        umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
        founder = TRUE;
       }
@@ -3415,11 +3441,19 @@ static void silc_server_command_join_channel(SilcServer server,
      we'll ignore it (in packet_receive.c) so we must send it here. If
      we are router then this will send it to local clients and local
      servers. */
+  SILC_LOG_DEBUG(("Send JOIN notify to channel"));
   silc_server_send_notify_to_channel(server, NULL, channel, FALSE, 
                                     SILC_NOTIFY_TYPE_JOIN, 2,
                                     clidp->data, clidp->len,
                                     chidp->data, chidp->len);
 
+  /* Update statistics */
+  server->stat.my_chanclients++;
+  if (server->server_type == SILC_ROUTER) {
+    server->stat.cell_chanclients++;
+    server->stat.chanclients++;
+  }
+
   if (!cmd->pending) {
     /* Send JOIN notify packet to our primary router */
     if (!server->standalone)
@@ -3436,22 +3470,23 @@ static void silc_server_command_join_channel(SilcServer server,
        notify the mode change to the channel. */
     if (founder) {
       SILC_PUT32_MSB(chl->mode, mode);
+      SILC_LOG_DEBUG(("Send CUMODE_CHANGE notify to channel"));
       silc_server_send_notify_to_channel(server, NULL, channel, FALSE, 
                                         SILC_NOTIFY_TYPE_CUMODE_CHANGE, 4,
                                         clidp->data, clidp->len,
                                         mode, 4, clidp->data, clidp->len,
                                         fkey, fkey_len);
-      
-      /* Set CUMODE notify type to network */
-      if (!server->standalone)
-       silc_server_send_notify_cumode(server, server->router->connection,
-                                      server->server_type == SILC_ROUTER ? 
-                                      TRUE : FALSE, channel,
-                                      chl->mode, client->id, SILC_ID_CLIENT,
-                                      client->id, channel->founder_key);
     }
   }
 
+  /* Set CUMODE notify type to network */
+  if (founder && !server->standalone)
+    silc_server_send_notify_cumode(server, server->router->connection,
+                                  server->server_type == SILC_ROUTER ?
+                                  TRUE : FALSE, channel,
+                                  chl->mode, client->id, SILC_ID_CLIENT,
+                                  client->id, channel->founder_key);
+
   silc_buffer_free(reply);
   silc_buffer_free(clidp);
   silc_buffer_free(chidp);
@@ -3527,6 +3562,7 @@ SILC_SERVER_CMD_FUNC(join)
 
   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
     SilcClientEntry entry = (SilcClientEntry)cmd->sock->user_data;
+    silc_free(client_id);
     client_id = silc_id_dup(entry->id, SILC_ID_CLIENT);
 
     if (!channel || 
@@ -3543,6 +3579,7 @@ SILC_SERVER_CMD_FUNC(join)
                                         cmd, SILC_COMMAND_JOIN,
                                         SILC_STATUS_ERR_UNKNOWN_ALGORITHM,
                                         0);
+         silc_free(client_id);
          goto out;
        }
        
@@ -3563,8 +3600,10 @@ SILC_SERVER_CMD_FUNC(join)
          /* If this is pending command callback then we've resolved
             it and it didn't work, return since we've notified the
             client already in the command reply callback. */
-         if (cmd->pending)
+         if (cmd->pending) {
+           silc_free(client_id);
            goto out;
+         }
          
          old_ident = silc_command_get_ident(cmd->payload);
          silc_command_set_ident(cmd->payload, ++server->cmd_ident);
@@ -3584,6 +3623,7 @@ SILC_SERVER_CMD_FUNC(join)
          cmd->pending = TRUE;
           silc_command_set_ident(cmd->payload, old_ident);
          silc_buffer_free(tmpbuf);
+         silc_free(client_id);
          goto out;
        }
        
@@ -3599,6 +3639,7 @@ SILC_SERVER_CMD_FUNC(join)
            silc_server_command_send_status_reply(
                                       cmd, SILC_COMMAND_JOIN,
                                       SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0);
+           silc_free(client_id);
            goto out;
          }
 
@@ -3616,8 +3657,10 @@ SILC_SERVER_CMD_FUNC(join)
         something went wrong with the joining as the channel was not found.
         We can't do anything else but ignore this. */
       if (cmd->sock->type == SILC_SOCKET_TYPE_ROUTER ||
-         server->server_type != SILC_ROUTER)
+         server->server_type != SILC_ROUTER) {
+       silc_free(client_id);
        goto out;
+      }
       
       /* We are router and the channel does not seem exist so we will check
         our global list as well for the channel. */
@@ -3631,6 +3674,7 @@ SILC_SERVER_CMD_FUNC(join)
          silc_server_command_send_status_reply(
                                       cmd, SILC_COMMAND_JOIN,
                                       SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0);
+         silc_free(client_id);
          goto out;
        }
 
@@ -3650,6 +3694,18 @@ SILC_SERVER_CMD_FUNC(join)
       SILC_GET32_MSB(created, tmp);
       if (silc_argument_get_arg_type(reply->args, 7, NULL))
        create_key = FALSE;     /* Router returned the key already */
+
+      if (silc_command_get_status(reply->payload, NULL, NULL) &&
+         channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
+       /* Save channel passphrase, if user provided it successfully */
+       unsigned char *pa;
+       SilcUInt32 pa_len;
+       pa = silc_argument_get_arg_type(reply->args, 3, &pa_len);
+       if (pa) {
+         silc_free(channel->passphrase);
+         channel->passphrase = silc_memdup(pa, pa_len);
+       }
+      }
     }
 
     if (silc_command_get(reply->payload) == SILC_COMMAND_WHOIS &&
@@ -3704,7 +3760,8 @@ SILC_SERVER_CMD_FUNC(motd)
     if (server->config && server->config->server_info &&
        server->config->server_info->motd_file) {
       /* Send motd */
-      motd = silc_file_readfile(server->config->server_info->motd_file, &motd_len);
+      motd = silc_file_readfile(server->config->server_info->motd_file,
+                               &motd_len);
       if (!motd)
        goto out;
       
@@ -3859,6 +3916,15 @@ SILC_SERVER_CMD_FUNC(umode)
       }
     }
 
+    /* Update statistics */
+    if (mask & SILC_UMODE_GONE) {
+      if (!(client->mode & SILC_UMODE_GONE))
+       server->stat.my_aways++;
+    } else {
+      if (client->mode & SILC_UMODE_GONE)
+       server->stat.my_aways--;
+    }
+
     /* Change the mode */
     client->mode = mask;
 
@@ -4480,11 +4546,27 @@ SILC_SERVER_CMD_FUNC(cumode)
   if (target_mask & SILC_CHANNEL_UMODE_CHANOP) {
     /* Promote to operator */
     if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
+      if (!(sender_mask & SILC_CHANNEL_UMODE_CHANOP) && 
+          !(sender_mask & SILC_CHANNEL_UMODE_CHANFO)) {
+        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                              SILC_STATUS_ERR_NO_CHANNEL_PRIV,
+                                              0);
+        goto out;
+      }
+
       chl->mode |= SILC_CHANNEL_UMODE_CHANOP;
       notify = TRUE;
     }
   } else {
     if (chl->mode & SILC_CHANNEL_UMODE_CHANOP) {
+      if (!(sender_mask & SILC_CHANNEL_UMODE_CHANOP) &&
+          !(sender_mask & SILC_CHANNEL_UMODE_CHANFO)) {
+        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,   
+                                              SILC_STATUS_ERR_NO_CHANNEL_PRIV,
+                                              0);
+        goto out;
+      }
+      
       /* Demote to normal user */
       chl->mode &= ~SILC_CHANNEL_UMODE_CHANOP;
       notify = TRUE;
@@ -4900,8 +4982,6 @@ SILC_TASK_CALLBACK(silc_server_command_detach_timeout)
   SilcClientID *client_id = (SilcClientID *)q->sock;
   SilcClientEntry client;
 
-  SILC_LOG_DEBUG(("Start"));
-
   client = silc_idlist_find_client_by_id(q->server->local_list, client_id,
                                         FALSE, NULL);
 
@@ -4943,6 +5023,7 @@ SILC_SERVER_CMD_FUNC(detach)
     silc_server_send_notify_umode(server, server->router->connection,
                                  server->server_type == SILC_SERVER ?
                                  FALSE : TRUE, client->id, client->mode);
+  server->stat.my_detached++;
 
   /* Check if anyone is watching this nickname */
   if (server->server_type == SILC_ROUTER)
@@ -5623,8 +5704,6 @@ SILC_SERVER_CMD_FUNC(getkey)
   SilcIdType id_type;
   SilcPublicKey public_key;
 
-  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,