updates.
authorPekka Riikonen <priikone@silcnet.org>
Tue, 10 Jul 2001 20:27:56 +0000 (20:27 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Tue, 10 Jul 2001 20:27:56 +0000 (20:27 +0000)
22 files changed:
CHANGES
TODO
apps/irssi/src/silc/core/client_ops.c
apps/irssi/src/silc/core/silc-channels.c
apps/irssi/src/silc/core/silc-servers.c
apps/silcd/command.c
apps/silcd/command.h
apps/silcd/command_reply.c
apps/silcd/command_reply.h
apps/silcd/idlist.c
apps/silcd/server.c
doc/draft-riikonen-silc-commands-01.nroff
lib/silcclient/client.c
lib/silcclient/client_notify.c
lib/silcclient/command.c
lib/silcclient/command.h
lib/silcclient/command_reply.c
lib/silcclient/command_reply.h
lib/silcclient/idlist.c
lib/silcclient/idlist.h
lib/silcclient/silcapi.h
lib/silccore/silccommand.h

diff --git a/CHANGES b/CHANGES
index 235f84174bf2e39f326569cbfca7825860beec9c..f170b1d9ee6932d8ff350d78f7d289deff96304d 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,75 @@
+Tue Jul 10 18:05:38 EEST 2001  Pekka Riikonen <priikone@silcnet.org>
+
+       * Added SilcServerEntry context into the client library
+         to represent one server.  The INFO command now allocates
+         these to save the resolved server info.  For now on the
+         client library will also keep information about servers,
+         connected and resolved with INFO.
+
+         The INFO command now allocates the SilcServerEntry context
+         and saves the server info there.  The COMMAND_REPLY in
+         the INFO now returns the parameters to application in 
+         same order as defined in the protocol specification.
+
+         The entries are cached in the client->server_cache.
+
+       * The INFO command is now issued after received the Client ID
+         from the server.  Affected file lib/silcclient/client.c.
+
+       * The CMODE_CHANGE notify may now return also an SilcServerEntry
+         to the application as the mode changer might be server.
+         It is guaranteed that NULL is not returned anymore to the
+         application.  Affected file lib/silcclient/client_notify.c.
+
+         The ID Type is now also passed to the application so that
+         it can check whether the returned entry is SilcClientEntry
+         or SilcServerEntry.
+
+         Added new function silc_client_get_server_by_id to return
+         the server entry by ID.  Affected files are the
+         lib/silcclient/silcapi.h and lib/silcclient/idlist.c.
+
+       * Do not create the channel in the Irssi SILC Client when issuing
+         the JOIN command but when received the sucessful JOIN command
+         reply.  Otherwise the channel might get created even though we
+         could not join it.  The Affected file is
+         irssi/src/silc/core/[silc-channels.c/client_ops.c].
+
+       * Fixed a channel joining bug in router.  The router must also
+         check the channel modes, invite and ban lists etc. when serving
+         the JOIN command sent by normal server.  Affected file is
+         silcd/command.c.  The router now resolves the client's 
+         information from the server who sent the JOIN command if it
+         does not know it, and processes the JOIN command only after
+         that.
+
+       * Changed the SilcCommandCb to take new argument; void *context2.
+         Affected file lib/silccore/silccommand.h
+
+         The second argument in the command callbacks in the server now
+         includes the SilcServerCommandReplyContext if the command was
+         called as pending command callback from the command reply.
+         Otherwise it is NULL. When called as pending the status of the
+         command reply will be checked and if it was erronous the
+         error will be sent to the original sender of the command.
+         This way the client always receives the error messages even
+         though the server was actually the one who received the error
+         when it resent the command to router, for example.  Affected
+         files silcd/command[_reply].[ch].
+
+       * Fixed sending WHOWAS command's error message to client if
+         the requested client could not be found.  It was missing.
+         silcd/command.c.
+
+       * Changed the CMODE and CUMODE commands reply arguments in the
+         protocol specification.  The Channel ID is now sent in both
+         of the commands to identify the channel.  Implemented this
+         new feature to the client and server.  Affected files
+         lib/silcclient/command_reply.c and silcd/command.c.
+
+       * Made better checks for invite and ban lists in the JOIN
+         command in server.  Affected file silcd/command.c.
+
 Mon Jul  9 18:28:34 EEST 2001  Pekka Riikonen <priikone@silcnet.org>
 
        * The server now performs the incoming host IP/DNS lookup
diff --git a/TODO b/TODO
index 745a026bbdae379e44680795d6d74c7bfe06d77b..b6c1447d4f20b558a408eecb4ade3fc92af00137 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,23 +1,15 @@
 TODO/bugs in Irssi SILC client
 ==============================
 
- o Do not let irssi update the status bar on JOIN until the join command
-   is successful, so that it does not update that I'm on the channel
-   even though I could not join the channel.
-
- o The CMODE notify handling in client library may return NULL
-   client entry pointer to the application (when server was the CMODE's
-   executor).  Fix this somehow.
-
- o Add PERL scripting support from Irssi CVS.
+ o We should get rid of the clientconfig.[ch] in Irssi SILC and move the
+   cipher, hash, hmac and pkcs configuration to the Irssi SILC's config
+   file.
 
  o Add local commands to list the current server and client public keys
    that the user has.  And a local command to dump the contents of the
    public key to the screen.  Something like LISTKEYS, SHOWKEY...
 
- o We should get rid of the clientconfig.[ch] in Irssi SILC and move the
-   cipher, hash, hmac and pkcs configuration to the Irssi SILC's config
-   file.
+ o Add PERL scripting support from Irssi CVS.
 
  o Extend the /HELP command to support sub commands or something.  So
    that user can say /help set mutual_authentication they would get
@@ -30,20 +22,11 @@ TODO/bugs in Irssi SILC client
 TODO/bugs In SILC Client Library
 ================================
 
- o Library should save the cumode and not start from 0 everytime then
-   CUMODE is issued.  A mechanism of getting the channel entry for
-   CMODE and CUMODE by the command reply identifier must be added.
-   Otherwise saving the modes for the channels and channel user
-   entries are impossible since server does not send Channel ID as
-   command reply in these commands.
-
  o All protocol execution timeouts are hard coded. They should be 
    configurable and the Irssi SILC client should be able to set them
    with for example /set key_exchange_timeout etc.  The silc_client_alloc
    should take a Params structure or something as argument.
 
- o silc_client_close_connection leaks memory.  Read the XXX from code.
-
  o The client library must manage somehow when receiving client that has
    same nickname, same server, same username but different Client ID than
    what we have in the cache.  It is now assumed that they are different
@@ -52,6 +35,8 @@ TODO/bugs In SILC Client Library
    interface separately or it could just remove the old client unless
    it is on some channels.
 
+ o silc_client_close_connection leaks memory.  Read the XXX from code.
+
 
 TODO/bugs In SILC Server
 ========================
index 12fe0f4eb13e2a37618ff300812a03c80c31bbef..b873e2cb9ed15ba194820b057a7866d042be3c02 100644 (file)
@@ -496,11 +496,9 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
       client_id_list = va_arg(vp, SilcBuffer);
 
       chanrec = silc_channel_find(server, channel);
-      if (chanrec != NULL && !success)
-       channel_destroy(CHANNEL(chanrec));
-      else if (chanrec == NULL && success)
+      if (!chanrec)
        chanrec = silc_channel_create(server, channel, TRUE);
-      
+
       if (topic) {
        g_free_not_null(chanrec->topic);
        chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
index c823e0a5e1699c87ca15ef31fbcaf3030a942152..5bf3383e920fd6dca98be97824b7566709c0d700 100644 (file)
@@ -89,7 +89,6 @@ static void silc_channels_join(SILC_SERVER_REC *server,
       continue;
     }
 
-    silc_channel_create(server, channel, FALSE);
     silc_command_exec(server, "JOIN", channel);
     g_free(channel);
   }
@@ -289,12 +288,16 @@ static void event_nick(SILC_SERVER_REC *server, va_list va)
 static void event_cmode(SILC_SERVER_REC *server, va_list va)
 {
   SILC_CHANNEL_REC *chanrec;
+  void *entry;
   SilcClientEntry client;
+  SilcServerEntry server_entry;
   SilcChannelEntry channel;
   char *mode;
   uint32 modei;
+  SilcIdType idtype;
 
-  client = va_arg(va, SilcClientEntry);
+  idtype = va_arg(va, SilcIdType);
+  entry = va_arg(va, void *);
   modei = va_arg(va, uint32);
   (void)va_arg(va, char *);
   (void)va_arg(va, char *);
@@ -311,10 +314,19 @@ static void event_cmode(SILC_SERVER_REC *server, va_list va)
     signal_emit("channel mode changed", 1, chanrec);
   }
   
-  printformat_module("fe-common/silc", server, channel->channel_name,
-                    MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
-                    channel->channel_name, mode ? mode : "removed all",
-                    client->nickname);
+  if (idtype == SILC_ID_CLIENT) {
+    client = (SilcClientEntry)entry;
+    printformat_module("fe-common/silc", server, channel->channel_name,
+                      MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
+                      channel->channel_name, mode ? mode : "removed all",
+                      client->nickname);
+  } else {
+    server_entry = (SilcServerEntry)entry;
+    printformat_module("fe-common/silc", server, channel->channel_name,
+                      MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
+                      channel->channel_name, mode ? mode : "removed all",
+                      server_entry->server_name);
+  }
   
   g_free(mode);
 }
index 05c76845519300b21dd251a7238e0b39036b8bf8..566b269a5c353dda7b44ae3ea660065774155839 100644 (file)
@@ -318,7 +318,7 @@ void silc_command_exec(SILC_SERVER_REC *server,
   ctx->argv_types = argv_types;
   
   /* Execute command */
-  (*cmd->cb)(ctx);
+  (*cmd->cb)(ctx, NULL);
 }
 
 /* Generic command function to call any SILC command directly. */
index b4c0b53017d61cb8845bb28afedc8b517beac19a..52a4a78f585434c6a7a4873a77a886941abc5bff 100644 (file)
@@ -37,6 +37,10 @@ silc_server_command_send_status_data(SilcServerCommandContext cmd,
                                     uint32 arg_type,
                                     unsigned char *arg,
                                     uint32 arg_len);
+static bool
+silc_server_command_pending_error_check(SilcServerCommandContext cmd,
+                                       SilcServerCommandReplyContext cmdr,
+                                       SilcCommand command);
 SILC_TASK_CALLBACK(silc_server_command_process_timeout);
 
 /* Server command list. */
@@ -76,12 +80,25 @@ SilcServerCommand silc_command_list[] =
   { NULL, 0 },
 };
 
-#define SILC_SERVER_COMMAND_CHECK_ARGC(command, context, min, max)           \
+/* Performs several checks to the command. It first checks whether this
+   command was called as pending command callback. If it was then it checks
+   whether error occurred in the command reply where the pending command
+   callback was called. 
+
+   It also checks that the requested command includes correct amount
+   of arguments. */
+#define SILC_SERVER_COMMAND_CHECK(command, context, min, max)                \
 do {                                                                         \
-  uint32 _argc = silc_argument_get_arg_num(cmd->args);               \
+  uint32 _argc;                                                                      \
                                                                              \
   SILC_LOG_DEBUG(("Start"));                                                 \
                                                                              \
+  if (silc_server_command_pending_error_check(cmd, context2, command)) {      \
+    silc_server_command_free(cmd);                                           \
+    return;                                                                  \
+  }                                                                          \
+                                                                             \
+  _argc = silc_argument_get_arg_num(cmd->args);                                      \
   if (_argc < min) {                                                         \
     silc_server_command_send_status_reply(cmd, command,                              \
                                          SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); \
@@ -132,12 +149,12 @@ SILC_TASK_CALLBACK(silc_server_command_process_timeout)
   client->last_command = time(NULL);
 
   if (!(timeout->cmd->flags & SILC_CF_REG))
-    timeout->cmd->cb(timeout->ctx);
+    timeout->cmd->cb(timeout->ctx, NULL);
   else if (silc_server_is_registered(timeout->ctx->server, 
                                     timeout->ctx->sock, 
                                     timeout->ctx, 
                                     timeout->cmd->cmd))
-    timeout->cmd->cb(timeout->ctx);
+    timeout->cmd->cb(timeout->ctx, NULL);
 
   silc_free(timeout);
 }
@@ -226,9 +243,9 @@ void silc_server_command_process(SilcServer server,
   /* Execute for server */
 
   if (!(cmd->flags & SILC_CF_REG))
-    cmd->cb(ctx);
+    cmd->cb(ctx, NULL);
   else if (silc_server_is_registered(server, sock, ctx, cmd->cmd))
-    cmd->cb(ctx);
+    cmd->cb(ctx, NULL);
 }
 
 /* Allocate Command Context */
@@ -389,6 +406,31 @@ silc_server_command_send_status_data(SilcServerCommandContext cmd,
   silc_buffer_free(buffer);
 }
 
+/* This function can be called to check whether in the command reply
+   an error occurred. This function has no effect if this is called
+   when the command function was not called as pending command callback. 
+   This returns TRUE if error had occurred. */
+
+static bool
+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) {
+    /* Send the error message */
+    silc_server_command_send_status_reply(cmd, command, status);
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
 /******************************************************************************
 
                               WHOIS Functions
@@ -919,7 +961,7 @@ SILC_SERVER_CMD_FUNC(whois)
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   int ret = 0;
 
-  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_WHOIS, cmd, 1, 3328);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WHOIS, cmd, 1, 3328);
 
   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
     ret = silc_server_command_whois_from_client(cmd);
@@ -1136,8 +1178,8 @@ silc_server_command_whowas_from_client(SilcServerCommandContext cmd)
      to our router if we are normal server, so let's do it now unless we
      are standalone. We will not send any replies to the client until we
      have received reply from the router. */
-  if (server->server_type == SILC_SERVER && 
-      !cmd->pending && !server->standalone) {
+  if (server->server_type == SILC_SERVER && !cmd->pending && 
+      !server->standalone) {
     SilcBuffer tmpbuf;
     uint16 old_ident;
 
@@ -1189,6 +1231,14 @@ silc_server_command_whowas_from_client(SilcServerCommandContext cmd)
                                    nick, server->md5hash,
                                    &clients, &clients_count);
   
+  if (!clients) {
+    /* Such a client really does not exist in the SILC network. */
+    silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOWAS,
+                                        SILC_STATUS_ERR_NO_SUCH_NICK,
+                                        3, nick, strlen(nick));
+    goto out;
+  }
+
   if (!silc_server_command_whowas_check(cmd, clients, clients_count)) {
     ret = -1;
     goto out;
@@ -1271,7 +1321,7 @@ SILC_SERVER_CMD_FUNC(whowas)
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   int ret = 0;
 
-  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_WHOWAS, cmd, 1, 2);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WHOWAS, cmd, 1, 2);
 
   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
     ret = silc_server_command_whowas_from_client(cmd);
@@ -1698,7 +1748,7 @@ SILC_SERVER_CMD_FUNC(identify)
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   int ret = 0;
 
-  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_IDENTIFY, cmd, 1, 3328);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_IDENTIFY, cmd, 1, 3328);
 
   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
     ret = silc_server_command_identify_from_client(cmd);
@@ -1743,7 +1793,7 @@ SILC_SERVER_CMD_FUNC(nick)
   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
     goto out;
 
-  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_NICK, cmd, 1, 1);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_NICK, cmd, 1, 1);
 
   /* Check nickname */
   nick = silc_argument_get_arg_type(cmd->args, 1, NULL);
@@ -1958,7 +2008,7 @@ SILC_SERVER_CMD_FUNC(list)
   SilcChannelEntry *lchannels = NULL, *gchannels = NULL;
   uint32 lch_count = 0, gch_count = 0;
 
-  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_LIST, cmd, 0, 2);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LIST, cmd, 0, 2);
 
   /* Get Channel ID */
   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
@@ -2004,7 +2054,7 @@ SILC_SERVER_CMD_FUNC(topic)
   uint32 argc, tmp_len;
   uint16 ident = silc_command_get_ident(cmd->payload);
 
-  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_TOPIC, cmd, 1, 2);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_TOPIC, cmd, 1, 2);
 
   argc = silc_argument_get_arg_num(cmd->args);
 
@@ -2130,7 +2180,7 @@ SILC_SERVER_CMD_FUNC(invite)
   uint32 len;
   uint16 ident = silc_command_get_ident(cmd->payload);
 
-  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INVITE, cmd, 1, 4);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_INVITE, cmd, 1, 4);
 
   /* Get Channel ID */
   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
@@ -2375,7 +2425,7 @@ SILC_SERVER_CMD_FUNC(quit)
   unsigned char *tmp = NULL;
   uint32 len = 0;
 
-  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_QUIT, cmd, 0, 1);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_QUIT, cmd, 0, 1);
 
   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
     goto out;
@@ -2412,7 +2462,7 @@ SILC_SERVER_CMD_FUNC(kill)
   unsigned char *tmp, *comment;
   uint32 tmp_len, tmp_len2;
 
-  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_KILL, cmd, 1, 2);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_KILL, cmd, 1, 2);
 
   if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
     goto out;
@@ -2535,7 +2585,7 @@ SILC_SERVER_CMD_FUNC(info)
   SilcServerEntry entry = NULL;
   SilcServerID *server_id = NULL;
 
-  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INFO, cmd, 0, 2);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_INFO, cmd, 0, 2);
 
   /* Get server name */
   dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
@@ -2694,7 +2744,7 @@ SILC_SERVER_CMD_FUNC(ping)
   uint32 len;
   unsigned char *tmp;
 
-  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INFO, cmd, 1, 2);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_INFO, cmd, 1, 2);
 
   /* Get Server ID */
   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
@@ -2742,7 +2792,7 @@ static void silc_server_command_join_channel(SilcServer server,
   SilcChannelClientEntry chl;
   SilcBuffer reply, chidp, clidp, keyp = NULL, user_list, mode_list;
   uint16 ident = silc_command_get_ident(cmd->payload);
-  char check[512];
+  char check[512], check2[512];
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -2753,35 +2803,55 @@ static void silc_server_command_join_channel(SilcServer server,
   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
     client = (SilcClientEntry)sock->user_data;
   } else {
-    client = silc_idlist_find_client_by_id(server->local_list, client_id, 
-                                          NULL);
-    if (!client)
-      goto out;
+    client = silc_server_get_client_resolve(server, client_id);
+    if (!client) {
+      if (cmd->pending)
+       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, NULL,
+                                 silc_server_command_join, 
+                                 silc_server_command_dup(cmd));
+      cmd->pending = TRUE;
+      return;
+    }
+
+    cmd->pending = FALSE;
   }
 
   /*
    * Check channel modes
    */
 
-  if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
-    strncat(check, client->nickname, strlen(client->nickname));
-    if (!strchr(client->nickname, '@')) {
-      strncat(check, "@", 1);
-      strncat(check, server->server_name, strlen(server->server_name));
-    }
-    strncat(check, "!", 1);
-    strncat(check, client->username, strlen(client->username));
-    if (!strchr(client->username, '@')) {
-      strncat(check, "@", 1);
-      strncat(check, cmd->sock->hostname, strlen(cmd->sock->hostname));
-    }
+  memset(check, 0, sizeof(check));
+  memset(check2, 0, sizeof(check2));
+  strncat(check, client->nickname, strlen(client->nickname));
+  strncat(check, "!", 1);
+  strncat(check, client->username, strlen(client->username));
+  if (!strchr(client->username, '@')) {
+    strncat(check, "@", 1);
+    strncat(check, cmd->sock->hostname, strlen(cmd->sock->hostname));
+  }
+
+  strncat(check2, client->nickname, strlen(client->nickname));
+  if (!strchr(client->nickname, '@')) {
+    strncat(check2, "@", 1);
+    strncat(check2, server->server_name, strlen(server->server_name));
+  }
+  strncat(check2, "!", 1);
+  strncat(check2, client->username, strlen(client->username));
+  if (!strchr(client->username, '@')) {
+    strncat(check2, "@", 1);
+    strncat(check2, cmd->sock->hostname, strlen(cmd->sock->hostname));
   }
 
   /* Check invite list if channel is invite-only channel */
-  if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT && 
-      channel->mode & SILC_CHANNEL_MODE_INVITE) {
+  if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
     if (!channel->invite_list ||
-       !silc_string_match(channel->invite_list, check)) {
+       (!silc_string_match(channel->invite_list, check) &&
+        !silc_string_match(channel->invite_list, check2))) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
                                            SILC_STATUS_ERR_NOT_INVITED);
       goto out;
@@ -2791,8 +2861,9 @@ static void silc_server_command_join_channel(SilcServer server,
   /* Check ban list if it exists. If the client's nickname, server,
      username and/or hostname is in the ban list the access to the
      channel is denied. */
-  if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT && channel->ban_list) {
-    if (silc_string_match(channel->ban_list, check)) {
+  if (channel->ban_list) {
+    if (silc_string_match(channel->ban_list, check) ||
+       silc_string_match(channel->ban_list, check2)) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
                              SILC_STATUS_ERR_BANNED_FROM_CHANNEL);
       goto out;
@@ -2953,7 +3024,7 @@ SILC_SERVER_CMD_FUNC(join)
   int created = FALSE;
   SilcClientID *client_id;
 
-  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_JOIN, cmd, 1, 4);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_JOIN, cmd, 1, 4);
 
   /* Get channel name */
   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
@@ -2970,7 +3041,6 @@ SILC_SERVER_CMD_FUNC(join)
   if (silc_server_command_bad_chars(channel_name) == TRUE) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
                                          SILC_STATUS_ERR_BAD_CHANNEL);
-    silc_free(channel_name);
     goto out;
   }
 
@@ -3034,6 +3104,12 @@ SILC_SERVER_CMD_FUNC(join)
        if (server->server_type == SILC_SERVER) {
          SilcBuffer tmpbuf;
          uint16 old_ident;
+
+         /* 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)
+           goto out;
          
          old_ident = silc_command_get_ident(cmd->payload);
          silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
@@ -3135,7 +3211,7 @@ SILC_SERVER_CMD_FUNC(motd)
   uint32 motd_len;
   uint16 ident = silc_command_get_ident(cmd->payload);
   
-  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_MOTD, cmd, 1, 1);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_MOTD, cmd, 1, 1);
 
   /* Get server name */
   dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
@@ -3282,7 +3358,7 @@ SILC_SERVER_CMD_FUNC(umode)
   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
     goto out;
 
-  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_UMODE, cmd, 2, 2);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_UMODE, cmd, 2, 2);
 
   /* Get the client's mode mask */
   tmp_mask = silc_argument_get_arg_type(cmd->args, 2, NULL);
@@ -3430,7 +3506,7 @@ SILC_SERVER_CMD_FUNC(cmode)
   uint32 mode_mask, tmp_len, tmp_len2;
   uint16 ident = silc_command_get_ident(cmd->payload);
 
-  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CMODE, cmd, 2, 7);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CMODE, cmd, 2, 7);
 
   /* Get Channel ID */
   tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
@@ -3744,8 +3820,9 @@ SILC_SERVER_CMD_FUNC(cmode)
 
   /* Send command reply to sender */
   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
-                                               SILC_STATUS_OK, ident, 1,
-                                               2, tmp_mask, 4);
+                                               SILC_STATUS_OK, ident, 2,
+                                               2, tmp_id, tmp_len2,
+                                               3, tmp_mask, 4);
   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
                          packet->data, packet->len, FALSE);
     
@@ -3776,7 +3853,7 @@ SILC_SERVER_CMD_FUNC(cumode)
   int notify = FALSE;
   uint16 ident = silc_command_get_ident(cmd->payload);
 
-  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CUMODE, cmd, 3, 4);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CUMODE, cmd, 3, 4);
 
   /* Get Channel ID */
   tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
@@ -3986,9 +4063,10 @@ SILC_SERVER_CMD_FUNC(cumode)
 
   /* Send command reply to sender */
   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CUMODE,
-                                               SILC_STATUS_OK, ident, 2,
+                                               SILC_STATUS_OK, ident, 3,
                                                2, tmp_mask, 4,
-                                               3, tmp_id, tmp_len);
+                                               3, tmp_ch_id, tmp_ch_len,
+                                               4, tmp_id, tmp_len);
   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
                          packet->data, packet->len, FALSE);
     
@@ -4017,7 +4095,7 @@ SILC_SERVER_CMD_FUNC(kick)
   uint32 tmp_len;
   unsigned char *tmp, *comment;
 
-  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_LEAVE, cmd, 1, 3);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LEAVE, cmd, 1, 3);
 
   /* Get Channel ID */
   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
@@ -4160,7 +4238,7 @@ SILC_SERVER_CMD_FUNC(oper)
   SilcServerConfigSectionAdminConnection *admin;
   SilcIDListData idata = (SilcIDListData)client;
 
-  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_OPER, cmd, 1, 2);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_OPER, cmd, 1, 2);
 
   if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
     goto out;
@@ -4232,7 +4310,7 @@ SILC_SERVER_CMD_FUNC(silcoper)
   SilcServerConfigSectionAdminConnection *admin;
   SilcIDListData idata = (SilcIDListData)client;
 
-  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_SILCOPER, cmd, 1, 2);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_SILCOPER, cmd, 1, 2);
 
   if (server->server_type == SILC_SERVER)
     goto out;
@@ -4306,7 +4384,7 @@ SILC_SERVER_CMD_FUNC(connect)
   uint32 tmp_len;
   uint32 port = SILC_PORT;
 
-  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CONNECT, cmd, 1, 2);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CONNECT, cmd, 1, 2);
 
   if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
     goto out;
@@ -4368,7 +4446,7 @@ SILC_SERVER_CMD_FUNC(ban)
   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
     goto out;
 
-  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_BAN, cmd, 0, 3);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_BAN, cmd, 0, 3);
 
   /* Get Channel ID */
   id = silc_argument_get_arg_type(cmd->args, 1, &id_len);
@@ -4496,7 +4574,7 @@ SILC_SERVER_CMD_FUNC(close)
   unsigned char *name;
   uint32 port = SILC_PORT;
 
-  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CLOSE, cmd, 1, 2);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CLOSE, cmd, 1, 2);
 
   if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
     goto out;
@@ -4551,7 +4629,7 @@ SILC_SERVER_CMD_FUNC(shutdown)
   SilcServer server = cmd->server;
   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
 
-  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_SHUTDOWN, cmd, 0, 0);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_SHUTDOWN, cmd, 0, 0);
 
   if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
     goto out;
@@ -4588,7 +4666,7 @@ SILC_SERVER_CMD_FUNC(leave)
   uint32 len;
   unsigned char *tmp;
 
-  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_LEAVE, cmd, 1, 2);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LEAVE, cmd, 1, 2);
 
   /* Get Channel ID */
   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
@@ -4673,7 +4751,7 @@ SILC_SERVER_CMD_FUNC(users)
   uint32 list_count = 0;
   uint16 ident = silc_command_get_ident(cmd->payload);
 
-  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_USERS, cmd, 1, 1);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_USERS, cmd, 1, 1);
 
   /* Get Channel ID */
   channel_id = silc_argument_get_arg_type(cmd->args, 1, &channel_id_len);
index 4134ee2e9450d2405c95f99364d1a98f3471dcea..7d884e169c84c1853dc7c1df79e94a55c6d8584a 100644 (file)
@@ -85,15 +85,21 @@ typedef struct SilcServerCommandPendingStruct {
 #define SILC_SERVER_CMD(func, cmd, flags) \
 { silc_server_command_##func, SILC_COMMAND_##cmd, flags }
 
-/* Macro used to declare command functions */
+/* Macro used to declare command functions. The `context' will be the
+   SilcServerCommandContext and the `context2' is the 
+   SilcServerCommandReplyContext if this function is called from the
+   command reply as pending command callback. Otherwise `context2' 
+   is NULL. */
 #define SILC_SERVER_CMD_FUNC(func) \
-void silc_server_command_##func(void *context)
-
-/* Executed pending command */
-#define SILC_SERVER_PENDING_EXEC(ctx, cmd)                             \
-do {                                                                   \
-  if (ctx->callback)                                                   \
-    (*ctx->callback)(ctx->context);                                    \
+void silc_server_command_##func(void *context, void *context2)
+
+/* Executed pending command. The first argument to the callback function
+   is the user specified context. The second argument is always the
+   SilcServerCommandReply context. */
+#define SILC_SERVER_PENDING_EXEC(ctx, cmd)     \
+do {                                           \
+  if (ctx->callback)                           \
+    (*ctx->callback)(ctx->context, ctx);       \
 } while(0)
 
 /* Execute destructor for pending command */
index 4717e3b77a440fa071f208cd6882a4fd84dc432d..a012aa8c7db56bbf843e87b706c5b60de4028f7c 100644 (file)
@@ -107,7 +107,7 @@ void silc_server_command_reply_process(SilcServer server,
     return;
   }
 
-  cmd->cb(ctx);
+  cmd->cb(ctx, NULL);
 }
 
 /* Free command reply context and its internals. */
index 213ed97932efdaaa684d0de3de033eb790203d56..75be5094ea0232dbf6c5c132821a6835ddb06c03 100644 (file)
@@ -54,7 +54,7 @@ typedef struct {
 
 /* Macro used to declare command reply functions */
 #define SILC_SERVER_CMD_REPLY_FUNC(func) \
-void silc_server_command_reply_##func(void *context)
+void silc_server_command_reply_##func(void *context, void *context2)
 
 /* Prototypes */
 void silc_server_command_reply_free(SilcServerCommandReplyContext cmd);
index abcfb9f12c34e14b5f1594019df606783ce6516d..4e5f5272a8c7305dcd7bfc7b2936b7a566d9d3de 100644 (file)
@@ -144,6 +144,8 @@ silc_idlist_find_server_by_id(SilcIDList id_list, SilcServerID *id,
   if (ret_entry)
     *ret_entry = id_cache;
 
+  SILC_LOG_DEBUG(("Found"));
+
   return server;
 }
 
index 707e1d2d385beb1dfb2f656fd54517528da5562e..38f645e49338ac19068edc549ff44c093e289f82 100644 (file)
@@ -3834,6 +3834,7 @@ SilcClientEntry silc_server_get_client_resolve(SilcServer server,
                            buffer->data, buffer->len, FALSE);
     silc_buffer_free(idp);
     silc_buffer_free(buffer);
+    return NULL;
   }
 
   return client;
index bf1aa6008364c9688054760ea1be1f27c4338f87..c03fd1929df64c4ce8176015dae0d4273df19aeb 100644 (file)
@@ -1163,8 +1163,9 @@ List of all defined commands in SILC follows.
 
         Reply messages to the command:
 
-        Max Arguments:  2
-            Arguments:  (1) <Status Payload>  (2) <channel mode mask>
+        Max Arguments:  3
+            Arguments:  (1) <Status Payload>  (2) <Channel ID>
+                        (3) <channel mode mask>
 
         This command replies with the changed channel mode mask that
         client MUST keep locally.
@@ -1230,12 +1231,13 @@ List of all defined commands in SILC follows.
 
         Reply messages to the command:
 
-        Max Arguments:  3
+        Max Arguments:  4
             Arguments:  (1) <Status Payload>  (2) <channel user mode mask>
-                        (3) <Client ID>
+                        (3) <Channel ID>      (4) <Client ID>
 
         This command replies with the changed channel user mode mask that
-        client MUST keep locally.  The <Client ID> is the target client.
+        client MUST keep locally. The <Channel ID> is the specified
+        channel.  The <Client ID> is the target client.
 
         Status messages:
 
index 20c878707604a6a23192a2bc7b5e08eb62b48cb8..2f857a1fcfc69535881a797c7d7c481c909fe104 100644 (file)
@@ -1262,6 +1262,7 @@ void silc_client_receive_new_id(SilcClient client,
 {
   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
   int connecting = FALSE;
+  SilcBuffer sidp;
 
   if (!conn->local_entry)
     connecting = TRUE;
@@ -1299,6 +1300,13 @@ void silc_client_receive_new_id(SilcClient client,
   silc_idcache_add(conn->client_cache, conn->nickname, conn->local_id, 
                   (void *)conn->local_entry, FALSE);
 
+  /* Issue INFO command to fetch the real server name and server information
+     and other stuff. */
+  sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
+  silc_client_send_command(client, conn, SILC_COMMAND_INFO,
+                          ++conn->cmd_ident, 1, 2, sidp->data, sidp->len);
+  silc_buffer_free(sidp);
+
   /* Notify application of successful connection. We do it here now that
      we've received the Client ID and are allowed to send traffic. */
   if (connecting)
index 44ae2fbe62e37861f49cf8edb87f58765e7a0cb8..f03a20074af7dba40bf066787f9f8c6353dc2963 100644 (file)
@@ -29,7 +29,7 @@
    is required before processing the notify message. This calls again the
    silc_client_notify_by_server and reprocesses the original notify packet. */
 
-static void silc_client_notify_by_server_pending(void *context)
+static void silc_client_notify_by_server_pending(void *context, void *context2)
 {
   SilcPacketContext *p = (SilcPacketContext *)context;
   silc_client_notify_by_server(p->context, p->sock, p);
@@ -79,10 +79,12 @@ void silc_client_notify_by_server(SilcClient client,
   SilcIDPayload idp;
   SilcClientID *client_id = NULL;
   SilcChannelID *channel_id = NULL;
+  SilcServerID *server_id = NULL;
   SilcClientEntry client_entry;
   SilcClientEntry client_entry2;
   SilcChannelEntry channel;
   SilcChannelUser chu;
+  SilcServerEntry server;
   SilcIDCacheEntry id_cache = NULL;
   unsigned char *tmp;
   uint32 tmp_len, mode;
@@ -441,26 +443,45 @@ void silc_client_notify_by_server(SilcClient client,
        goto out;
       }
     } else {
-      client_entry = NULL;
+      server_id = silc_id_payload_parse_id(tmp, tmp_len);
+      if (!server_id) {
+       silc_id_payload_free(idp);
+       goto out;
+      }
+      
+      server = silc_client_get_server_by_id(client, conn, server_id);
+      if (!server) {
+       silc_id_payload_free(idp);
+       silc_free(server_id);
+       goto out;
+      }
+      
+      /* Save the pointer to the client_entry pointer */
+      client_entry = (SilcClientEntry)server;
+      silc_free(server_id);
     }
 
-    silc_id_payload_free(idp);
-
     /* Get the mode */
     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
-    if (!tmp)
+    if (!tmp) {
+      silc_id_payload_free(idp);
       goto out;
+    }
 
     SILC_GET32_MSB(mode, tmp);
 
     /* Get channel entry */
     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
                                SILC_ID_CHANNEL);
-    if (!channel_id)
+    if (!channel_id) {
+      silc_id_payload_free(idp);
       goto out;
+    }
     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
-                                &id_cache))
-      break;
+                                    &id_cache)) {
+      silc_id_payload_free(idp);
+      goto out;
+    }
 
     channel = (SilcChannelEntry)id_cache->context;
 
@@ -487,8 +508,10 @@ void silc_client_notify_by_server(SilcClient client,
     /* Notify application. The channel entry is sent last as this notify
        is for channel but application don't know it from the arguments
        sent by server. */
-    client->ops->notify(client, conn, type, client_entry, mode, NULL, 
-                       tmp, channel);
+    client->ops->notify(client, conn, type, silc_id_payload_get_type(idp), 
+                       client_entry, mode, NULL, tmp, channel);
+
+    silc_id_payload_free(idp);
     break;
 
   case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
index ce57cdbad035f368a011eddba5c41a787b1bee2c..3e6839fad2fb0fe9a206909c22d3c7e032acade2 100644 (file)
@@ -752,7 +752,8 @@ SILC_CLIENT_CMD_FUNC(kill)
 
   /* Parse the typed nickname. */
   if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
-    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Bad nickname");
+    cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+                         "Bad nickname");
     COMMAND_ERROR;
     goto out;
   }
index 69a94efd267aacd77a4eff669111bd3005d81c46..10218167500bb60153b0d53a9834d0601cb307f6 100644 (file)
@@ -101,13 +101,13 @@ extern SilcClientCommandPending *silc_command_pending;
 
 /* Macro used to declare command functions */
 #define SILC_CLIENT_CMD_FUNC(func) \
-void silc_client_command_##func(void *context)
+void silc_client_command_##func(void *context, void *context2)
 
 /* Executed pending command callback */
 #define SILC_CLIENT_PENDING_EXEC(ctx, cmd)     \
 do {                                           \
   if ((ctx)->callback)                         \
-    (*ctx->callback)(ctx->context);            \
+    (*ctx->callback)(ctx->context, ctx);       \
 } while(0)
 
 /* Execute destructor for pending command */
index 1fa5d5a5af24d1322cea95ce77391d1434dda3cf..b36e5446dd958823459eea0cbb8dbae7c908dd6a 100644 (file)
@@ -168,7 +168,7 @@ void silc_client_command_reply_process(SilcClient client,
     return;
   }
 
-  cmd->cb(ctx);
+  cmd->cb(ctx, NULL);
 }
 
 /* Returns status message string */
@@ -800,9 +800,13 @@ SILC_CLIENT_CMD_REPLY_FUNC(info)
 {
   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
-  SilcClient client = cmd->client;
   SilcCommandStatus status;
   unsigned char *tmp;
+  SilcIDCacheEntry id_cache;
+  SilcServerEntry server;
+  SilcServerID *server_id = NULL;
+  char *server_name, *server_info;
+  uint32 len;
 
   tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
   SILC_GET16_MSB(status, tmp);
@@ -816,32 +820,50 @@ SILC_CLIENT_CMD_REPLY_FUNC(info)
   }
 
   /* Get server ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
+  tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
   if (!tmp)
     goto out;
 
-  /* XXX save server id */
+  server_id = silc_id_payload_parse_id(tmp, len);
+  if (!server_id)
+    goto out;
 
   /* Get server name */
-  tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
-  if (!tmp)
+  server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
+  if (!server_name)
     goto out;
 
   /* Get server info */
-  tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
-  if (!tmp)
+  server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
+  if (!server_info)
     goto out;
 
-  client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
-                  "Info: %s", tmp);
+  /* See whether we have this server cached. If not create it. */
+  if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
+                                  &id_cache)) {
+    SILC_LOG_DEBUG(("New server entry"));
+
+    server = silc_calloc(1, sizeof(*server));
+    server->server_name = strdup(server_name);
+    server->server_info = strdup(server_info);
+    server->server_id = silc_id_dup(server_id, SILC_ID_SERVER);
 
+    /* Add it to the cache */
+    silc_idcache_add(conn->server_cache, server->server_name,
+                    server->server_id, (void *)server, FALSE);
+  } else {
+    server = (SilcServerEntry)id_cache->context;
+  }
+  
   /* Notify application */
-  COMMAND_REPLY((ARGS, NULL, (char *)tmp));
+  COMMAND_REPLY((ARGS, server, server->server_name, server->server_info));
 
   /* Execute any pending command callbacks */
   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
 
  out:
+  if (server_id)
+    silc_free(server_id);
   SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
   silc_client_command_reply_free(cmd);
 }
@@ -1210,6 +1232,10 @@ SILC_CLIENT_CMD_REPLY_FUNC(cmode)
   SilcCommandStatus status;
   unsigned char *tmp;
   uint32 mode;
+  SilcIDCacheEntry id_cache;
+  SilcChannelID *channel_id;
+  SilcChannelEntry channel;
+  uint32 len;
 
   SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
   if (status != SILC_STATUS_OK) {
@@ -1219,17 +1245,39 @@ SILC_CLIENT_CMD_REPLY_FUNC(cmode)
     goto out;
   }
 
+  /* Take Channel ID */
+  tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+  if (!tmp)
+    goto out;
+  channel_id = silc_id_payload_parse_id(tmp, len);
+  if (!channel_id)
+    goto out;
+
+  /* Get the channel entry */
+  if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
+                                  &id_cache)) {
+    silc_free(channel_id);
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+  
+  channel = (SilcChannelEntry)id_cache->context;
+
   /* Get channel mode */
-  tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
+  tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
   if (!tmp) {
+    silc_free(channel_id);
     COMMAND_REPLY_ERROR;
     goto out;
   }
 
+  /* Save the mode */
   SILC_GET32_MSB(mode, tmp);
+  channel->mode = mode;
 
   /* Notify application */
-  COMMAND_REPLY((ARGS, mode));
+  COMMAND_REPLY((ARGS, channel, mode));
+  silc_free(channel_id);
 
   /* Execute any pending command callbacks */
   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
@@ -1248,6 +1296,10 @@ SILC_CLIENT_CMD_REPLY_FUNC(cumode)
   SilcCommandStatus status;
   SilcIDCacheEntry id_cache = NULL;
   SilcClientID *client_id;
+  SilcChannelID *channel_id;
+  SilcClientEntry client_entry;
+  SilcChannelEntry channel;
+  SilcChannelUser chu;
   unsigned char *tmp, *id;
   uint32 len, mode;
   
@@ -1266,14 +1318,34 @@ SILC_CLIENT_CMD_REPLY_FUNC(cumode)
     goto out;
   }
 
+  /* Take Channel ID */
+  tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
+  if (!tmp)
+    goto out;
+  channel_id = silc_id_payload_parse_id(tmp, len);
+  if (!channel_id)
+    goto out;
+
+  /* Get the channel entry */
+  if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
+                                  &id_cache)) {
+    silc_free(channel_id);
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+  
+  channel = (SilcChannelEntry)id_cache->context;
+
   /* Get Client ID */
-  id = silc_argument_get_arg_type(cmd->args, 3, &len);
+  id = silc_argument_get_arg_type(cmd->args, 4, &len);
   if (!id) {
+    silc_free(channel_id);
     COMMAND_REPLY_ERROR;
     goto out;
   }
   client_id = silc_id_payload_parse_id(id, len);
   if (!client_id) {
+    silc_free(channel_id);
     COMMAND_REPLY_ERROR;
     goto out;
   }
@@ -1283,15 +1355,27 @@ SILC_CLIENT_CMD_REPLY_FUNC(cumode)
                                       NULL, NULL, 
                                       silc_hash_client_id_compare, NULL,
                                       &id_cache)) {
+    silc_free(channel_id);
+    silc_free(client_id);
     COMMAND_REPLY_ERROR;
     goto out;
   }
 
+  client_entry = (SilcClientEntry)id_cache->context;
+
+  /* Save the mode */
   SILC_GET32_MSB(mode, tmp);
+  while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
+    if (chu->client == client_entry) {
+      chu->mode = mode;
+      break;
+    }
+  }
 
   /* Notify application */
-  COMMAND_REPLY((ARGS, mode, (SilcClientEntry)id_cache->context));
+  COMMAND_REPLY((ARGS, mode, channel, client_entry));
   silc_free(client_id);
+  silc_free(channel_id);
   
   /* Execute any pending command callbacks */
   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
index 8c3951a495f9af5d37e07eab0fc4732f09ca8022..1c50430fed8f6b4f838e9ac97f96744d9ca81ecd 100644 (file)
@@ -53,7 +53,7 @@ typedef struct {
 
 /* Macro used to declare command reply functions */
 #define SILC_CLIENT_CMD_REPLY_FUNC(func) \
-void silc_client_command_reply_##func(void *context)
+void silc_client_command_reply_##func(void *context, void *context2)
 
 /* Status message structure. Messages are defined below. */
 typedef struct {
index ea45f108a4582cf3a9a0d394cb5eecb43c5bacce..6d865882b390042967e7504fb0684d4e807323b5 100644 (file)
@@ -101,7 +101,7 @@ void silc_client_get_clients(SilcClient client,
   i->context = context;
 
   /* Call the command */
-  ctx->command->cb(ctx);
+  ctx->command->cb(ctx, NULL);
 
   /* Add pending callback */
   silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 
@@ -338,7 +338,7 @@ void silc_client_get_clients_by_list(SilcClient client,
                   client_id_list->head);
 
   /* We have the clients in cache, get them and call the completion */
-  silc_client_command_get_clients_list_callback((void *)in);
+  silc_client_command_get_clients_list_callback((void *)in, NULL);
 }
 
 /* The old style function to find client entry. This is used by the
@@ -377,7 +377,7 @@ SilcClientEntry silc_idlist_get_client(SilcClient client,
       snprintf(ident, sizeof(ident), "IDENTIFY %s", nickname);
       silc_parse_command_line(ident, &ctx->argv, &ctx->argv_lens, 
                              &ctx->argv_types, &ctx->argc, 2);
-      ctx->command->cb(ctx);
+      ctx->command->cb(ctx, NULL);
       
       if (list)
        silc_idcache_list_free(list);
@@ -555,3 +555,21 @@ SilcChannelEntry silc_client_get_channel(SilcClient client,
 
   return entry;
 }
+
+/* Finds entry for server by the server ID. */
+
+SilcServerEntry silc_client_get_server_by_id(SilcClient client,
+                                            SilcClientConnection conn,
+                                            SilcServerID *server_id)
+{
+  SilcIDCacheEntry id_cache;
+  SilcServerEntry entry;
+
+  if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id, 
+                                  &id_cache))
+    return NULL;
+
+  entry = (SilcServerEntry)id_cache->context;
+
+  return entry;
+}
index b0de770077cc677af7f82e4db0b48d142da180e2..835da1aa02fbf5df3d53012c469a56de1a0e4404 100644 (file)
@@ -25,7 +25,7 @@
    (it receives its ID, for example, by IDENTIFY request) we create new
    client entry. This entry also includes the private message keys if
    they are used. */
-typedef struct SilcClientEntryStruct {
+typedef struct {
   char *nickname;              /* nickname */
   char *username;              /* username[@host] */
   char *server;                        /* SILC server name */
@@ -79,6 +79,15 @@ typedef struct SilcChannelEntryStruct {
   SilcChannelPrivateKey curr_key;           /* Current private key */
 } *SilcChannelEntry;
 
+/* Server entry context. This represents one server. When server information
+   is resolved with INFO command the server info is saved in this context. 
+   Also the connected servers are saved here. */
+typedef struct {
+  char *server_name;
+  char *server_info;
+  SilcServerID *server_id;
+} *SilcServerEntry;
+
 /* Prototypes (some functions are defined in the silcapi.h) */
 
 SilcClientEntry silc_idlist_get_client(SilcClient client,
index 5f60e182e800aa6b7d685445008c0c5109a4ceb1..140f2f2227aec9e84027105d24e034c0be6c3e9a 100644 (file)
@@ -829,6 +829,24 @@ SilcChannelEntry silc_client_get_channel(SilcClient client,
                                         SilcClientConnection conn,
                                         char *channel);
 
+/****f* silcclient/SilcClientAPI/silc_client_get_server_by_id
+ *
+ * SYNOPSIS
+ *
+ *    SilcServerEntry silc_client_get_server_by_id(SilcClient client,
+ *                                                 SilcClientConnection conn,
+ *                                                 SilcServerID *server_id);
+ *
+ * DESCRIPTION
+ *
+ *    Finds entry for server by the server ID. Returns the entry or NULL
+ *    if the entry was not found.
+ *
+ ***/
+SilcServerEntry silc_client_get_server_by_id(SilcClient client,
+                                            SilcClientConnection conn,
+                                            SilcServerID *server_id);
+
 
 /* Command management (command.c) */
 
index eeda5a8cdd368a492e9b95918c933b65ecbcbee2..c298d76237ce22803d99ac286da112f4af6eb010 100644 (file)
  *
  * SYNOPSIS
  *
- *    SilcChannelPayload silc_channel_payload_parse(SilcBuffer buffer);
+ *    typedef void (*SilcCommandCb)(void *context, void *context2);
  *
  * DESCRIPTION
  *
  *    Command function callback. The actual command function pointer.
  *    This is generic command callback that the application may choose to
- *    use with its command routines.
+ *    use with its command routines.  However, none of the generic
+ *    routines depend on this callback so application may freely define
+ *    their own command callback if desired.
  *
  ***/
-typedef void (*SilcCommandCb)(void *context);
+typedef void (*SilcCommandCb)(void *context, void *context2);
 
 /****s* silccore/SilcCommandAPI/SilcCommandPayload
  *