Created SILC Client Libary by moving stuff from silc/ directory.
[silc.git] / apps / silcd / command.c
index fae70a4f7772cc8e1eaf9dcfd8238bd7561897d7..0c52c4e251509ce9dfe2eecbf2ec04c5711643d9 100644 (file)
 /*
  * $Id$
  * $Log$
+ * Revision 1.13  2000/08/21 14:21:21  priikone
+ *     Fixed channel joining and channel message sending inside a
+ *     SILC cell. Added silc_server_send_remove_channel_user and
+ *     silc_server_remove_channel_user functions.
+ *
+ * Revision 1.12  2000/07/26 07:05:11  priikone
+ *     Fixed the server to server (server to router actually) connections
+ *     and made the private message work inside a cell. Added functin
+ *     silc_server_replace_id.
+ *
+ * Revision 1.11  2000/07/19 07:08:09  priikone
+ *     Added version detection support to SKE.
+ *
+ * Revision 1.10  2000/07/17 11:47:30  priikone
+ *     Added command lagging support. Added idle counting support.
+ *
  * Revision 1.9  2000/07/12 05:59:41  priikone
  *     Major rewrite of ID Cache system. Support added for the new
  *     ID cache system. Major rewrite of ID List stuff on server.  All
@@ -157,6 +173,24 @@ void silc_server_command_process(SilcServer server,
 {
   SilcServerCommandContext ctx;
   SilcServerCommand *cmd;
+
+  /* Check whether it is allowed for this connection to execute any
+     command. */
+  if (sock->type == SILC_SOCKET_TYPE_CLIENT) {
+    time_t curtime;
+    SilcClientEntry client = (SilcClientEntry)sock->user_data;
+
+    if (!client)
+      goto out;
+
+    /* Allow only one command executed in 2 seconds. */
+    curtime = time(NULL);
+    if (client->last_command && (curtime - client->last_command) < 2)
+      goto out;
+
+    /* Update access time */
+    client->last_command = curtime;
+  }
   
   /* Allocate command context. This must be free'd by the
      command routine receiving it. */
@@ -192,9 +226,10 @@ void silc_server_command_process(SilcServer server,
   if (cmd == NULL) {
     SILC_LOG_ERROR(("Unknown command, packet dropped"));
     silc_free(ctx);
-    return;
+    goto out;
   }
 
+ out:
   silc_buffer_free(packet->buffer);
 }
 
@@ -409,6 +444,7 @@ SILC_SERVER_CMD_FUNC(whois)
   /* XXX */
   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
     char nh[256], uh[256];
+    unsigned char idle[4];
     SilcSocketConnection hsock;
 
     memset(uh, 0, sizeof(uh));
@@ -427,23 +463,27 @@ SILC_SERVER_CMD_FUNC(whois)
     len = hsock->hostname ? strlen(hsock->hostname) : strlen(hsock->ip);
     strncat(uh, hsock->hostname ? hsock->hostname : hsock->ip, len);
 
+    SILC_PUT32_MSB((time(NULL) - entry->last_receive), idle);
+
     /* XXX */
     if (entry->userinfo)
       packet = 
         silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS,
-                                            SILC_STATUS_OK, 4
+                                            SILC_STATUS_OK, 5
                                             2, id_string, SILC_ID_CLIENT_LEN,
                                             3, nh, strlen(nh),
                                             4, uh, strlen(uh),
                                             5, entry->userinfo, 
-                                            strlen(entry->userinfo));
+                                            strlen(entry->userinfo),
+                                            7, idle, 4);
     else
       packet = 
         silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS,
-                                            SILC_STATUS_OK, 3
+                                            SILC_STATUS_OK, 4
                                             2, id_string, SILC_ID_CLIENT_LEN,
                                             3, nh, strlen(nh),
-                                            4, uh, strlen(uh));
+                                            4, uh, strlen(uh),
+                                            7, idle, 4);
 
   } else {
     /* XXX */
@@ -522,47 +562,44 @@ SILC_SERVER_CMD_FUNC(identify)
     count = atoi(tmp);
   }
 
-  /* Then, make the query from our local client list */
+  /* Find client */
   entry = silc_idlist_find_client_by_nickname(server->local_list,
                                              nick, NULL);
-  if (!entry) {
-
-    /* If we are normal server and are connected to a router we will
-       make global query from the router. */
-    if (server->server_type == SILC_SERVER && !server->standalone) {
-      SilcBuffer buffer = cmd->packet->buffer;
-
-      SILC_LOG_DEBUG(("Requesting identify from router"));
-
-      /* Send IDENTIFY command to our router */
-      silc_buffer_push(buffer, buffer->data - buffer->head);
-      silc_server_packet_forward(server, (SilcSocketConnection)
-                                server->id_entry->router->connection,
-                                buffer->data, buffer->len, TRUE);
-      goto out;
-    }
+  if (!entry)
+    entry = silc_idlist_find_client_by_hash(server->global_list,
+                                           nick, server->md5hash);
+
+  /* If client was not found and if we are normal server and are connected
+     to a router we will make global query from the router. */
+  if (!entry && server->server_type == SILC_SERVER && !server->standalone &&
+      !cmd->pending) {
+    SilcBuffer buffer = cmd->packet->buffer;
     
-    /* If we are router then we will check our global list as well. */
-    if (server->server_type == SILC_ROUTER) {
-      entry = 
-       silc_idlist_find_client_by_nickname(server->global_list,
-                                           nick, NULL);
-      if (!entry) {
-       silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
-                                            SILC_STATUS_ERR_NO_SUCH_NICK,
-                                            3, tmp, strlen(tmp));
-       goto out;
-      }
-      goto ok;
-    }
+    SILC_LOG_DEBUG(("Requesting identify from router"));
+    
+    /* Send IDENTIFY command to our router */
+    silc_buffer_push(buffer, buffer->data - buffer->head);
+    silc_server_packet_forward(server, (SilcSocketConnection)
+                              server->id_entry->router->connection,
+                              buffer->data, buffer->len, TRUE);
+    return;
+  }
+
+  /* If we are router we have checked our local list by nickname and our
+     global list by hash so far. It is possible that the client is still not
+     found and we'll check it from local list by hash. */
+  if (!entry && server->server_type == SILC_ROUTER)
+    entry = silc_idlist_find_client_by_hash(server->local_list,
+                                           nick, server->md5hash);
 
+  if (!entry) {
+    /* The client definitely does not exist */
     silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
                                         SILC_STATUS_ERR_NO_SUCH_NICK,
                                         3, tmp, strlen(tmp));
     goto out;
   }
 
- ok:
   /* Send IDENTIFY reply */
   id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
   tmp = silc_command_get_first_arg(cmd->payload, NULL);
@@ -571,7 +608,6 @@ SILC_SERVER_CMD_FUNC(identify)
                                                2, id_string, 
                                                SILC_ID_CLIENT_LEN,
                                                3, nick, strlen(nick));
-#if 0
   if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
     void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
     silc_server_packet_send_dest(server, cmd->sock, 
@@ -579,11 +615,11 @@ SILC_SERVER_CMD_FUNC(identify)
                                 id, cmd->packet->src_id_type,
                                 packet->data, packet->len, FALSE);
     silc_free(id);
-  } else
-#endif
+  } else {
     silc_server_packet_send(server, cmd->sock, 
                            SILC_PACKET_COMMAND_REPLY, 0, 
                            packet->data, packet->len, FALSE);
+  }
 
   silc_free(id_string);
   silc_buffer_free(packet);
@@ -1357,8 +1393,17 @@ SILC_SERVER_CMD_FUNC(leave)
     goto out;
   }
 
+  /* Notify routers that they should remove this client from their list
+     of clients on the channel. */
+  if (!server->standalone)
+    silc_server_send_remove_channel_user(server, 
+                                        server->id_entry->router->connection,
+                                        server->server_type == SILC_ROUTER ?
+                                        TRUE : FALSE, id_entry->id, id);
+
   /* Remove client from channel */
-  i = silc_server_remove_from_one_channel(server, sock, channel, id_entry);
+  i = silc_server_remove_from_one_channel(server, sock, channel, id_entry,
+                                         TRUE);
   silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
                                        SILC_STATUS_OK);
 
@@ -1489,6 +1534,8 @@ SILC_SERVER_CMD_FUNC(names)
       len++;
     }
   }
+  if (!name_list)
+    name_list = "";
 
   /* Assemble the Client ID list now */
   client_id_list = silc_buffer_alloc(SILC_ID_CLIENT_LEN *