updates.
[silc.git] / apps / silcd / command.c
index 98f1a29cbf73b1f609a36ff9455296a28e0b7756..3a0bd76fbe06d7feb456c3a180778a42b030c6a7 100644 (file)
@@ -56,6 +56,7 @@ SilcServerCommand silc_command_list[] =
   SILC_SERVER_CMD(quit, QUIT, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG_STRICT | SILC_CF_REG | SILC_CF_OPER),
   SILC_SERVER_CMD(info, INFO, SILC_CF_LAG | SILC_CF_REG),
+  SILC_SERVER_CMD(stats, STATS, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(ping, PING, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(oper, OPER, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
   SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG_STRICT | SILC_CF_REG),
@@ -394,7 +395,7 @@ silc_server_command_send_status_reply(SilcServerCommandContext cmd,
   SILC_LOG_DEBUG(("Sending command status %d", status));
 
   buffer = 
-    silc_command_reply_payload_encode_va(command, status, 
+    silc_command_reply_payload_encode_va(command, status, 0,
                                         silc_command_get_ident(cmd->payload),
                                         0);
   silc_server_packet_send(cmd->server, cmd->sock,
@@ -419,7 +420,7 @@ silc_server_command_send_status_data(SilcServerCommandContext cmd,
   SILC_LOG_DEBUG(("Sending command status %d", status));
 
   buffer = 
-    silc_command_reply_payload_encode_va(command, status, 
+    silc_command_reply_payload_encode_va(command, status, 0,
                                         silc_command_get_ident(cmd->payload),
                                         1, arg_type, arg, arg_len);
   silc_server_packet_send(cmd->server, cmd->sock,
@@ -438,16 +439,10 @@ silc_server_command_pending_error_check(SilcServerCommandContext cmd,
                                        SilcServerCommandReplyContext cmdr,
                                        SilcCommand command)
 {
-  SilcCommandStatus status;
-
   if (!cmd->pending || !cmdr)
     return FALSE;
 
-  SILC_GET16_MSB(status, silc_argument_get_arg_type(cmdr->args, 1, NULL));
-  if (status != SILC_STATUS_OK &&
-      status != SILC_STATUS_LIST_START &&
-      status != SILC_STATUS_LIST_ITEM &&
-      status != SILC_STATUS_LIST_END) {
+  if (!silc_command_get_status(cmdr->payload, NULL, NULL)) {
     SilcBuffer buffer;
 
     /* Send the same command reply payload */
@@ -801,7 +796,7 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
 
     packet = 
       silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
-                                          status, ident, 8, 
+                                          status, 0, ident, 8, 
                                           2, idp->data, idp->len,
                                           3, nh, strlen(nh),
                                           4, uh, strlen(uh),
@@ -1159,7 +1154,7 @@ silc_server_command_whowas_send_reply(SilcServerCommandContext cmd,
       
     packet = 
       silc_command_reply_payload_encode_va(SILC_COMMAND_WHOWAS,
-                                          status, ident, 4, 
+                                          status, 0, ident, 4, 
                                           2, idp->data, idp->len,
                                           3, nh, strlen(nh),
                                           4, uh, strlen(uh),
@@ -1818,7 +1813,7 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
 
       if (!entry->username) {
        packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
-                                                     status, ident, 2,
+                                                     status, 0, ident, 2,
                                                      2, idp->data, idp->len, 
                                                      3, nh, strlen(nh));
       } else {
@@ -1831,7 +1826,7 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
        }
        
        packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
-                                                     status, ident, 3,
+                                                     status, 0, ident, 3,
                                                      2, idp->data, idp->len, 
                                                      3, nh, strlen(nh),
                                                      4, uh, strlen(uh));
@@ -1869,7 +1864,7 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
       idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
       packet = 
        silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
-                                            status, ident, 2,
+                                            status, 0, ident, 2,
                                             2, idp->data, idp->len, 
                                             3, entry->server_name, 
                                             entry->server_name ? 
@@ -1906,7 +1901,7 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
       idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
       packet = 
        silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
-                                            status, ident, 2,
+                                            status, 0, ident, 2,
                                             2, idp->data, idp->len, 
                                             3, entry->channel_name, 
                                             entry->channel_name ? 
@@ -2061,7 +2056,7 @@ SILC_SERVER_CMD_FUNC(nick)
  send_reply:
   /* Send the new Client ID as reply command back to client */
   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NICK, 
-                                               SILC_STATUS_OK, ident, 1, 
+                                               SILC_STATUS_OK, 0, ident, 1, 
                                                2, nidp->data, nidp->len);
   silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
                          0, packet->data, packet->len, FALSE);
@@ -2136,7 +2131,7 @@ silc_server_command_list_send_reply(SilcServerCommandContext cmd,
     /* Send the reply */
     packet = 
       silc_command_reply_payload_encode_va(SILC_COMMAND_LIST, 
-                                          status, ident, 4,
+                                          status, 0, ident, 4,
                                           2, idp->data, idp->len,
                                           3, entry->channel_name, 
                                           strlen(entry->channel_name),
@@ -2175,7 +2170,7 @@ silc_server_command_list_send_reply(SilcServerCommandContext cmd,
     /* Send the reply */
     packet = 
       silc_command_reply_payload_encode_va(SILC_COMMAND_LIST, 
-                                          status, ident, 4,
+                                          status, 0, ident, 4,
                                           2, idp->data, idp->len,
                                           3, entry->channel_name, 
                                           strlen(entry->channel_name),
@@ -2361,7 +2356,7 @@ SILC_SERVER_CMD_FUNC(topic)
   /* Send the topic to client as reply packet */
   idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC, 
-                                               SILC_STATUS_OK, ident, 2, 
+                                               SILC_STATUS_OK, 0, ident, 2, 
                                                2, idp->data, idp->len,
                                                3, channel->topic, 
                                                channel->topic ? 
@@ -2485,7 +2480,8 @@ SILC_SERVER_CMD_FUNC(invite)
     }
     
     /* Get route to the client */
-    dest_sock = silc_server_get_client_route(server, NULL, 0, dest_id, &idata);
+    dest_sock = silc_server_get_client_route(server, NULL, 0, dest_id, 
+                                            &idata, NULL);
     if (!dest_sock) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
                                            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
@@ -2581,7 +2577,7 @@ SILC_SERVER_CMD_FUNC(invite)
   if (add || del)
     packet = 
       silc_command_reply_payload_encode_va(SILC_COMMAND_INVITE,
-                                          SILC_STATUS_OK, ident, 2,
+                                          SILC_STATUS_OK, 0, ident, 2,
                                           2, tmp, len,
                                           3, channel->invite_list,
                                           channel->invite_list ?
@@ -2589,7 +2585,7 @@ SILC_SERVER_CMD_FUNC(invite)
   else
     packet = 
       silc_command_reply_payload_encode_va(SILC_COMMAND_INVITE,
-                                          SILC_STATUS_OK, ident, 1,
+                                          SILC_STATUS_OK, 0, ident, 1,
                                           2, tmp, len);
   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
                          packet->data, packet->len, FALSE);
@@ -2776,7 +2772,7 @@ SILC_SERVER_CMD_FUNC(kill)
     /* Update statistics */
     if (remote_client->connection)
       server->stat.my_clients--;
-    if (server->server_type == SILC_ROUTER)
+    if (server->stat.cell_clients)
       server->stat.cell_clients--;
     SILC_OPER_STATS_UPDATE(remote_client, server, SILC_UMODE_SERVER_OPERATOR);
     SILC_OPER_STATS_UPDATE(remote_client, router, SILC_UMODE_ROUTER_OPERATOR);
@@ -2934,7 +2930,7 @@ SILC_SERVER_CMD_FUNC(info)
 
   /* Send the reply */
   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
-                                               SILC_STATUS_OK, ident, 3,
+                                               SILC_STATUS_OK, 0, ident, 3,
                                                2, idp->data, idp->len,
                                                3, server_name, 
                                                strlen(server_name),
@@ -2990,6 +2986,102 @@ SILC_SERVER_CMD_FUNC(ping)
   silc_server_command_free(cmd);
 }
 
+/* Server side of command STATS. */
+
+SILC_SERVER_CMD_FUNC(stats)
+{
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+  SilcServer server = cmd->server;
+  SilcServerID *server_id;
+  unsigned char *tmp;
+  SilcUInt32 tmp_len;
+  SilcBuffer packet, stats;
+  SilcUInt16 ident = silc_command_get_ident(cmd->payload);
+  SilcUInt32 uptime;
+
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_STATS, cmd, 1, 1);
+
+  /* Get Server ID */
+  tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+  if (!tmp) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
+                                         SILC_STATUS_ERR_NO_SERVER_ID);
+    goto out;
+  }
+  server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+  if (!server_id)
+    goto out;
+
+  /* The ID must be ours */
+  if (!SILC_ID_SERVER_COMPARE(server->id, server_id)) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
+                                         SILC_STATUS_ERR_NO_SUCH_SERVER);
+    silc_free(server_id);
+    goto out;
+  }
+  silc_free(server_id);
+
+  /* If we are router then just send everything we got. If we are normal
+     server then we'll send this to our router to get all the latest
+     statistical information. */
+  if (!cmd->pending && server->server_type != SILC_ROUTER && 
+      !server->standalone) {
+    /* Send request to our router */
+    SilcBuffer idp = silc_id_payload_encode(server->router->id, 
+                                           SILC_ID_SERVER);
+    packet = silc_command_payload_encode_va(SILC_COMMAND_STATS, 
+                                           ++server->cmd_ident, 1,
+                                           1, idp->data, idp->len);
+    silc_server_packet_send(server, server->router->connection,
+                           SILC_PACKET_COMMAND, 0, packet->data,
+                           packet->len, FALSE);
+
+    /* Reprocess this packet after received reply from router */
+    silc_server_command_pending(server, SILC_COMMAND_STATS, 
+                               server->cmd_ident,
+                               silc_server_command_stats,
+                               silc_server_command_dup(cmd));
+    cmd->pending = TRUE;
+    silc_buffer_free(packet);
+    silc_buffer_free(idp);
+    goto out;
+  }
+
+  /* Send our reply to sender */
+  uptime = time(NULL) - server->starttime;
+
+  stats = silc_buffer_alloc_size(60);
+  silc_buffer_format(stats,
+                    SILC_STR_UI_INT(server->starttime),
+                    SILC_STR_UI_INT(uptime),
+                    SILC_STR_UI_INT(server->stat.my_clients),
+                    SILC_STR_UI_INT(server->stat.my_channels),
+                    SILC_STR_UI_INT(server->stat.my_server_ops),
+                    SILC_STR_UI_INT(server->stat.my_router_ops),
+                    SILC_STR_UI_INT(server->stat.cell_clients),
+                    SILC_STR_UI_INT(server->stat.cell_channels),
+                    SILC_STR_UI_INT(server->stat.cell_servers),
+                    SILC_STR_UI_INT(server->stat.clients),
+                    SILC_STR_UI_INT(server->stat.channels),
+                    SILC_STR_UI_INT(server->stat.servers),
+                    SILC_STR_UI_INT(server->stat.routers),
+                    SILC_STR_UI_INT(server->stat.server_ops),
+                    SILC_STR_UI_INT(server->stat.router_ops),
+                    SILC_STR_END);
+
+  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_STATS, 
+                                               SILC_STATUS_OK, 0, ident, 2,
+                                               2, tmp, tmp_len,
+                                               3, stats->data, stats->len);
+  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
+                         0, packet->data, packet->len, FALSE);
+  silc_buffer_free(packet);
+  silc_buffer_free(stats);
+
+ out:
+  silc_server_command_free(cmd);
+}
+
 /* Internal routine to join channel. The channel sent to this function
    has been either created or resolved from ID lists. This joins the sent
    client to the channel. */
@@ -3215,7 +3307,7 @@ static void silc_server_command_join_channel(SilcServer server,
 
   reply = 
     silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
-                                        SILC_STATUS_OK, ident, 13,
+                                        SILC_STATUS_OK, 0, ident, 13,
                                         2, channel->channel_name,
                                         strlen(channel->channel_name),
                                         3, chidp->data, chidp->len,
@@ -3470,8 +3562,7 @@ SILC_SERVER_CMD_FUNC(join)
 
   /* Check whether the channel was created by our router */
   if (cmd->pending && context2) {
-    SilcServerCommandReplyContext reply = 
-      (SilcServerCommandReplyContext)context2;
+    SilcServerCommandReplyContext reply = context2;
 
     if (silc_command_get(reply->payload) == SILC_COMMAND_JOIN) {
       tmp = silc_argument_get_arg_type(reply->args, 6, NULL);
@@ -3537,13 +3628,15 @@ SILC_SERVER_CMD_FUNC(motd)
       
       motd[motd_len] = 0;
       packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
-                                                   SILC_STATUS_OK, ident, 2,
+                                                   SILC_STATUS_OK, 0, 
+                                                   ident, 2,
                                                    2, idp, idp->len,
                                                    3, motd, motd_len);
     } else {
       /* No motd */
       packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
-                                                   SILC_STATUS_OK, ident, 1,
+                                                   SILC_STATUS_OK, 0, 
+                                                   ident, 1,
                                                    2, idp, idp->len);
     }
 
@@ -3619,7 +3712,7 @@ SILC_SERVER_CMD_FUNC(motd)
 
     idp = silc_id_payload_encode(server->id_entry->id, SILC_ID_SERVER);
     packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
-                                                 SILC_STATUS_OK, ident, 2,
+                                                 SILC_STATUS_OK, 0, ident, 2,
                                                  2, idp, idp->len,
                                                  3, entry->motd,
                                                  entry->motd ? 
@@ -3669,6 +3762,21 @@ SILC_SERVER_CMD_FUNC(umode)
     goto out;
   }
 
+  /* Anonymous mode cannot be set by client */
+  if (mask & SILC_UMODE_ANONYMOUS) {
+    if (!(client->mode & SILC_UMODE_ANONYMOUS)) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
+                                           SILC_STATUS_ERR_PERM_DENIED);
+      goto out;
+    }
+  } else {
+    if (client->mode & SILC_UMODE_ANONYMOUS) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
+                                           SILC_STATUS_ERR_PERM_DENIED);
+      goto out;
+    }
+  }
+
   /* Change the mode */
   client->mode = mask;
 
@@ -3679,7 +3787,7 @@ SILC_SERVER_CMD_FUNC(umode)
 
   /* Send command reply to sender */
   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_UMODE,
-                                               SILC_STATUS_OK, ident, 1,
+                                               SILC_STATUS_OK, 0, ident, 1,
                                                2, tmp_mask, 4);
   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
                          packet->data, packet->len, FALSE);
@@ -4053,7 +4161,7 @@ SILC_SERVER_CMD_FUNC(cmode)
 
   /* Send command reply to sender */
   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
-                                               SILC_STATUS_OK, ident, 2,
+                                               SILC_STATUS_OK, 0, ident, 2,
                                                2, tmp_id, tmp_len2,
                                                3, tmp_mask, 4);
   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
@@ -4184,18 +4292,18 @@ SILC_SERVER_CMD_FUNC(cumode)
   }
 
   if (target_mask & SILC_CHANNEL_UMODE_CHANFO) {
+    if (target_client != client) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                           SILC_STATUS_ERR_NOT_YOU);
+      goto out;
+    }
+
     if (!(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
       /* The client tries to claim the founder rights. */
       unsigned char *tmp_auth;
       SilcUInt32 tmp_auth_len, auth_len;
       void *auth;
       
-      if (target_client != client) {
-       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
-                                             SILC_STATUS_ERR_NOT_YOU);
-       goto out;
-      }
-
       if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) ||
          !channel->founder_key || !idata->public_key ||
          !silc_pkcs_public_key_compare(channel->founder_key, 
@@ -4270,6 +4378,31 @@ SILC_SERVER_CMD_FUNC(cumode)
     }
   }
 
+  if (target_mask & SILC_CHANNEL_UMODE_BLOCK_MESSAGES) {
+    if (target_client != client) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                           SILC_STATUS_ERR_NOT_YOU);
+      goto out;
+    }
+
+    if (!(chl->mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES)) {
+      chl->mode |= SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
+      notify = TRUE;
+    }
+  } else {
+    if (chl->mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES) {
+      if (target_client != client) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                             SILC_STATUS_ERR_NOT_YOU);
+       goto out;
+      }
+
+      chl->mode &= ~SILC_CHANNEL_UMODE_BLOCK_MESSAGES;
+      notify = TRUE;
+    }
+  }
+
+
   idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
   tmp_id = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
 
@@ -4293,7 +4426,7 @@ SILC_SERVER_CMD_FUNC(cumode)
 
   /* Send command reply to sender */
   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CUMODE,
-                                               SILC_STATUS_OK, ident, 3,
+                                               SILC_STATUS_OK, 0, ident, 3,
                                                2, tmp_mask, 4,
                                                3, tmp_ch_id, tmp_ch_len,
                                                4, tmp_id, tmp_len);
@@ -4752,7 +4885,7 @@ SILC_SERVER_CMD_FUNC(ban)
   /* Send the reply back to the client */
   packet = 
     silc_command_reply_payload_encode_va(SILC_COMMAND_BAN,
-                                        SILC_STATUS_OK, ident, 2,
+                                        SILC_STATUS_OK, 0, ident, 2,
                                         2, id, id_len,
                                         3, channel->ban_list, 
                                         channel->ban_list ? 
@@ -4966,7 +5099,7 @@ SILC_SERVER_CMD_FUNC(users)
   /* Send reply */
   idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_USERS,
-                                               SILC_STATUS_OK, ident, 4,
+                                               SILC_STATUS_OK, 0, ident, 4,
                                                2, idp->data, idp->len,
                                                3, lc, 4,
                                                4, client_id_list->data,
@@ -5041,7 +5174,7 @@ SILC_SERVER_CMD_FUNC(getkey)
       SilcSocketConnection dest_sock;
       
       dest_sock = silc_server_get_client_route(server, NULL, 0, 
-                                              client_id, NULL);
+                                              client_id, NULL, NULL);
       if (!dest_sock)
        goto out;
       
@@ -5161,7 +5294,7 @@ SILC_SERVER_CMD_FUNC(getkey)
 
   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_GETKEY,
-                                               SILC_STATUS_OK, ident, 
+                                               SILC_STATUS_OK, 0, ident, 
                                                pkdata ? 2 : 1,
                                                2, tmp, tmp_len,
                                                3, pkdata, pklen);