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
 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;
 
 {
   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;
   }
     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;
       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) {
       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 *);
       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,
       
       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);
 
                         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);
        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;
          SilcChannelPayload entry;
+         int i = 0;
+
          memset(buf, 0, sizeof(buf));
          silc_dlist_start(list);
          while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
          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;
            SilcUInt32 name_len;
+           char *m = silc_client_chumode_char(umodes[i++]);
            char *name = silc_channel_get_name(entry, &name_len);
            
            if (m)
            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);
          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));
   /* 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 */
   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);
 
   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);
     /* 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;
   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);
   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);
     }
 
       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;
 
     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);
 
       
     SILC_PUT32_MSB(entry->mode, mode);
 
-    if (entry->connection)
+    if (entry->connection) {
       SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
       SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
+    }
 
     packet = 
       silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
 
     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),
                                           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,
                                           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);
 
     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);
     silc_buffer_free(idp);
     if (channels)
       silc_buffer_free(channels);
+    if (umode_list) {
+      silc_buffer_free(umode_list);
+      umode_list = NULL;
+    }
 
     k++;
   }
 
     k++;
   }
@@ -5062,7 +5075,7 @@ SILC_SERVER_CMD_FUNC(users)
     channel = silc_idlist_find_channel_by_name(server->local_list, 
                                               channel_name, NULL);
 
     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;
     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;
 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;
   char *nickname, *username, *realname, *servername = NULL;
   unsigned char *fingerprint;
   SilcClientID *client_id;
   SilcClientEntry client;
+  SilcIDCacheEntry cache = NULL;
   char global = FALSE;
   char *nick;
   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);
 
   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;
 
     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, 
     /* 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);
   }
 
     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);
 
   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);
   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);
 
  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);
 
                                    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);
 
   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;
 
   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_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++;
       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
     }
   } 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;
     }
 
       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. */
       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)
        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);
     }
 
                                            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,
     /* 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);
 
     /* 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)) {
     /* 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;
       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,
       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);
       /* 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);
 
     }
     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++;
 
 
   server->stat.my_channels++;
 
+  if (server->server_type == SILC_ROUTER)
+    entry->users_resolved = TRUE;
+
   return entry;
 }
 
   return entry;
 }
 
@@ -3079,6 +3082,9 @@ silc_server_create_new_channel_with_id(SilcServer server,
 
   server->stat.my_channels++;
 
 
   server->stat.my_channels++;
 
+  if (server->server_type == SILC_ROUTER)
+    entry->users_resolved = TRUE;
+
   return entry;
 }
 
   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
 /* 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,
    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;
 {
   SilcBuffer buffer = NULL;
   SilcChannelEntry channel;
@@ -4071,12 +4187,16 @@ SilcBuffer silc_server_get_client_channel_list(SilcServer server,
   SilcUInt16 name_len;
   int len;
 
   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;
 
   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);
       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,
 
     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_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);
                       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);
   }
   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;
 }
 
   return buffer;
 }
@@ -4135,9 +4269,11 @@ SilcClientEntry silc_server_get_client_resolve(SilcServer server,
       always_resolve) {
     SilcBuffer buffer, idp;
 
       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,
 
     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);
                                       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,
 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,
                             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,
 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:
 
 
         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>]
             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
 
 
         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.
 
         <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
         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
         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);
 
                                 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
 }
 
 /* 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 */
     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
 
       /* 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);
 
       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);
        /* 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);
 
 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. */
 
 /* 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;
 }
 
   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)
 /* 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);
 }
 
     (*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
 
 /* 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)
  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 */
 }
 
 /* Received cmode to channel entry */
@@ -418,8 +436,7 @@ SILC_CLIENT_CMD_FUNC(resume_cmode)
  err:
   session->channel_count--;
   if (!session->channel_count)
  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 */
 }
 
 /* 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)
      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;
 
   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)
   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;
   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;
   
   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);
   }
 
   tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
-  if (tmp)
+  if (tmp) {
     silc_buffer_set(&channels, tmp, len);
     silc_buffer_set(&channels, tmp, len);
+    has_channels = TRUE;
+  }
 
   tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
   if (tmp)
 
   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);
 
 
   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) {
   /* 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, 
   /* 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
 }
 
 /* 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 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();
 
  ***/
 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 */
 #endif /* !SILCUTIL_H */