updates.
authorPekka Riikonen <priikone@silcnet.org>
Sun, 25 Mar 2001 18:17:05 +0000 (18:17 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Sun, 25 Mar 2001 18:17:05 +0000 (18:17 +0000)
CHANGES
apps/silcd/command.c
apps/silcd/idlist.c
apps/silcd/server.c
apps/silcd/server.h
doc/draft-riikonen-silc-pp-01.nroff
doc/draft-riikonen-silc-spec-01.nroff

diff --git a/CHANGES b/CHANGES
index c835fdbefe44d9fd9110f0a8d44d724cbffc52f5..100651d86ca2ec99076cb745db4eaccd5934c738 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,10 @@
+Sun Mar 25 20:27:09 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Added function silc_server_get_client_resolve to find the
+         client entry by ID from all ID lists and then resolve it
+         (using WHOIS) if it cannot be found.  Affected file is
+         silcd/server.[ch].
+
 Sun Mar 25 13:52:51 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
        * Implemented the BAN command to the client library.
index 7bfbc62d63b79e0ce0195313cd5050b1dafc6053..afd888f1d5094f0cecbf540326cc02c17db66e46 100644 (file)
@@ -2090,39 +2090,28 @@ SILC_SERVER_CMD_FUNC(topic)
   silc_server_command_free(cmd);
 }
 
-/* Server side of INVITE command. Invites some client to join some channel. */
+/* Server side of INVITE command. Invites some client to join some channel. 
+   This command is also used to manage the invite list of the channel. */
 
 SILC_SERVER_CMD_FUNC(invite)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
   SilcSocketConnection sock = cmd->sock, dest_sock;
+  SilcChannelClientEntry chl;
   SilcClientEntry sender, dest;
-  SilcClientID *dest_id;
+  SilcClientID *dest_id = NULL;
   SilcChannelEntry channel;
-  SilcChannelID *channel_id;
-  SilcBuffer sidp;
-  unsigned char *tmp;
+  SilcChannelID *channel_id = NULL;
+  SilcIDListData idata;
+  SilcBuffer idp;
+  unsigned char *tmp, *add, *del;
   unsigned int len;
 
   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INVITE, cmd, 1, 2);
 
-  /* Get destination ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
-  if (!tmp) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
-                                         SILC_STATUS_ERR_NO_CLIENT_ID);
-    goto out;
-  }
-  dest_id = silc_id_payload_parse_id(tmp, len);
-  if (!dest_id) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
-                                         SILC_STATUS_ERR_NO_CLIENT_ID);
-    goto out;
-  }
-
   /* Get Channel ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+  tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
   if (!tmp) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
                                          SILC_STATUS_ERR_NO_CHANNEL_ID);
@@ -2135,7 +2124,7 @@ SILC_SERVER_CMD_FUNC(invite)
     goto out;
   }
 
-  /* Check whether the channel exists */
+  /* Get the channel entry */
   channel = silc_idlist_find_channel_by_id(server->local_list, 
                                           channel_id, NULL);
   if (!channel) {
@@ -2159,8 +2148,6 @@ 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) {
-    SilcChannelClientEntry chl;
-
     silc_list_start(channel->user_list);
     while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
       if (chl->client == sender) {
@@ -2173,39 +2160,144 @@ SILC_SERVER_CMD_FUNC(invite)
       }
   }
 
-  /* Find the connection data for the destination. If it is local we will
-     send it directly otherwise we will send it to router for routing. */
-  dest = silc_idlist_find_client_by_id(server->local_list, dest_id, NULL);
-  if (dest)
-    dest_sock = (SilcSocketConnection)dest->connection;
-  else
-    dest_sock = silc_server_route_get(server, dest_id, SILC_ID_CLIENT);
+  /* Get destination client ID */
+  tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+  if (tmp) {
+    char invite[512];
 
-  /* Check whether the requested client is already on the channel. */
-  /* XXX if we are normal server we don't know about global clients on
-     the channel thus we must request it (USERS command), check from
-     local cache as well. */
-  if (silc_server_client_on_channel(dest, channel)) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
-                                         SILC_STATUS_ERR_USER_ON_CHANNEL);
-    goto out;
+    dest_id = silc_id_payload_parse_id(tmp, len);
+    if (!dest_id) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+                                           SILC_STATUS_ERR_NO_CLIENT_ID);
+      goto out;
+    }
+
+    /* Get the client entry */
+    dest = silc_server_get_client_resolve(server, dest_id);
+    if (!dest) {
+      if (server->server_type == SILC_ROUTER) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+                                    SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
+       goto out;
+      }
+      
+      /* The client info is being resolved. Reprocess this packet after
+        receiving the reply to the query. */
+      silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
+                                 server->cmd_ident,
+                                 silc_server_command_destructor,
+                                 silc_server_command_invite, 
+                                 silc_server_command_dup(cmd));
+      cmd->pending = TRUE;
+      silc_free(channel_id);
+      silc_free(dest_id);
+      return;
+    }
+
+    /* Check whether the requested client is already on the channel. */
+    if (silc_server_client_on_channel(dest, channel)) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+                                           SILC_STATUS_ERR_USER_ON_CHANNEL);
+      goto out;
+    }
+    
+    /* Get route to the client */
+    dest_sock = silc_server_get_client_route(server, tmp, len, &idata);
+
+    strncat(invite, dest->nickname, strlen(dest->nickname));
+    if (!strchr(dest->nickname, '@')) {
+      strncat(invite, "@", 1);
+      strncat(invite, server->server_name, strlen(server->server_name));
+    }
+    strncat(invite, "!", 1);
+    strncat(invite, dest->username, strlen(dest->username));
+    if (!strchr(dest->username, '@')) {
+      strncat(invite, "@", 1);
+      strncat(invite, cmd->sock->hostname, strlen(cmd->sock->hostname));
+    }
+
+    len = strlen(invite);
+    if (!channel->invite_list)
+      channel->invite_list = silc_calloc(len + 2, 
+                                        sizeof(*channel->invite_list));
+    else
+      channel->invite_list = silc_realloc(channel->ban_list, 
+                                         sizeof(*channel->invite_list) * 
+                                         (len + 
+                                          strlen(channel->invite_list) + 2));
+    strncat(channel->invite_list, invite, len);
+    strncat(channel->invite_list, ",", 1);
+
+    /* Send notify to the client that is invited to the channel */
+    idp = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
+    tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+    silc_server_send_notify_dest(server, dest_sock, FALSE, dest_id, 
+                                SILC_ID_CLIENT,
+                                SILC_NOTIFY_TYPE_INVITE, 2, 
+                                idp->data, idp->len, tmp, len);
+    silc_buffer_free(idp);
   }
 
-  sidp = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
+  /* Add the client to the invite list of the channel */
+  add = silc_argument_get_arg_type(cmd->args, 3, &len);
+  if (add && strlen(add) == len) {
+    if (!channel->invite_list)
+      channel->invite_list = silc_calloc(len + 2, 
+                                        sizeof(*channel->invite_list));
+    else
+      channel->invite_list = silc_realloc(channel->ban_list, 
+                                         sizeof(*channel->invite_list) * 
+                                         (len + 
+                                          strlen(channel->invite_list) + 2));
+    if (add[len - 1] == ',')
+      add[len - 1] = '\0';
+    
+    strncat(channel->invite_list, add, len);
+    strncat(channel->invite_list, ",", 1);
+  }
+
+  /* Get the invite to be removed and remove it from the list */
+  del = silc_argument_get_arg_type(cmd->args, 4, &len);
+  if (del && channel->invite_list) {
+    char *start, *end, *n;
+
+    if (!strncmp(channel->invite_list, del, 
+                strlen(channel->invite_list) - 1)) {
+      silc_free(channel->invite_list);
+      channel->invite_list = NULL;
+      goto out0;
+    }
+
+    start = strstr(channel->invite_list, del);
+    if (start && strlen(start) >= len) {
+      end = start + len;
+      n = silc_calloc(strlen(channel->invite_list) - len, sizeof(*n));
+      strncat(n, channel->invite_list, start - channel->invite_list);
+      strncat(n, end + 1, ((channel->invite_list + 
+                           strlen(channel->invite_list)) - end) - 1);
+      silc_free(channel->invite_list);
+      channel->invite_list = n;
+    }
+  }
+
+ out0:
+
+  idp = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
+
+  /* Send notify to the primary router */
 
-  /* Send notify to the client that is invited to the channel */
-  silc_server_send_notify_dest(server, dest_sock, FALSE, dest_id, 
-                              SILC_ID_CLIENT,
-                              SILC_NOTIFY_TYPE_INVITE, 2, 
-                              sidp->data, sidp->len, tmp, len);
 
   /* Send command reply */
   silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
                                        SILC_STATUS_OK);
 
-  silc_buffer_free(sidp);
+  silc_buffer_free(idp);
 
  out:
+  if (dest_id)
+    silc_free(dest_id);
+  if (channel_id)
+    silc_free(channel_id);
   silc_server_command_free(cmd);
 }
 
@@ -4437,7 +4529,7 @@ SILC_SERVER_CMD_FUNC(ban)
 
   /* Get the new ban and add it to the ban list */
   add = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
-  if (add) {
+  if (add && strlen(add) == tmp_len) {
     if (!channel->ban_list)
       channel->ban_list = silc_calloc(tmp_len + 2, sizeof(*channel->ban_list));
     else
@@ -4445,6 +4537,9 @@ SILC_SERVER_CMD_FUNC(ban)
                                       sizeof(*channel->ban_list) * 
                                       (tmp_len + 
                                        strlen(channel->ban_list) + 2));
+    if (add[tmp_len - 1] == ',')
+      add[tmp_len - 1] = '\0';
+
     strncat(channel->ban_list, add, tmp_len);
     strncat(channel->ban_list, ",", 1);
   }
index b5c17daf5627dd5b9e79f2063538d4085b01a66c..f756df1372948dd1c2d9a0f34aae74a0e7985f56 100644 (file)
@@ -385,7 +385,7 @@ silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
 /* XXX This actually checks the data, which can be hash of the nickname
    but is not if the client is local client. Global client on global
    list may have hash.  Thus, this is not fully reliable function.
-   Instead this should probably check the hash from the lists client ID's. */
+   Instead this should probably check the hash from the list of client ID's. */
 
 SilcClientEntry *
 silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname,
index 6df25f7bc93f276b37709b315996fe84704a7557..6134452413234de6dd20afb86fa2f1d52cab4ed4 100644 (file)
@@ -3245,3 +3245,40 @@ SilcBuffer silc_server_get_client_channel_list(SilcServer server,
 
   return buffer;
 }
+
+/* Finds client entry by Client ID and if it is not found then resolves
+   it using WHOIS command. */
+
+SilcClientEntry silc_server_get_client_resolve(SilcServer server,
+                                              SilcClientID *client_id)
+{
+  SilcClientEntry client;
+
+  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 && server->server_type == SILC_ROUTER)
+      return NULL;
+  }
+
+  if (!client && server->standalone)
+    return NULL;
+
+  if (!client || !client->nickname || !client->username) {
+    SilcBuffer buffer, idp;
+
+    idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
+                                           ++server->cmd_ident, 1,
+                                           3, idp->data, idp->len);
+    silc_server_packet_send(server, client ? client->router->connection :
+                           server->router->connection,
+                           SILC_PACKET_COMMAND, 0,
+                           buffer->data, buffer->len, FALSE);
+    silc_buffer_free(idp);
+    silc_buffer_free(buffer);
+  }
+
+  return client;
+}
index d65394e138db120194b464248608ba9133838afc..ded8b8086ae10146c956b5273ae50f520453ff89 100644 (file)
@@ -163,5 +163,7 @@ SilcSocketConnection silc_server_get_client_route(SilcServer server,
                                                  SilcIDListData *idata);
 SilcBuffer silc_server_get_client_channel_list(SilcServer server,
                                               SilcClientEntry client);
+SilcClientEntry silc_server_get_client_resolve(SilcServer server,
+                                              SilcClientID *client_id);
 
 #endif
index 1c8374fd2c2aaf7a1d191214f5ae9471e746144c..fed19883d135d2143815a2cad67076b08799d498 100644 (file)
@@ -1128,14 +1128,16 @@ ID's sent in arguments are sent inside ID Payload.
       is sent between routers and if the <Client ID> is argument is
       provided to the client as well.
 
-      Max Arguments:  4
-          Arguments:  (1) [<Client ID>]       (2) <Channel ID>
-                      (3) [<adding client>]   (4) [<removing client>]
+      Max Arguments:  5
+          Arguments:  (1) <Channel ID>          (2) [<Client ID>]
+                      (3) [<sender Client ID>]  (3) [<adding client>]
+                      (4) [<removing client>]
 
       The <Client ID> is the client which was invited to the channel.
-      The <Channel ID> is the channel.  The <adding client> and the
-      <removing client> indicates the added or removed client from the
-      channel's invite list.  The format of the <adding client and the
+      The <Channel ID> is the channel.  The <sender Client ID> is the
+      Client ID who invited the client to the channel.  The <adding client>
+      and the <removing client> indicates the added or removed client from
+      the channel's invite list.  The format of the <adding client and the
       <removing client> is defined in the [SILC1] with SILC_COMMAND_INVITE
       command.
 
index d641e083f55b5f31f5d99d2dad755cbc184de5f6..7dda5ce7b4f89fe3a9165a8d16f0d9690cf8b855 100644 (file)
@@ -2264,7 +2264,7 @@ List of all defined commands in SILC follows.
    7    SILC_COMMAND_INVITE
 
         Max Arguments:  4
-            Arguments:  (1) [<Client ID>]      (2) <Channel ID>
+            Arguments:  (1) <Channel ID>       (2) [<Client ID>]
                         (3) [<adding client>]  (4) [<removing client>]
 
         This command is used to invite other clients to join to the