updates.
authorPekka Riikonen <priikone@silcnet.org>
Fri, 12 Apr 2002 12:34:36 +0000 (12:34 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Fri, 12 Apr 2002 12:34:36 +0000 (12:34 +0000)
16 files changed:
CHANGES
apps/irssi/src/silc/core/client_ops.c
apps/irssi/src/silc/core/silc-servers.c
apps/silcd/command.c
apps/silcd/command_reply.c
apps/silcd/idlist.h
apps/silcd/packet_receive.c
apps/silcd/server.c
apps/silcd/server.h
doc/draft-riikonen-silc-commands-03.nroff
lib/silcclient/client.c
lib/silcclient/client_notify.c
lib/silcclient/client_resume.c
lib/silcclient/command_reply.c
lib/silcutil/silcutil.c
lib/silcutil/silcutil.h

diff --git a/CHANGES b/CHANGES
index 99dde0ab10bcae418e9e12d10d9cd71365e0541d..dcb48950c76eaa1d1d700a52cfa76defd6a9ccba 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,22 @@
+Fri Apr 12 10:17:51 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
+
+       * Defined that server receives WHOIS command reply for private
+         and secret channels too.  Updated protocol specs and the
+         code in server.  Affected file silcd/command.c.
+
+       * Defined <channel user mode list> argument to WHOIS command
+         reply for returning user modes on the channels.  The
+         channel list now doesn't include the user mode anymore but the
+         actual channel mode.  Updated protocol specs and the code in
+         client and server.  Affected files are silcd/command_reply.c,
+         silcd/command.c, silcd/server.c, irssi/src/silc/core/client_ops.c,
+         and lib/silcclient/command_reply.c.
+
+       * Save the channels list in WHOIS command reply in normal server
+         so that WHOIS always shows joined channels also in normal
+         server and not just on router.  Affected file is
+         silcd/command_reply.c.
+
 Thu Apr 11 22:29:33 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
 
        * Defined that server receives USERS command reply for private
index 664d625a3718de1750a8b42e62e44bca4680bf0a..6bbf81a555d7a98c0f57b055cefad95577af90d4 100644 (file)
@@ -633,7 +633,7 @@ void silc_connect(SilcClient client, SilcClientConnection conn,
 {
   SILC_SERVER_REC *server = conn->context;
 
-  if (!server && status == SILC_CLIENT_CONN_ERROR) {
+  if (!server || status == SILC_CLIENT_CONN_ERROR) {
     silc_client_close_connection(client, conn);
     return;
   }
@@ -856,7 +856,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
       char buf[1024], *nickname, *username, *realname, *nick;
       unsigned char *fingerprint;
       SilcUInt32 idle, mode;
-      SilcBuffer channels;
+      SilcBuffer channels, user_modes;
       SilcClientEntry client_entry;
       
       if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
@@ -901,6 +901,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
       mode = va_arg(vp, SilcUInt32);
       idle = va_arg(vp, SilcUInt32);
       fingerprint = va_arg(vp, unsigned char *);
+      user_modes = va_arg(vp, SilcBuffer);
       
       silc_parse_userfqdn(nickname, &nick, NULL);
       printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
@@ -911,16 +912,20 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
                         SILCTXT_WHOIS_REALNAME, realname);
       silc_free(nick);
 
-      if (channels) {
+      if (channels && user_modes) {
+       SilcUInt32 *umodes;
        SilcDList list = silc_channel_payload_parse_list(channels->data,
                                                         channels->len);
-       if (list) {
+       if (list && silc_get_mode_list(user_modes, silc_dlist_count(list),
+                                      &umodes)) {
          SilcChannelPayload entry;
+         int i = 0;
+
          memset(buf, 0, sizeof(buf));
          silc_dlist_start(list);
          while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
-           char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
            SilcUInt32 name_len;
+           char *m = silc_client_chumode_char(umodes[i++]);
            char *name = silc_channel_get_name(entry, &name_len);
            
            if (m)
@@ -933,6 +938,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
          printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
                             SILCTXT_WHOIS_CHANNELS, buf);
          silc_channel_payload_list_free(list);
+         silc_free(umodes);
        }
       }
       
index 9ae0003bc4922a135c155e73489881526722304f..841b8411f23f7ad4408e62e6200e474273b44ebc 100644 (file)
@@ -204,8 +204,7 @@ static void sig_connected(SILC_SERVER_REC *server)
   /* Try to read detached session data and use it if found. */
   memset(&params, 0, sizeof(params));
   memset(file, 0, sizeof(file));
-  snprintf(file, sizeof(file) - 1, "%s/session", get_irssi_dir(),
-          server->connrec->address, server->connrec->port);
+  snprintf(file, sizeof(file) - 1, "%s/session", get_irssi_dir());
   params.detach_data = silc_file_readfile(file, &params.detach_data_len);
 
   /* Add connection to the client library */
@@ -239,7 +238,7 @@ static void sig_disconnected(SILC_SERVER_REC *server)
 
   if (server->conn && server->conn->sock != NULL) {
     silc_client_close_connection(silc_client, server->conn);
-    
+
     /* SILC closes the handle */
     g_io_channel_unref(net_sendbuffer_handle(server->handle));
     net_sendbuffer_destroy(server->handle, FALSE);
index dd8a43fe3f779924b59825ad9de067c845ccb52d..184382eaf0b3c14a34332b375cee4fa8d9468390 100644 (file)
@@ -701,7 +701,7 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
   SilcServer server = cmd->server;
   char *tmp;
   int i, k, len, valid_count;
-  SilcBuffer packet, idp, channels;
+  SilcBuffer packet, idp, channels, umode_list = NULL;
   SilcClientEntry entry;
   SilcCommandStatus status;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
@@ -782,7 +782,12 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
       strncat(uh, hsock->hostname, len);
     }
 
-    channels = silc_server_get_client_channel_list(server, entry);
+    if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
+      channels = silc_server_get_client_channel_list(server, entry, FALSE, 
+                                                    FALSE, &umode_list);
+    else
+      channels = silc_server_get_client_channel_list(server, entry, TRUE, 
+                                                    TRUE, &umode_list);
 
     if (entry->data.fingerprint[0] != 0 && entry->data.fingerprint[1] != 0)
       fingerprint = entry->data.fingerprint;
@@ -791,12 +796,13 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
       
     SILC_PUT32_MSB(entry->mode, mode);
 
-    if (entry->connection)
+    if (entry->connection) {
       SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
+    }
 
     packet = 
       silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
-                                          status, 0, ident, 8
+                                          status, 0, ident, 9
                                           2, idp->data, idp->len,
                                           3, nh, strlen(nh),
                                           4, uh, strlen(uh),
@@ -807,7 +813,10 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
                                           7, mode, 4,
                                           8, idle, 4,
                                           9, fingerprint,
-                                          fingerprint ? 20 : 0);
+                                          fingerprint ? 20 : 0,
+                                          10, umode_list ? umode_list->data :
+                                          NULL, umode_list ? umode_list->len :
+                                          0);
 
     silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
                            0, packet->data, packet->len, FALSE);
@@ -816,6 +825,10 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
     silc_buffer_free(idp);
     if (channels)
       silc_buffer_free(channels);
+    if (umode_list) {
+      silc_buffer_free(umode_list);
+      umode_list = NULL;
+    }
 
     k++;
   }
@@ -5062,7 +5075,7 @@ SILC_SERVER_CMD_FUNC(users)
     channel = silc_idlist_find_channel_by_name(server->local_list, 
                                               channel_name, NULL);
 
-  if (!channel || channel->disabled) {
+  if (!channel || channel->disabled || !channel->users_resolved) {
     if (server->server_type != SILC_ROUTER && !server->standalone &&
        !cmd->pending) {
       SilcBuffer tmpbuf;
index c524111bd2389923bebafc479f4152a6692f90a7..13e6c8db2f752c65aaabd631db176aeec5cbe339 100644 (file)
@@ -121,15 +121,15 @@ static char
 silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
 {
   SilcServer server = cmd->server;
-  unsigned char *tmp, *id_data;
+  unsigned char *tmp, *id_data, *umodes;
   char *nickname, *username, *realname, *servername = NULL;
   unsigned char *fingerprint;
   SilcClientID *client_id;
   SilcClientEntry client;
+  SilcIDCacheEntry cache = NULL;
   char global = FALSE;
   char *nick;
-  SilcUInt32 mode = 0, len, id_len, flen;
-  int expire = 0;
+  SilcUInt32 mode = 0, len, len2, id_len, flen;
 
   id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
   nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
@@ -210,19 +210,34 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
     client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
     client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
 
-    /* If client is global and is not on any channel then add that we'll
-       expire the entry after a while. */
-    if (global && !silc_hash_table_count(client->channels) &&
-       server->server_type == SILC_SERVER)
-      expire = time(NULL) + 300;
-
     /* Create new cache entry */
     silc_idcache_add(global ? server->global_list->clients :
                     server->local_list->clients, nick, client->id, 
-                    client, expire, NULL); 
+                    client, 0, &cache); 
     silc_free(client_id);
   }
 
+  /* Save channel list if it was sent to us */
+  if (server->server_type == SILC_SERVER) {
+    tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
+    umodes = silc_argument_get_arg_type(cmd->args, 10, &len2);
+    if (tmp && umodes) {
+      SilcBufferStruct channels_buf, umodes_buf;
+      silc_buffer_set(&channels_buf, tmp, len);
+      silc_buffer_set(&umodes_buf, umodes, len2);
+      silc_server_save_user_channels(server, cmd->sock, client, &channels_buf,
+                                    &umodes_buf);
+    } else {
+      silc_server_save_user_channels(server, cmd->sock, client, NULL, NULL);
+    }
+
+    if (cache)
+      /* If client is global and is not on any channel then add that we'll
+        expire the entry after a while. */
+      if (global && !silc_hash_table_count(client->channels))
+       cache->expire = time(NULL) + 300;
+  }
+
   if (fingerprint && flen == sizeof(client->data.fingerprint))
     memcpy(client->data.fingerprint, fingerprint, flen);
 
@@ -939,6 +954,7 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
   silc_server_save_users_on_channel(server, cmd->sock, entry, 
                                    client_id, client_id_list,
                                    client_mode_list, list_count);
+  entry->users_resolved = TRUE;
 
  out:
   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
@@ -1071,6 +1087,9 @@ SILC_SERVER_CMD_REPLY_FUNC(users)
                                    client_id_list, client_mode_list, 
                                    list_count);
 
+  channel->global_users = silc_server_channel_has_global(channel);
+  channel->users_resolved = TRUE;
+
   silc_buffer_free(client_id_list);
   silc_buffer_free(client_mode_list);
 
index 888e509b804a2ae3ad54514046664807552f3106..1d92d4c388687738aa09e816386bcd04e35f54f0 100644 (file)
@@ -496,6 +496,7 @@ struct SilcChannelEntryStruct {
 
   unsigned long created;
   bool disabled;
+  bool users_resolved;
 };
 
 /* 
index eddd848aa40b024b8cf4f7a8894ab8322e35aa12..6bfe3089c5ef87d7d135f4ffb6f38dbf828fb730 100644 (file)
@@ -2427,9 +2427,15 @@ void silc_server_new_channel(SilcServer server,
                      silc_id_render(channel_id, SILC_ID_CHANNEL), 
                      sock->hostname));
     
-      silc_idlist_add_channel(server->global_list, strdup(channel_name), 
-                             0, channel_id, sock->user_data, NULL, NULL, 0);
+      channel = 
+       silc_idlist_add_channel(server->global_list, strdup(channel_name), 
+                               0, channel_id, sock->user_data, NULL, NULL, 0);
+      if (!channel)
+       return;
+
       server->stat.channels++;
+      if (server->server_type == SILC_ROUTER)
+       channel->users_resolved = TRUE;
     }
   } else {
     /* The channel is coming from our server, thus it is in our cell
@@ -2946,12 +2952,14 @@ void silc_server_resume_client(SilcServer server,
       return;
     }
 
-    /* Check that the client is detached */
-    if (!(detached_client->mode & SILC_UMODE_DETACHED)) {
+    /* Check that the client is detached, and that we have other info too */
+    if (!(detached_client->mode & SILC_UMODE_DETACHED) ||
+       !silc_hash_table_count(detached_client->channels) ||
+       !detached_client->nickname) {
       if (server->server_type == SILC_SERVER && !server->standalone) {
        /* The client info is being resolved. Reprocess this packet after
           receiving the reply to the query. */
-       SILC_LOG_DEBUG(("Resolving client mode"));
+       SILC_LOG_DEBUG(("Resolving client info"));
        silc_server_get_client_resolve(server, client_id, TRUE, NULL);
        r = silc_calloc(1, sizeof(*r));
        if (!r)
@@ -3093,6 +3101,24 @@ void silc_server_resume_client(SilcServer server,
                                            client->nickname);
     }
 
+    /* Resolve users on those channels that client has joined but we
+       haven't resolved user list yet. */
+    if (server->server_type == SILC_SERVER && !server->standalone) {
+      silc_hash_table_list(client->channels, &htl);
+      while (silc_hash_table_get(&htl, NULL, (void **)&chl)) {
+       channel = chl->channel;
+       SILC_LOG_DEBUG(("Resolving users for %s channel", 
+                       channel->channel_name));
+       if (channel->disabled || !channel->users_resolved) {
+         silc_server_send_command(server, server->router->connection,
+                                  SILC_COMMAND_USERS, ++server->cmd_ident,
+                                  1, 2, channel->channel_name,
+                                  strlen(channel->channel_name));
+       }
+      }
+      silc_hash_table_list_reset(&htl);
+    }
+
     /* Send the new client ID to the client. After this client may start
        receiving other packets, and may start sending packets too. */
     silc_server_send_new_id(server, sock, FALSE, client_id, SILC_ID_CLIENT,
@@ -3125,15 +3151,22 @@ void silc_server_resume_client(SilcServer server,
     /* Send some nice info to the client */
     silc_server_send_connect_notifys(server, sock, client);
 
-    /* XXX normal server may not know about any joined channels!!! 
-       Do this by saving the joined list in the resume_resolve callback.
-       Resolve it here with USERS per channel. */
-
-
     /* Send all channel keys of channels the client has joined */
     silc_hash_table_list(client->channels, &htl);
     while (silc_hash_table_get(&htl, NULL, (void **)&chl)) {
+      bool created = FALSE;
       channel = chl->channel;
+
+      if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY)
+       continue;
+
+      /* If we don't have channel key, then create one */
+      if (!channel->channel_key) {
+       if (!silc_server_create_channel_key(server, channel, 0))
+         continue;
+       created = TRUE;
+      }
+
       id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
       keyp = 
        silc_channel_key_payload_encode(silc_id_get_len(channel->id,
@@ -3148,7 +3181,14 @@ void silc_server_resume_client(SilcServer server,
       /* Send the key packet to client */
       silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0, 
                              keyp->data, keyp->len, FALSE);
-      channel->global_users = silc_server_channel_has_global(channel);
+
+      if (created && server->server_type == SILC_SERVER && 
+         !server->standalone)
+       silc_server_packet_send(server, server->router->connection, 
+                               SILC_PACKET_CHANNEL_KEY, 0, 
+                               keyp->data, keyp->len, FALSE);
+
+      silc_buffer_free(keyp);
     }
     silc_hash_table_list_reset(&htl);
 
index 064ff3860b57922d4bbbf797e50d07b304ef382f..87de942ec0f1063da4c0d818629e9c2df32879b2 100644 (file)
@@ -3015,6 +3015,9 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server,
 
   server->stat.my_channels++;
 
+  if (server->server_type == SILC_ROUTER)
+    entry->users_resolved = TRUE;
+
   return entry;
 }
 
@@ -3079,6 +3082,9 @@ silc_server_create_new_channel_with_id(SilcServer server,
 
   server->stat.my_channels++;
 
+  if (server->server_type == SILC_ROUTER)
+    entry->users_resolved = TRUE;
+
   return entry;
 }
 
@@ -3968,6 +3974,113 @@ void silc_server_save_users_on_channel(SilcServer server,
   }
 }
 
+/* Saves channels and channels user modes to the `client'.  Removes
+   the client from those channels that are not sent in the list but
+   it has joined. */
+
+void silc_server_save_user_channels(SilcServer server,
+                                   SilcSocketConnection sock,
+                                   SilcClientEntry client,
+                                   SilcBuffer channels,
+                                   SilcBuffer channels_user_modes)
+{
+  SilcDList ch;
+  SilcUInt32 *chumodes;
+  SilcChannelPayload entry;
+  SilcChannelEntry channel;
+  SilcChannelID *channel_id;
+  SilcChannelClientEntry chl;
+  SilcHashTable ht = NULL;
+  SilcHashTableList htl;
+  char *name;
+  int i = 0;
+
+  if (!channels ||!channels_user_modes)
+    goto out;
+  
+  ch = silc_channel_payload_parse_list(channels->data, channels->len);
+  if (ch && silc_get_mode_list(channels_user_modes, silc_dlist_count(ch),
+                              &chumodes)) {
+    ht = silc_hash_table_alloc(0, silc_hash_ptr, NULL, NULL, 
+                              NULL, NULL, NULL, TRUE);
+    silc_dlist_start(ch);
+    while ((entry = silc_dlist_get(ch)) != SILC_LIST_END) {
+      /* Check if we have this channel, and add it if we don't have it.
+        Also add the client on the channel unless it is there already. */
+      channel_id = silc_channel_get_id_parse(entry);
+      channel = silc_idlist_find_channel_by_id(server->local_list, 
+                                              channel_id, NULL);
+      if (!channel)
+       channel = silc_idlist_find_channel_by_id(server->global_list,
+                                                channel_id, NULL);
+      if (!channel) {
+       if (server->server_type != SILC_SERVER) {
+         silc_free(channel_id);
+         i++;
+         continue;
+       }
+       
+       /* We don't have that channel anywhere, add it. */
+       name = silc_channel_get_name(entry, NULL);
+       channel = silc_idlist_add_channel(server->global_list, strdup(name), 0,
+                                         channel_id, server->router,
+                                         NULL, NULL, 0);
+       if (!channel) {
+         silc_free(channel_id);
+         i++;
+         continue;
+       }
+       channel_id = NULL;
+      }
+
+      channel->mode = silc_channel_get_mode(entry);
+
+      /* Add the client on the channel */
+      if (!silc_server_client_on_channel(client, channel, &chl)) {
+       chl = silc_calloc(1, sizeof(*chl));
+       chl->client = client;
+       chl->mode = chumodes[i++];
+       chl->channel = channel;
+       silc_hash_table_add(channel->user_list, chl->client, chl);
+       silc_hash_table_add(client->channels, chl->channel, chl);
+       channel->user_count++;
+      } else {
+       /* Update mode */
+       chl->mode = chumodes[i++];
+      }
+
+      silc_hash_table_add(ht, channel, channel);
+      silc_free(channel_id);
+    }
+    silc_channel_payload_list_free(ch);
+    silc_free(chumodes);
+  }
+
+ out:
+  /* Go through the list again and remove client from channels that
+     are no part of the list. */
+  if (ht) {
+    silc_hash_table_list(client->channels, &htl);
+    while (silc_hash_table_get(&htl, NULL, (void **)&chl)) {
+      if (!silc_hash_table_find(ht, chl->channel, NULL, NULL)) {
+       silc_hash_table_del(chl->channel->user_list, chl->client);
+       silc_hash_table_del(chl->client->channels, chl->channel);
+       silc_free(chl);
+      }
+    }
+    silc_hash_table_list_reset(&htl);
+    silc_hash_table_free(ht);
+  } else {
+    silc_hash_table_list(client->channels, &htl);
+    while (silc_hash_table_get(&htl, NULL, (void **)&chl)) {
+      silc_hash_table_del(chl->channel->user_list, chl->client);
+      silc_hash_table_del(chl->client->channels, chl->channel);
+      silc_free(chl);
+    }
+    silc_hash_table_list_reset(&htl);
+  }
+}
+
 /* Lookups route to the client indicated by the `id_data'. The connection
    object and internal data object is returned. Returns NULL if route
    could not be found to the client. If the `client_id' is specified then
@@ -4060,7 +4173,10 @@ silc_server_get_client_route(SilcServer server,
    Secret channels are not put to the list. */
 
 SilcBuffer silc_server_get_client_channel_list(SilcServer server,
-                                              SilcClientEntry client)
+                                              SilcClientEntry client,
+                                              bool get_private,
+                                              bool get_secret,
+                                              SilcBuffer *user_mode_list)
 {
   SilcBuffer buffer = NULL;
   SilcChannelEntry channel;
@@ -4071,12 +4187,16 @@ SilcBuffer silc_server_get_client_channel_list(SilcServer server,
   SilcUInt16 name_len;
   int len;
 
+  if (user_mode_list)
+    *user_mode_list = NULL;
+
   silc_hash_table_list(client->channels, &htl);
   while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
     channel = chl->channel;
 
-    if (channel->mode & SILC_CHANNEL_MODE_SECRET ||
-       channel->mode & SILC_CHANNEL_MODE_PRIVATE)
+    if (channel->mode & SILC_CHANNEL_MODE_SECRET && !get_secret)
+      continue;
+    if (channel->mode & SILC_CHANNEL_MODE_PRIVATE && !get_private)
       continue;
 
     cid = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
@@ -4085,23 +4205,37 @@ SilcBuffer silc_server_get_client_channel_list(SilcServer server,
 
     len = 4 + name_len + id_len + 4;
     buffer = silc_buffer_realloc(buffer,
-                                (buffer ? (buffer)->truelen + len : len));
-    silc_buffer_pull_tail(buffer, ((buffer)->end - (buffer)->data));
+                                (buffer ? buffer->truelen + len : len));
+    silc_buffer_pull_tail(buffer, (buffer->end - buffer->data));
     silc_buffer_format(buffer,
                       SILC_STR_UI_SHORT(name_len),
                       SILC_STR_UI_XNSTRING(channel->channel_name,
                                            name_len),
                       SILC_STR_UI_SHORT(id_len),
                       SILC_STR_UI_XNSTRING(cid, id_len),
-                      SILC_STR_UI_INT(chl->mode), /* Client's mode */
+                      SILC_STR_UI_INT(chl->channel->mode),
                       SILC_STR_END);
     silc_buffer_pull(buffer, len);
     silc_free(cid);
+
+    if (user_mode_list) {
+      *user_mode_list = silc_buffer_realloc(*user_mode_list,
+                                           (*user_mode_list ?
+                                            (*user_mode_list)->truelen + 4 :
+                                            4));
+      silc_buffer_pull_tail(*user_mode_list, ((*user_mode_list)->end -
+                                             (*user_mode_list)->data));
+      SILC_PUT32_MSB(chl->mode, (*user_mode_list)->data);
+      silc_buffer_pull(*user_mode_list, 4);
+    }
   }
   silc_hash_table_list_reset(&htl);
 
   if (buffer)
     silc_buffer_push(buffer, buffer->data - buffer->head);
+  if (user_mode_list && *user_mode_list)
+    silc_buffer_push(*user_mode_list, ((*user_mode_list)->data -
+                                      (*user_mode_list)->head));
 
   return buffer;
 }
@@ -4135,9 +4269,11 @@ SilcClientEntry silc_server_get_client_resolve(SilcServer server,
       always_resolve) {
     SilcBuffer buffer, idp;
 
-    client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
-    client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
-    client->resolve_cmd_ident = ++server->cmd_ident;
+    if (client) {
+      client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
+      client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
+      client->resolve_cmd_ident = ++server->cmd_ident;
+    }
 
     idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
     buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
index 74326d1990700eca441e64851053de488aa28c7c..93ec1f49e68bbda839f1ba70feb7a4e49a6cdc57 100644 (file)
@@ -208,6 +208,11 @@ void silc_server_save_users_on_channel(SilcServer server,
                                       SilcBuffer user_list,
                                       SilcBuffer mode_list,
                                       SilcUInt32 user_count);
+void silc_server_save_user_channels(SilcServer server,
+                                   SilcSocketConnection sock,
+                                   SilcClientEntry client,
+                                   SilcBuffer channels,
+                                   SilcBuffer channels_user_modes);
 SilcSocketConnection
 silc_server_get_client_route(SilcServer server,
                             unsigned char *id_data,
@@ -216,7 +221,10 @@ silc_server_get_client_route(SilcServer server,
                             SilcIDListData *idata,
                             SilcClientEntry *client_entry);
 SilcBuffer silc_server_get_client_channel_list(SilcServer server,
-                                              SilcClientEntry client);
+                                              SilcClientEntry client,
+                                              bool get_private,
+                                              bool get_secret,
+                                              SilcBuffer *user_mode_list);
 SilcClientEntry silc_server_get_client_resolve(SilcServer server,
                                               SilcClientID *client_id,
                                               bool always_resolve,
index 421013fe748e1d2fd6ca767a94934ff4a88e6942..5f76f8e4de4aff4fb75e90e9d853ce8d42163f26 100644 (file)
@@ -261,13 +261,14 @@ List of all defined commands in SILC follows.
 
         Reply messages to the command:
 
-        Max Arguments:  9
+        Max Arguments:  10
             Arguments:  (1) <Status Payload>       (2) <Client ID> 
                         (3) <nickname>[@<server>]  (4) <username@host> 
                         (5) <real name>            (6) [<Channel Payload 
                                                          list>] 
                         (7) [<user mode>]          (8) [<idle time>]
-                        (9) [<fingerprint>]
+                        (9) [<fingerprint>]        (10) <channel user
+                                                         mode list>
 
 
         This command may reply with several command reply messages to
@@ -284,14 +285,19 @@ List of all defined commands in SILC follows.
         <count> option were defined in the query there will be only
         <count> many replies from the server.
 
-        The server may return the list of channels if the client has
+        The server returns the list of channels if the client has
         joined channels.  In this case the list is list of Channel
-        Payloads.  The Mode Mask in the Channel Payload (see [SILC2] and
-        section 2.3.2.3 for the Channel Payload) is the client's mode
-        on the channel.  The list is encoded by adding the Channel
-        Payloads one after the other.
-
-        The server may also send client's user mode, idle time, and the
+        Payloads.  The Mode Mask in the Channel Payload is the channel's
+        mode.  The list is encoded by adding the Channel Payloads one
+        after the other.  Private and secret channels MUST NOT be sent,
+        except if the sender of this command is on those channels, or
+        the sender is server.  The <channel user mode list> MUST also
+        be sent if client is joined channels.  This list includes 32 bit
+        MSB first order values one after the other and each indicate
+        the user's mode on a channel.  The order of these values MUST
+        be same as the channel order in the <Channel Payload list>.
+
+        The server also returns client's user mode, idle time, and the
         fingerprint of the client's public key.  The <fingerprint> is the
         binary hash digest of the public key.  The fingerprint MUST NOT
         be sent if the server has not verified the proof of posession of
index 2619df2671b66c5d6e6b82c61bb2948f21dbcd41..becb0829d527ae34de7537aa173961e4375c699e 100644 (file)
@@ -1543,15 +1543,17 @@ static void silc_client_resume_session_cb(SilcClient client,
                                 SILC_CLIENT_CONN_SUCCESS_RESUME :
                                 SILC_CLIENT_CONN_ERROR);
 
-  /* Issue INFO command to fetch the real server name and server
-     information and other stuff. */
-  silc_client_command_register(client, SILC_COMMAND_INFO, NULL, NULL,
-                              silc_client_command_reply_info_i, 0, 
-                              ++conn->cmd_ident);
-  sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
-  silc_client_command_send(client, conn, SILC_COMMAND_INFO,
-                          conn->cmd_ident, 1, 2, sidp->data, sidp->len);
-  silc_buffer_free(sidp);
+  if (success) {
+    /* Issue INFO command to fetch the real server name and server
+       information and other stuff. */
+    silc_client_command_register(client, SILC_COMMAND_INFO, NULL, NULL,
+                                silc_client_command_reply_info_i, 0, 
+                                ++conn->cmd_ident);
+    sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
+    silc_client_command_send(client, conn, SILC_COMMAND_INFO,
+                            conn->cmd_ident, 1, 2, sidp->data, sidp->len);
+    silc_buffer_free(sidp);
+  }
 }
 
 /* Processes the received new Client ID from server. Old Client ID is
index 50aebb3ca84f19db80c87459f2450b7237abd492..7a48419f04a6f1a7e18ab4b85433815cb8e9f219 100644 (file)
@@ -482,7 +482,7 @@ void silc_client_notify_by_server(SilcClient client,
     tmp = silc_argument_get_arg_type(args, 3, NULL);
     if (tmp) {
       /* Protocol version 1.1 */
-      char *tmp_nick;
+      char *tmp_nick = NULL;
 
       /* Check whether nickname changed at all.  It is possible that nick
         change notify is received but nickname didn't changed, only the
@@ -493,7 +493,7 @@ void silc_client_notify_by_server(SilcClient client,
       else
        tmp_nick = strdup(tmp);
 
-      if (!strcmp(tmp, tmp_nick)) {
+      if (tmp_nick && !strcmp(tmp, tmp_nick)) {
        /* Nickname didn't change. Update only the ID */
        silc_idcache_del_by_context(conn->client_cache, client_entry);
        silc_free(client_entry->id);
index 0d0d24ba7b19b4f393ec48b2d04d556617098a9e..b0e08ed65031d5ea97cafa7a64ca86e49c7f356a 100644 (file)
@@ -27,6 +27,14 @@ SILC_CLIENT_CMD_FUNC(resume_identify);
 SILC_CLIENT_CMD_FUNC(resume_cmode);
 SILC_CLIENT_CMD_FUNC(resume_users);
 
+#define RESUME_CALL_COMPLETION(client, session, s)                     \
+do {                                                                   \
+  session->success = s;                                                        \
+  silc_schedule_task_add(client->schedule, 0,                          \
+                        silc_client_resume_call_completion, session,   \
+                        0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);   \
+} while(0)
+
 /* Generates the session detachment data. This data can be used later
    to resume back to the server. */
 
@@ -157,6 +165,17 @@ bool silc_client_process_detach_data(SilcClient client,
   return TRUE;
 }
 
+
+/* Resume session context */
+typedef struct {
+  SilcClient client;
+  SilcClientConnection conn;
+  SilcClientResumeSessionCallback callback;
+  void *context;
+  SilcUInt32 channel_count;
+  bool success;
+} *SilcClientResumeSession;
+
 /* Generic command reply callback */
 
 SILC_CLIENT_CMD_REPLY_FUNC(resume)
@@ -169,14 +188,14 @@ SILC_CLIENT_CMD_REPLY_FUNC(resume)
     (*cmd->callback)(cmd->context, cmd);
 }
 
-/* Resume session context */
-typedef struct {
-  SilcClient client;
-  SilcClientConnection conn;
-  SilcClientResumeSessionCallback callback;
-  void *context;
-  SilcUInt32 channel_count;
-} *SilcClientResumeSession;
+/* Completion calling callback */
+
+SILC_TASK_CALLBACK(silc_client_resume_call_completion)
+{
+  SilcClientResumeSession session = context;
+  session->callback(session->client, session->conn, session->success,
+                   session->context);
+}
 
 /* This function is used to perform the resuming procedure after the
    client has connected to the server properly and has received the
@@ -355,8 +374,7 @@ SILC_CLIENT_CMD_FUNC(resume_identify)
  err:
   session->channel_count--;
   if (!session->channel_count)
-    session->callback(session->client, session->conn, FALSE,
-                     session->context);
+    RESUME_CALL_COMPLETION(client, session, FALSE);
 }
 
 /* Received cmode to channel entry */
@@ -418,8 +436,7 @@ SILC_CLIENT_CMD_FUNC(resume_cmode)
  err:
   session->channel_count--;
   if (!session->channel_count)
-    session->callback(session->client, session->conn, FALSE,
-                     session->context);
+    RESUME_CALL_COMPLETION(client, session, FALSE);
 }
 
 /* Received users reply to a channel entry */
@@ -506,8 +523,7 @@ SILC_CLIENT_CMD_FUNC(resume_users)
      our channels */
   session->channel_count--;
   if (!session->channel_count)
-    session->callback(session->client, session->conn, TRUE,
-                     session->context);
+    RESUME_CALL_COMPLETION(client, session, TRUE);
 
   silc_free(channel_id);
   return;
@@ -516,6 +532,5 @@ SILC_CLIENT_CMD_FUNC(resume_users)
   silc_free(channel_id);
   session->channel_count--;
   if (!session->channel_count)
-    session->callback(session->client, session->conn, FALSE,
-                     session->context);
+    RESUME_CALL_COMPLETION(client, session, FALSE);
 }
index 85609d337d0db7c21173c9f91208d93c359e9d22..415f6d49b2568d061250ac3eb84c88c1db7a0ddd 100644 (file)
@@ -195,7 +195,8 @@ silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
   char *nickname = NULL, *username = NULL;
   char *realname = NULL;
   SilcUInt32 idle = 0, mode = 0;
-  SilcBufferStruct channels;
+  SilcBufferStruct channels, ch_user_modes;
+  bool has_channels = FALSE, has_user_modes = FALSE;
   unsigned char *fingerprint;
   SilcUInt32 fingerprint_len;
   
@@ -223,8 +224,10 @@ silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
   }
 
   tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
-  if (tmp)
+  if (tmp) {
     silc_buffer_set(&channels, tmp, len);
+    has_channels = TRUE;
+  }
 
   tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
   if (tmp)
@@ -236,6 +239,12 @@ silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
 
   fingerprint = silc_argument_get_arg_type(cmd->args, 9, &fingerprint_len);
 
+  tmp = silc_argument_get_arg_type(cmd->args, 10, &len);
+  if (tmp) {
+    silc_buffer_set(&ch_user_modes, tmp, len);
+    has_user_modes = TRUE;
+  }
+
   /* Check if we have this client cached already. */
   client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
   if (!client_entry) {
@@ -260,7 +269,8 @@ silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
   /* Notify application */
   if (!cmd->callback && notify)
     COMMAND_REPLY((ARGS, client_entry, nickname, username, realname, 
-                  &channels, mode, idle, fingerprint));
+                  has_channels ? &channels : NULL, mode, idle, 
+                  fingerprint, has_user_modes ? &ch_user_modes : NULL));
 }
 
 /* Received reply for WHOIS command. This maybe called several times
index 4ac00f38363803b05857ee774b61ef0a8cb3af86..e3778bb7b2f8b78ef25112a90f46ccac7cb0a73b 100644 (file)
@@ -900,3 +900,25 @@ char *silc_get_input(const char *prompt, bool echo_off)
   return NULL;
 #endif /* SILC_UNIX */
 }
+
+/* Return mode list */
+
+bool silc_get_mode_list(SilcBuffer mode_list, SilcUInt32 mode_list_count,
+                       SilcUInt32 **list)
+{
+  int i;
+
+  if (mode_list->len / 4 != mode_list_count)
+    return FALSE;
+
+  *list = silc_calloc(mode_list_count, sizeof(**list));
+
+  for (i = 0; i < mode_list_count; i++) {
+    SILC_GET32_MSB((*list)[i], mode_list->data);
+    silc_buffer_pull(mode_list, 4);
+  }
+
+  silc_buffer_push(mode_list, mode_list->data - mode_list->head);
+
+  return TRUE;
+}
index d1374d902a5f2b0ee4d400288493d21784bc1dbf..ecaf5796e326315291d3134fcf1ade643fe14383 100644 (file)
@@ -529,4 +529,22 @@ char *silc_get_username();
  ***/
 char *silc_get_real_name();
 
+/****f* silcutil/SilcUtilAPI/silc_get_mode_list
+ *
+ * SYNOPSIS
+ *
+ *    bool silc_get_mode_list(SilcBuffer mode_list, SilcUInt32 mode_list_count,
+ *                            SilcUInt32 **list);
+ *
+ * DESCRIPTION
+ *
+ *    Returns modes from list of 32 bit MSB first order values that are
+ *    encoded one after the other in the `mode_list' into the `list'
+ *    array.  The caller must free the returned list.  Return FALSE if
+ *    there is error parsing the list.
+ *
+ ***/
+bool silc_get_mode_list(SilcBuffer mode_list, SilcUInt32 mode_list_count,
+                       SilcUInt32 **list);
+
 #endif /* !SILCUTIL_H */