Rewrote detach/resuming.
authorPekka Riikonen <priikone@silcnet.org>
Mon, 18 Dec 2006 14:49:41 +0000 (14:49 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Mon, 18 Dec 2006 14:49:41 +0000 (14:49 +0000)
12 files changed:
lib/silcclient/client.h
lib/silcclient/client_channel.c
lib/silcclient/client_entry.c
lib/silcclient/client_entry.h
lib/silcclient/client_internal.h
lib/silcclient/client_notify.c
lib/silcclient/client_prvmsg.c
lib/silcclient/client_register.c
lib/silcclient/client_register.h
lib/silcclient/command_reply.c
lib/silcclient/silcclient.h
lib/silcclient/silcclient_entry.h

index 53a5550aaea5b22cfb7aa21109ce54aceaa63331..ab56cfbba7073166cba3c6f1f648d8138ead549f 100644 (file)
@@ -84,7 +84,7 @@ typedef struct SilcChannelEntryInternalStruct {
                                                stuff that relates to the
                                                channel. Not used for the
                                                channel resolving itself. */
-  SilcAtomic8 refcnt;                       /* Reference counter */
+  SilcAtomic16 refcnt;                      /* Reference counter */
 } SilcChannelEntryInternal;
 
 /* Internal server entry context */
index 51fc85471d11a358d2be3727a237c9bfc60957de..34d51c64881a98940bf474ed3f466030c7396e09 100644 (file)
@@ -43,15 +43,15 @@ SilcBool silc_client_send_channel_message(SilcClient client,
 
   SILC_LOG_DEBUG(("Sending channel message"));
 
-  if (!client || !conn || !channel)
+  if (silc_unlikely(!client || !conn || !channel))
     return FALSE;
-  if (flags & SILC_MESSAGE_FLAG_SIGNED && !hash)
+  if (silc_unlikely(flags & SILC_MESSAGE_FLAG_SIGNED && !hash))
     return FALSE;
-  if (conn->internal->disconnected)
+  if (silc_unlikely(conn->internal->disconnected))
     return FALSE;
 
   chu = silc_client_on_channel(channel, conn->local_entry);
-  if (!chu) {
+  if (silc_unlikely(!chu)) {
     client->internal->ops->say(conn->client, conn,
                               SILC_CLIENT_MESSAGE_AUDIT,
                               "Cannot talk to channel: not joined");
@@ -59,13 +59,14 @@ SilcBool silc_client_send_channel_message(SilcClient client,
   }
 
   /* Check if it is allowed to send messages to this channel by us. */
-  if (channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS && !chu->mode)
+  if (silc_unlikely(channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS &&
+                   !chu->mode))
     return FALSE;
-  if (channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS &&
-      chu->mode & SILC_CHANNEL_UMODE_CHANOP &&
-      !(chu->mode & SILC_CHANNEL_UMODE_CHANFO))
+  if (silc_unlikely(channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS &&
+                   chu->mode & SILC_CHANNEL_UMODE_CHANOP &&
+                   !(chu->mode & SILC_CHANNEL_UMODE_CHANFO)))
     return FALSE;
-  if (chu->mode & SILC_CHANNEL_UMODE_QUIET)
+  if (silc_unlikely(chu->mode & SILC_CHANNEL_UMODE_QUIET))
     return FALSE;
 
   /* Take the key to be used */
@@ -102,7 +103,7 @@ SilcBool silc_client_send_channel_message(SilcClient client,
     hmac = channel->internal.hmac;
   }
 
-  if (!cipher || !hmac) {
+  if (silc_unlikely(!cipher || !hmac)) {
     SILC_LOG_ERROR(("No cipher and HMAC for channel"));
     return FALSE;
   }
@@ -111,7 +112,7 @@ SilcBool silc_client_send_channel_message(SilcClient client,
   buffer = silc_message_payload_encode(flags, data, data_len, TRUE, FALSE,
                                       cipher, hmac, client->rng, NULL,
                                       conn->private_key, hash, NULL);
-  if (!buffer) {
+  if (silc_unlikely(!buffer)) {
     SILC_LOG_ERROR(("Error encoding channel message"));
     return FALSE;
   }
@@ -162,14 +163,15 @@ SILC_FSM_STATE(silc_client_channel_message)
 
   SILC_LOG_DEBUG(("Received channel message"));
 
-  if (packet->dst_id_type != SILC_ID_CHANNEL) {
+  if (silc_unlikely(packet->dst_id_type != SILC_ID_CHANNEL)) {
     /** Invalid packet */
     silc_fsm_next(fsm, silc_client_channel_message_error);
     return SILC_FSM_CONTINUE;
   }
 
-  if (!silc_id_str2id(packet->src_id, packet->src_id_len, SILC_ID_CLIENT,
-                     &remote_id, sizeof(remote_id))) {
+  if (silc_unlikely(!silc_id_str2id(packet->src_id,
+                                   packet->src_id_len, SILC_ID_CLIENT,
+                                   &remote_id, sizeof(remote_id)))) {
     /** Invalid source ID */
     silc_fsm_next(fsm, silc_client_channel_message_error);
     return SILC_FSM_CONTINUE;
@@ -187,8 +189,9 @@ SILC_FSM_STATE(silc_client_channel_message)
     /* NOT REACHED */
   }
 
-  if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
-                     &channel_id, sizeof(channel_id))) {
+  if (silc_unlikely(!silc_id_str2id(packet->dst_id, packet->dst_id_len,
+                                   SILC_ID_CHANNEL, &channel_id,
+                                   sizeof(channel_id)))) {
     /** Invalid destination ID */
     silc_fsm_next(fsm, silc_client_channel_message_error);
     return SILC_FSM_CONTINUE;
@@ -196,15 +199,17 @@ SILC_FSM_STATE(silc_client_channel_message)
 
   /* Find the channel */
   channel = silc_client_get_channel_by_id(client, conn, &channel_id);
-  if (!channel) {
+  if (silc_unlikely(!channel)) {
     /** Unknown channel */
     silc_fsm_next(fsm, silc_client_channel_message_error);
     return SILC_FSM_CONTINUE;
   }
 
   /* Check that user is on channel */
-  if (!silc_client_on_channel(channel, client_entry)) {
+  if (silc_unlikely(!silc_client_on_channel(channel, client_entry))) {
     /** User not on channel */
+    SILC_LOG_WARNING(("Message from user not on channel, client or "
+                     "server bug"));
     silc_fsm_next(fsm, silc_client_channel_message_error);
     return SILC_FSM_CONTINUE;
   }
@@ -223,7 +228,7 @@ SILC_FSM_STATE(silc_client_channel_message)
     /* If decryption failed and we have just performed channel key rekey
        we will use the old key in decryption. If that fails too then we
        cannot do more and will drop the packet. */
-    if (!payload) {
+    if (silc_unlikely(!payload)) {
       SilcCipher cipher;
       SilcHmac hmac;
 
@@ -346,6 +351,8 @@ SilcBool silc_client_save_channel_key(SilcClient client,
   SilcChannelID id;
   SilcChannelKeyPayload payload;
 
+  SILC_LOG_DEBUG(("New channel key"));
+
   payload = silc_channel_key_payload_parse(silc_buffer_data(key_payload),
                                           silc_buffer_len(key_payload));
   if (!payload)
@@ -366,6 +373,7 @@ SilcBool silc_client_save_channel_key(SilcClient client,
   if (!channel) {
     channel = silc_client_get_channel_by_id(client, conn, &id);
     if (!channel) {
+      SILC_LOG_DEBUG(("Key for unknown channel"));
       silc_channel_key_payload_free(payload);
       return FALSE;
     }
@@ -404,7 +412,7 @@ SilcBool silc_client_save_channel_key(SilcClient client,
 
   /* Set the cipher key */
   key = silc_channel_key_get_key(payload, &tmp_len);
-  silc_cipher_set_key(channel->internal.channel_key, key, tmp_len * 8);
+  silc_cipher_set_key(channel->internal.channel_key, key, tmp_len * 8, TRUE);
 
   /* Get channel HMAC */
   hmac = (channel->internal.hmac ?
@@ -501,7 +509,7 @@ SilcBool silc_client_add_channel_private_key(SilcClient client,
   }
   entry->name = name ? strdup(name) : NULL;
 
-  /* Allocate the cipher and set the key*/
+  /* Allocate the cipher and set the key */
   if (!silc_cipher_alloc(cipher, &entry->cipher)) {
     silc_free(entry);
     silc_free(entry->name);
@@ -509,7 +517,7 @@ SilcBool silc_client_add_channel_private_key(SilcClient client,
     return FALSE;
   }
   silc_cipher_set_key(entry->cipher, keymat->send_enc_key,
-                     keymat->enc_key_len);
+                     keymat->enc_key_len, TRUE);
 
   /* Generate HMAC key from the channel key data and set it */
   if (!silc_hmac_alloc(hmac, NULL, &entry->hmac)) {
index da8f0b246f7cdd49abb094969b0eb409f5e5507f..0927606946509df606aba675f5e3590277ad870b 100644 (file)
@@ -802,6 +802,56 @@ void silc_client_update_client(SilcClient client,
   client_entry->mode = mode;
 }
 
+/* Change a client's nickname */
+
+SilcBool silc_client_change_nickname(SilcClient client,
+                                    SilcClientConnection conn,
+                                    SilcClientEntry client_entry,
+                                    const char *new_nick,
+                                    SilcClientID *new_id,
+                                    const unsigned char *idp,
+                                    SilcUInt32 idp_len)
+{
+  char *tmp;
+
+  SILC_LOG_DEBUG(("Change nickname %s to %s", client_entry->nickname,
+                 new_nick));
+
+  /* Normalize nickname */
+  tmp = silc_identifier_check(new_nick, strlen(new_nick),
+                             SILC_STRING_UTF8, 128, NULL);
+  if (!tmp)
+    return FALSE;
+
+  /* Update the client entry */
+  silc_mutex_lock(conn->internal->lock);
+  if (!silc_idcache_update_by_context(conn->internal->client_cache,
+                                     client_entry, new_id, tmp, TRUE)) {
+    silc_free(tmp);
+    silc_mutex_unlock(conn->internal->lock);
+    return FALSE;
+  }
+  silc_mutex_unlock(conn->internal->lock);
+
+  memset(client_entry->nickname, 0, sizeof(client_entry->nickname));
+  memcpy(client_entry->nickname, new_nick, strlen(new_nick));
+  client_entry->nickname_normalized = tmp;
+  silc_client_nickname_format(client, conn, client_entry);
+
+  /* For my client entry, update ID and set new ID to packet stream */
+  if (client_entry == conn->local_entry) {
+    if (idp && idp_len) {
+      silc_buffer_enlarge(conn->internal->local_idp, idp_len);
+      silc_buffer_put(conn->internal->local_idp, idp, idp_len);
+    }
+    if (new_id)
+      silc_packet_set_ids(conn->stream, SILC_ID_CLIENT, conn->local_id,
+                         0, NULL);
+  }
+
+  return TRUE;
+}
+
 /* Deletes the client entry and frees all memory. */
 
 void silc_client_del_client_entry(SilcClient client,
@@ -1286,7 +1336,7 @@ SilcChannelEntry silc_client_add_channel(SilcClient client,
   if (!channel)
     return NULL;
 
-  silc_atomic_init8(&channel->internal.refcnt, 0);
+  silc_atomic_init16(&channel->internal.refcnt, 0);
   channel->id = *channel_id;
   channel->mode = mode;
 
@@ -1347,7 +1397,7 @@ SilcBool silc_client_del_channel(SilcClient client, SilcClientConnection conn,
   if (!channel)
     return FALSE;
 
-  if (silc_atomic_sub_int8(&channel->internal.refcnt, 1) > 0)
+  if (silc_atomic_sub_int16(&channel->internal.refcnt, 1) > 0)
     return FALSE;
 
   SILC_LOG_DEBUG(("Deleting channel %p", channel));
@@ -1382,8 +1432,11 @@ SilcBool silc_client_del_channel(SilcClient client, SilcClientConnection conn,
       silc_hmac_free(hmac);
     silc_dlist_uninit(channel->internal.old_hmacs);
   }
+  if (channel->channel_pubkeys)
+    silc_argument_list_free(channel->channel_pubkeys,
+                           SILC_ARGUMENT_PUBLIC_KEY);
   silc_client_del_channel_private_keys(client, conn, channel);
-  silc_atomic_uninit8(&channel->internal.refcnt);
+  silc_atomic_uninit16(&channel->internal.refcnt);
   silc_schedule_task_del_by_context(conn->client->schedule, channel);
   silc_free(channel);
 
@@ -1422,10 +1475,10 @@ SilcBool silc_client_replace_channel_id(SilcClient client,
 void silc_client_ref_channel(SilcClient client, SilcClientConnection conn,
                             SilcChannelEntry channel_entry)
 {
-  silc_atomic_add_int8(&channel_entry->internal.refcnt, 1);
+  silc_atomic_add_int16(&channel_entry->internal.refcnt, 1);
   SILC_LOG_DEBUG(("Channel %p refcnt %d->%d", channel_entry,
-                 silc_atomic_get_int8(&channel_entry->internal.refcnt) - 1,
-                 silc_atomic_get_int8(&channel_entry->internal.refcnt)));
+                 silc_atomic_get_int16(&channel_entry->internal.refcnt) - 1,
+                 silc_atomic_get_int16(&channel_entry->internal.refcnt)));
 }
 
 /* Release reference of channel entry */
@@ -1435,8 +1488,8 @@ void silc_client_unref_channel(SilcClient client, SilcClientConnection conn,
 {
   if (channel_entry) {
     SILC_LOG_DEBUG(("Channel %p refcnt %d->%d", channel_entry,
-                   silc_atomic_get_int8(&channel_entry->internal.refcnt),
-                   silc_atomic_get_int8(&channel_entry->internal.refcnt)
+                   silc_atomic_get_int16(&channel_entry->internal.refcnt),
+                   silc_atomic_get_int16(&channel_entry->internal.refcnt)
                    - 1));
     silc_client_del_channel(client, conn, channel_entry);
   }
index e82ece6b41eb5fd5cb64796c2c660d28e83b07d7..195edd587106c0372dc6f628ba2aa63acd619962 100644 (file)
@@ -32,6 +32,13 @@ void silc_client_update_client(SilcClient client,
                               const char *username,
                               const char *userinfo,
                               SilcUInt32 mode);
+SilcBool silc_client_change_nickname(SilcClient client,
+                                    SilcClientConnection conn,
+                                    SilcClientEntry client_entry,
+                                    const char *new_nick,
+                                    SilcClientID *new_id,
+                                    const unsigned char *idp,
+                                    SilcUInt32 idp_len);
 void silc_client_del_client_entry(SilcClient client,
                                  SilcClientConnection conn,
                                  SilcClientEntry client_entry);
index 7d42b470789c541559ba32d6d33687962573e83d..4478142ff8f7b2ecb1f3dd587449b540c608adbe 100644 (file)
@@ -157,9 +157,7 @@ struct SilcClientInternalStruct {
 
 /* Internal context for conn->internal in SilcClientConnection. */
 struct SilcClientConnectionInternalStruct {
-  SilcIDCacheEntry local_entry;                 /* Local client cache entry */
   SilcClientConnectionParams params;    /* Connection parameters */
-
   SilcFSMStruct fsm;                    /* Connection FSM */
   SilcFSMThreadStruct event_thread;      /* FSM thread for events */
   SilcFSMSemaStruct wait_event;                 /* Event signaller */
index 068b22d5926560c9dc9c9389a27f3e85eb96c8d1..e8665f746f5cdc9e0882da810ec4f8f2de395154 100644 (file)
@@ -99,7 +99,7 @@ SILC_FSM_STATE(silc_client_notify)
   }
 
   if (!silc_notify_get_args(payload)) {
-    SILC_LOG_DEBUG(("Malformed notify"));
+    SILC_LOG_DEBUG(("Malformed notify %d", silc_notify_get_type(payload)));
     silc_notify_payload_free(payload);
     silc_packet_free(packet);
     return SILC_FSM_FINISH;
@@ -489,7 +489,7 @@ SILC_FSM_STATE(silc_client_notify_signoff)
 
   /* Get signoff message */
   tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
-  if (tmp_len > 128)
+  if (tmp && tmp_len > 128)
     tmp[128] = '\0';
 
   /* Notify application */
@@ -636,7 +636,7 @@ SILC_FSM_STATE(silc_client_notify_nick_change)
   SilcNotifyType type = silc_notify_get_type(payload);
   SilcArgumentPayload args = silc_notify_get_args(payload);
   SilcClientEntry client_entry = NULL;
-  unsigned char *tmp, *nick, oldnick[128 + 1];
+  unsigned char *tmp, oldnick[128 + 1];
   SilcUInt32 tmp_len;
   SilcID id, id2;
 
@@ -691,24 +691,11 @@ SILC_FSM_STATE(silc_client_notify_nick_change)
     goto out;
   }
 
-  /* Normalize nickname */
-  nick = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8, 128, NULL);
-  if (!nick)
-    goto out;
-
-  /* Update nickname */
-  silc_mutex_lock(conn->internal->lock);
-  if (!silc_idcache_update_by_context(conn->internal->client_cache,
-                                     client_entry, NULL, nick, TRUE)) {
-    silc_free(nick);
-    silc_mutex_unlock(conn->internal->lock);
-    goto out;
-  }
-  silc_mutex_unlock(conn->internal->lock);
+  /* Change the nickname */
   memcpy(oldnick, client_entry->nickname, sizeof(client_entry->nickname));
-  memcpy(client_entry->nickname, tmp, tmp_len);
-  client_entry->nickname_normalized = nick;
-  silc_client_nickname_format(client, conn, client_entry);
+  if (!silc_client_change_nickname(client, conn, client_entry, tmp,
+                                  &id2.u.client_id, NULL, 0))
+    goto out;
 
   /* Notify application */
   NOTIFY(client, conn, type, client_entry, client_entry->nickname, oldnick);
@@ -876,6 +863,8 @@ SILC_FSM_STATE(silc_client_notify_cmode_change)
     chpks = silc_argument_list_parse_decoded(tmp, tmp_len,
                                             SILC_ARGUMENT_PUBLIC_KEY);
 
+  /* XXX add to/remove from channel pubkeys channel->channel_pubkeys */
+
   /* Notify application. */
   NOTIFY(client, conn, type, id.type, entry, mode, cipher, hmac,
         passphrase, channel->founder_key, chpks, channel);
index deb5d9a87e7a3c5ea4f213a5132aa4644b264d18..ab5665eacc05cc35b013194eaaccfebbe0f77247 100644 (file)
@@ -37,11 +37,11 @@ SilcBool silc_client_send_private_message(SilcClient client,
   SilcBuffer buffer;
   SilcBool ret;
 
-  if (!client || !conn || !client_entry)
+  if (silc_unlikely(!client || !conn || !client_entry))
     return FALSE;
-  if (flags & SILC_MESSAGE_FLAG_SIGNED && !hash)
+  if (silc_unlikely(flags & SILC_MESSAGE_FLAG_SIGNED && !hash))
     return FALSE;
-  if (conn->internal->disconnected)
+  if (silc_unlikely(conn->internal->disconnected))
     return FALSE;
 
   SILC_LOG_DEBUG(("Sending private message"));
@@ -55,7 +55,7 @@ SilcBool silc_client_send_private_message(SilcClient client,
                                client_entry->internal.hmac_send,
                                client->rng, NULL, conn->private_key,
                                hash, NULL);
-  if (!buffer) {
+  if (silc_unlikely(!buffer)) {
     SILC_LOG_ERROR(("Error encoding private message"));
     return FALSE;
   }
@@ -114,14 +114,15 @@ SILC_FSM_STATE(silc_client_private_message)
 
   SILC_LOG_DEBUG(("Received private message"));
 
-  if (packet->src_id_type != SILC_ID_CLIENT) {
+  if (silc_unlikely(packet->src_id_type != SILC_ID_CLIENT)) {
     /** Invalid packet */
     silc_fsm_next(fsm, silc_client_private_message_error);
     return SILC_FSM_CONTINUE;
   }
 
-  if (!silc_id_str2id(packet->src_id, packet->src_id_len, SILC_ID_CLIENT,
-                     &remote_id, sizeof(remote_id))) {
+  if (silc_unlikely(!silc_id_str2id(packet->src_id, packet->src_id_len,
+                                   SILC_ID_CLIENT, &remote_id,
+                                   sizeof(remote_id)))) {
     /** Invalid source ID */
     silc_fsm_next(fsm, silc_client_private_message_error);
     return SILC_FSM_CONTINUE;
@@ -139,9 +140,9 @@ SILC_FSM_STATE(silc_client_private_message)
     /* NOT REACHED */
   }
 
-  if (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY &&
-      !remote_client->internal.receive_key &&
-      !remote_client->internal.hmac_receive)
+  if (silc_unlikely(packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY &&
+                   !remote_client->internal.receive_key &&
+                   !remote_client->internal.hmac_receive))
     goto out;
 
   /* Parse the payload and decrypt it also if private message key is set */
@@ -151,7 +152,7 @@ SILC_FSM_STATE(silc_client_private_message)
                               remote_client->internal.receive_key,
                               remote_client->internal.hmac_receive,
                               NULL, FALSE, NULL);
-  if (!payload)
+  if (silc_unlikely(!payload))
     goto out;
 
 #if 0 /* We need to rethink this.  This doesn't work with multiple
@@ -548,12 +549,12 @@ SilcBool silc_client_add_private_message_key_ske(SilcClient client,
   if (client_entry->internal.prv_resp) {
     silc_cipher_set_key(client_entry->internal.send_key,
                        keymat->receive_enc_key,
-                       keymat->enc_key_len);
+                       keymat->enc_key_len, TRUE);
     silc_cipher_set_iv(client_entry->internal.send_key,
                       keymat->receive_iv);
     silc_cipher_set_key(client_entry->internal.receive_key,
                        keymat->send_enc_key,
-                       keymat->enc_key_len);
+                       keymat->enc_key_len, FALSE);
     silc_cipher_set_iv(client_entry->internal.receive_key, keymat->send_iv);
     silc_hmac_set_key(client_entry->internal.hmac_send,
                      keymat->receive_hmac_key,
@@ -564,12 +565,12 @@ SilcBool silc_client_add_private_message_key_ske(SilcClient client,
   } else {
     silc_cipher_set_key(client_entry->internal.send_key,
                        keymat->send_enc_key,
-                       keymat->enc_key_len);
+                       keymat->enc_key_len, TRUE);
     silc_cipher_set_iv(client_entry->internal.send_key,
                       keymat->send_iv);
     silc_cipher_set_key(client_entry->internal.receive_key,
                        keymat->receive_enc_key,
-                       keymat->enc_key_len);
+                       keymat->enc_key_len, FALSE);
     silc_cipher_set_iv(client_entry->internal.receive_key, keymat->receive_iv);
     silc_hmac_set_key(client_entry->internal.hmac_send,
                      keymat->send_hmac_key,
index 2b28d4542ddba38cbbbaa9e4802406630602fa91..c5f4cfc95dbe5a61ce4912ab631beb7e53d0c4e5 100644 (file)
@@ -29,11 +29,7 @@ typedef struct {
   SilcClientConnection conn;
   SilcBufferStruct detach;
   char *nickname;
-  SilcClientID client_id;
   SilcUInt32 channel_count;
-  SilcUInt32 *cmd_idents;
-  SilcUInt32 cmd_idents_count;
-  SilcBool success;
 } *SilcClientResumeSession;
 
 /************************ Static utility functions **************************/
@@ -72,6 +68,21 @@ silc_client_resume_continue(SilcClient client,
   return TRUE;
 }
 
+/* Function used to call command replies back to application in resuming. */
+
+static void
+silc_client_resume_command_callback(SilcClient client,
+                                   SilcClientConnection conn,
+                                   SilcCommand command, ...)
+{
+  va_list ap;
+  va_start(ap, command);
+  client->internal->ops->command_reply(client, conn, command,
+                                      SILC_STATUS_OK, SILC_STATUS_OK, ap);
+  va_end(ap);
+}
+
+
 /****************************** NEW_ID packet *******************************/
 
 /* Received new ID packet from server during registering to SILC network */
@@ -104,20 +115,10 @@ SILC_FSM_STATE(silc_client_new_id)
   if (!conn->local_entry)
     goto out;
 
-  /* Save the ID */
+  /* Save the ID.  Take reference to conn->local_id. */
   conn->local_id = &conn->local_entry->id;
   conn->internal->local_idp = silc_buffer_copy(&packet->buffer);
 
-  /* Save cache entry */
-  silc_mutex_lock(conn->internal->lock);
-  if (!silc_idcache_find_by_id_one(conn->internal->client_cache,
-                                  conn->local_id,
-                                  &conn->internal->local_entry)) {
-    silc_mutex_unlock(conn->internal->lock);
-    goto out;
-  }
-  silc_mutex_unlock(conn->internal->lock);
-
   /* Save remote ID */
   if (packet->src_id_len) {
     conn->internal->remote_idp =
@@ -284,6 +285,7 @@ SILC_FSM_STATE(silc_client_st_resume)
   SilcBuffer auth;
   unsigned char *id;
   SilcUInt16 id_len;
+  SilcClientID client_id;
   int ret;
 
   SILC_LOG_DEBUG(("Resuming detached session"));
@@ -312,13 +314,15 @@ SILC_FSM_STATE(silc_client_st_resume)
                             SILC_STR_END);
   if (ret < 0) {
     /** Malformed detach data */
+    SILC_LOG_DEBUG(("Malformed detachment data"));
     silc_fsm_next(fsm, silc_client_st_resume_error);
     return SILC_FSM_CONTINUE;
   }
 
-  if (!silc_id_str2id(id, id_len, SILC_ID_CLIENT, &resume->client_id,
-                     sizeof(resume->client_id))) {
+  if (!silc_id_str2id(id, id_len, SILC_ID_CLIENT, &client_id,
+                     sizeof(client_id))) {
     /** Malformed ID */
+    SILC_LOG_DEBUG(("Malformed ID"));
     silc_fsm_next(fsm, silc_client_st_resume_error);
     return SILC_FSM_CONTINUE;
   }
@@ -328,8 +332,7 @@ SILC_FSM_STATE(silc_client_st_resume)
                                            conn->private_key,
                                            client->rng,
                                            conn->internal->hash,
-                                           &resume->client_id,
-                                           SILC_ID_CLIENT);
+                                           &client_id, SILC_ID_CLIENT);
   if (!auth) {
     /** Out of memory */
     silc_fsm_next(fsm, silc_client_st_resume_error);
@@ -344,6 +347,7 @@ SILC_FSM_STATE(silc_client_st_resume)
                                         silc_buffer_len(auth)),
                           SILC_STR_END)) {
     /** Error sending packet */
+    SILC_LOG_DEBUG(("Error sending packet"));
     silc_fsm_next(fsm, silc_client_st_resume_error);
     return SILC_FSM_CONTINUE;
   }
@@ -365,6 +369,12 @@ SILC_FSM_STATE(silc_client_st_resume_resolve_channels)
   unsigned char **res_argv = NULL;
   int i;
 
+  if (conn->internal->disconnected) {
+    /** Disconnected */
+    silc_fsm_next(fsm, silc_client_st_resume_error);
+    return SILC_FSM_CONTINUE;
+  }
+
   if (!conn->local_id) {
     /** Timeout, ID not received */
     conn->internal->registering = FALSE;
@@ -372,32 +382,47 @@ SILC_FSM_STATE(silc_client_st_resume_resolve_channels)
     return SILC_FSM_CONTINUE;
   }
 
-  /* First, send UMODE command to get our own user mode in the network */
+  /* Change our nickname */
+  silc_client_change_nickname(client, conn, conn->local_entry,
+                             resume->nickname, NULL, NULL, 0);
+
+  /* Send UMODE command to get our own user mode in the network */
   SILC_LOG_DEBUG(("Resolving user mode"));
   silc_client_command_send(client, conn, SILC_COMMAND_UMODE,
                           silc_client_register_command_called, NULL,
                           1, 1, silc_buffer_data(conn->internal->local_idp),
                           silc_buffer_len(conn->internal->local_idp));
 
-  /* Second, send IDENTIFY command for all channels we know about.  These
-     are the channels we've joined to according our detachment data. */
+  /* Send IDENTIFY command for all channels we know about.  These are the
+     channels we've joined to according our detachment data. */
   for (i = 0; i < resume->channel_count; i++) {
-    SilcChannelID channel_id;
+    SilcChannelEntry channel;
     unsigned char *chid;
     SilcUInt16 chid_len;
     SilcBuffer idp;
+    SilcChannelID channel_id;
+    char *name;
 
     if (silc_buffer_unformat(&resume->detach,
                             SILC_STR_ADVANCE,
-                            SILC_STR_UI16_NSTRING(NULL, NULL),
+                            SILC_STR_UI16_NSTRING(&name, NULL),
                             SILC_STR_UI16_NSTRING(&chid, &chid_len),
                             SILC_STR_UI_INT(NULL),
                             SILC_STR_END) < 0)
       continue;
 
+    if (!silc_id_str2id(chid, chid_len, SILC_ID_CHANNEL, &channel_id,
+                       sizeof(channel_id)))
+      continue;
     idp = silc_id_payload_encode_data(chid, chid_len, SILC_ID_CHANNEL);
     if (!idp)
       continue;
+
+    /* Add the channel to cache */
+    channel = silc_client_get_channel_by_id(client, conn, &channel_id);
+    if (!channel)
+      silc_client_add_channel(client, conn, name, 0, &channel_id);
+
     res_argv = silc_realloc(res_argv, sizeof(*res_argv) * (res_argc + 1));
     res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
                                 (res_argc + 1));
@@ -427,30 +452,176 @@ SILC_FSM_STATE(silc_client_st_resume_resolve_channels)
   return SILC_FSM_WAIT;
 }
 
-/* Resolve joined channel modes. */
+/* Resolve joined channel modes, users and topics. */
 
 SILC_FSM_STATE(silc_client_st_resume_resolve_cmodes)
 {
   SilcClientConnection conn = fsm_context;
+  SilcClient client = conn->client;
   SilcClientResumeSession resume = state_context;
-  SilcHashTableList htl;
-  SilcChannelUser chu;
+  SilcIDCacheEntry entry;
+  SilcChannelEntry channel;
+  SilcList channels;
+  SilcBuffer idp;
+
+  if (conn->internal->disconnected) {
+    /** Disconnected */
+    silc_fsm_next(fsm, silc_client_st_resume_error);
+    return SILC_FSM_CONTINUE;
+  }
 
-  SILC_LOG_DEBUG(("Resolving joined channel modes"));
+  SILC_LOG_DEBUG(("Resolving channel details"));
 
-  silc_hash_table_list(conn->local_entry->channels, &htl);
-  while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
+  /** Wait for channel modes */
+  silc_fsm_next(fsm, silc_client_st_resume_completed);
 
+  if (!silc_idcache_get_all(conn->internal->channel_cache, &channels))
+    return SILC_FSM_CONTINUE;
+
+  /* Resolve channels' mode, users and topic */
+  resume->channel_count = silc_list_count(channels) * 3;
+  silc_list_start(channels);
+  while ((entry = silc_list_get(channels))) {
+    channel = entry->context;
+    idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
+    if (!idp)
+      continue;
+
+    silc_client_command_send(client, conn, SILC_COMMAND_CMODE,
+                            silc_client_resume_continue, conn, 1,
+                            1, silc_buffer_data(idp),
+                            silc_buffer_len(idp));
+    silc_client_command_send(client, conn, SILC_COMMAND_USERS,
+                            silc_client_resume_continue, conn, 1,
+                            1, silc_buffer_data(idp),
+                            silc_buffer_len(idp));
+    silc_client_command_send(client, conn, SILC_COMMAND_TOPIC,
+                            silc_client_resume_continue, conn, 1,
+                            1, silc_buffer_data(idp),
+                            silc_buffer_len(idp));
+    silc_buffer_free(idp);
   }
-  silc_hash_table_list_reset(&htl);
+
+  return SILC_FSM_WAIT;
+}
+
+/* Resuming completed */
+
+SILC_FSM_STATE(silc_client_st_resume_completed)
+{
+  SilcClientConnection conn = fsm_context;
+  SilcClient client = conn->client;
+  SilcClientResumeSession resume = state_context;
+  SilcIDCacheEntry entry;
+  SilcChannelEntry channel;
+  SilcList channels;
+
+  if (conn->internal->disconnected) {
+    /** Disconnected */
+    silc_fsm_next(fsm, silc_client_st_resume_error);
+    return SILC_FSM_CONTINUE;
+  }
+
+  if (resume->channel_count > 0) {
+    resume->channel_count--;
+    if (resume->channel_count)
+      return SILC_FSM_WAIT;
+  }
+
+  SILC_LOG_DEBUG(("Resuming completed"));
+
+  /* Issue IDENTIFY command for itself to get resolved hostname
+     correctly from server. */
+  silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
+                          silc_client_register_command_called, NULL,
+                          1, 5, silc_buffer_data(conn->internal->local_idp),
+                          silc_buffer_len(conn->internal->local_idp));
+
+  /* Issue INFO command to fetch the real server name and server
+     information and other stuff. */
+  silc_client_command_send(client, conn, SILC_COMMAND_INFO,
+                          silc_client_register_command_called, NULL,
+                          1, 2, silc_buffer_data(conn->internal->remote_idp),
+                          silc_buffer_len(conn->internal->remote_idp));
+
+  /* Call connection callback.  We have now resumed to SILC network. */
+  conn->callback(client, conn, SILC_CLIENT_CONN_SUCCESS_RESUME, 0, NULL,
+                conn->callback_context);
+
+  /* Call NICK command reply. */
+  silc_client_resume_command_callback(client, conn, SILC_COMMAND_NICK,
+                                     conn->local_entry,
+                                     conn->local_entry->nickname,
+                                     &conn->local_entry->id);
+
+  /* Call JOIN command replies for all joined channel */
+  silc_idcache_get_all(conn->internal->channel_cache, &channels);
+  silc_list_start(channels);
+  while ((entry = silc_list_get(channels))) {
+    SilcHashTableList htl;
+    const char *cipher, *hmac;
+
+    channel = entry->context;
+    cipher = (channel->internal.channel_key ?
+             silc_cipher_get_name(channel->internal.channel_key) : NULL);
+    hmac = (channel->internal.hmac ?
+           silc_hmac_get_name(channel->internal.hmac) : NULL);
+    silc_hash_table_list(channel->user_list, &htl);
+    silc_client_resume_command_callback(client, conn, SILC_COMMAND_JOIN,
+                                       channel->channel_name, channel,
+                                       channel->mode, &htl, channel->topic,
+                                       cipher, hmac, channel->founder_key,
+                                       channel->channel_pubkeys,
+                                       channel->user_limit);
+    silc_hash_table_list_reset(&htl);
+  }
+
+  conn->internal->registering = FALSE;
+  silc_schedule_task_del_by_all(conn->internal->schedule, 0,
+                               silc_client_connect_timeout, conn);
+  silc_free(resume->nickname);
+  silc_free(resume);
 
   return SILC_FSM_FINISH;
 }
 
+/* Error resuming to network */
+
 SILC_FSM_STATE(silc_client_st_resume_error)
 {
-  /* XXX */
-  /* Close connection */
+  SilcClientConnection conn = fsm_context;
+  SilcClient client = conn->client;
+  SilcClientResumeSession resume = state_context;
+
+  if (conn->internal->disconnected) {
+    if (resume) {
+      silc_free(resume->nickname);
+      silc_free(resume);
+    }
+    return SILC_FSM_FINISH;
+  }
+
+  SILC_LOG_DEBUG(("Error resuming to network"));
+
+  /* Signal to close connection */
+  if (!conn->internal->disconnected) {
+    conn->internal->disconnected = TRUE;
+    SILC_FSM_SEMA_POST(&conn->internal->wait_event);
+  }
+
+  /* Call connect callback */
+  if (conn->internal->callback_called)
+    conn->callback(client, conn, SILC_CLIENT_CONN_ERROR, 0, NULL,
+                  conn->callback_context);
+  conn->internal->callback_called = TRUE;
+
+  silc_schedule_task_del_by_all(conn->internal->schedule, 0,
+                               silc_client_connect_timeout, conn);
+
+  if (resume) {
+    silc_free(resume->nickname);
+    silc_free(resume);
+  }
 
   return SILC_FSM_FINISH;
 }
@@ -464,11 +635,14 @@ SilcBuffer silc_client_get_detach_data(SilcClient client,
   SilcBuffer detach;
   SilcHashTableList htl;
   SilcChannelUser chu;
+  unsigned char id[64];
+  SilcUInt32 id_len;
   int ret, ch_count;
 
   SILC_LOG_DEBUG(("Creating detachment data"));
 
   ch_count = silc_hash_table_count(conn->local_entry->channels);
+  silc_id_id2str(conn->local_id, SILC_ID_CLIENT, id, sizeof(id), &id_len);
 
   /* Save the nickname, Client ID and user mode in SILC network */
   detach = silc_buffer_alloc(0);
@@ -480,12 +654,8 @@ SilcBuffer silc_client_get_detach_data(SilcClient client,
                       SILC_STR_UI_SHORT(strlen(conn->local_entry->nickname)),
                       SILC_STR_DATA(conn->local_entry->nickname,
                                     strlen(conn->local_entry->nickname)),
-                      SILC_STR_UI_SHORT(silc_buffer_len(conn->internal->
-                                                        local_idp)),
-                      SILC_STR_DATA(silc_buffer_data(conn->internal->
-                                                     local_idp),
-                                    silc_buffer_len(conn->internal->
-                                                    local_idp)),
+                      SILC_STR_UI_SHORT(id_len),
+                      SILC_STR_DATA(id, id_len),
                       SILC_STR_UI_INT(conn->local_entry->mode),
                       SILC_STR_UI_INT(ch_count),
                       SILC_STR_END);
@@ -511,7 +681,6 @@ SilcBuffer silc_client_get_detach_data(SilcClient client,
                       SILC_STR_DATA(chid, chid_len),
                       SILC_STR_UI_INT(chu->channel->mode),
                       SILC_STR_END);
-    silc_free(chid);
   }
   silc_hash_table_list_reset(&htl);
 
index dca9ff9c81a0b4021576df3e96eb532aba97602f..37a8c7c8a54d4fbdc5f933dceddc821939110297 100644 (file)
@@ -27,6 +27,7 @@ SILC_FSM_STATE(silc_client_st_register_error);
 SILC_FSM_STATE(silc_client_st_resume);
 SILC_FSM_STATE(silc_client_st_resume_resolve_channels);
 SILC_FSM_STATE(silc_client_st_resume_resolve_cmodes);
+SILC_FSM_STATE(silc_client_st_resume_completed);
 SILC_FSM_STATE(silc_client_st_resume_error);
 
 SilcBuffer silc_client_get_detach_data(SilcClient client,
index 236fb0f67674b23a236bea53b5b9a30fd8912d8f..bfc114fa7a2b575e37bdc7e9cc3c17f58c697544 100644 (file)
@@ -106,10 +106,11 @@ static void silc_client_command_process_error(SilcClientCommandContext cmd,
   SilcClient client = cmd->conn->client;
   SilcClientConnection conn = cmd->conn;
   SilcArgumentPayload args = silc_command_get_args(payload);
-  SilcClientEntry client_entry;
   SilcID id;
 
   if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
+    SilcClientEntry client_entry;
+
     /* Remove unknown client entry from cache */
     if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
       return;
@@ -120,6 +121,38 @@ static void silc_client_command_process_error(SilcClientCommandContext cmd,
       silc_client_del_client(client, conn, client_entry);
       silc_client_unref_client(client, conn, client_entry);
     }
+    return;
+  }
+
+  if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID) {
+    SilcChannelEntry channel;
+
+    /* Remove unknown client entry from cache */
+    if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
+      return;
+
+    channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
+    if (channel) {
+      silc_client_empty_channel(client, conn, channel);
+      silc_client_del_channel(client, conn, channel);
+      silc_client_unref_channel(client, conn, channel);
+    }
+    return;
+  }
+
+  if (cmd->error == SILC_STATUS_ERR_NO_SUCH_SERVER_ID) {
+    SilcServerEntry server_entry;
+
+    /* Remove unknown client entry from cache */
+    if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
+      return;
+
+    server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
+    if (server_entry) {
+      silc_client_del_server(client, conn, server_entry);
+      silc_client_unref_server(client, conn, server_entry);
+    }
+    return;
   }
 }
 
@@ -617,7 +650,7 @@ SILC_FSM_STATE(silc_client_command_reply_identify)
     channel_entry = silc_client_get_channel_by_id(client, conn,
                                                  &id.u.channel_id);
     if (!channel_entry) {
-      SILC_LOG_DEBUG(("Adding new channel entry (IDENTIFY"));
+      SILC_LOG_DEBUG(("Adding new channel entry (IDENTIFY)"));
 
       if (!name) {
        ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
@@ -656,7 +689,7 @@ SILC_FSM_STATE(silc_client_command_reply_nick)
   SilcClient client = conn->client;
   SilcCommandPayload payload = state_context;
   SilcArgumentPayload args = silc_command_get_args(payload);
-  unsigned char *tmp, *nick, *idp;
+  unsigned char *nick, *idp;
   SilcUInt32 len, idp_len;
   SilcClientID old_client_id;
   SilcID id;
@@ -665,8 +698,6 @@ SILC_FSM_STATE(silc_client_command_reply_nick)
   CHECK_STATUS("Cannot set nickname: ");
   CHECK_ARGS(2, 3);
 
-  old_client_id = *conn->local_id;
-
   /* Take received Client ID */
   idp = silc_argument_get_arg_type(args, 2, &idp_len);
   if (!idp) {
@@ -685,32 +716,14 @@ SILC_FSM_STATE(silc_client_command_reply_nick)
     goto out;
   }
 
-  /* Normalize nickname */
-  tmp = silc_identifier_check(nick, len, SILC_STRING_UTF8, 128, NULL);
-  if (!tmp) {
+  /* Change the nickname */
+  old_client_id = *conn->local_id;
+  if (!silc_client_change_nickname(client, conn, conn->local_entry,
+                                  nick, &id.u.client_id, idp, idp_len)) {
     ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME);
     goto out;
   }
 
-  /* Update the client entry */
-  silc_mutex_lock(conn->internal->lock);
-  if (!silc_idcache_update(conn->internal->client_cache,
-                          conn->internal->local_entry,
-                          &id.u.client_id, tmp, TRUE)) {
-    silc_free(tmp);
-    silc_mutex_unlock(conn->internal->lock);
-    ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME);
-    goto out;
-  }
-  silc_mutex_unlock(conn->internal->lock);
-  memset(conn->local_entry->nickname, 0, sizeof(conn->local_entry->nickname));
-  memcpy(conn->local_entry->nickname, nick, len);
-  conn->local_entry->nickname_normalized = tmp;
-  silc_buffer_enlarge(conn->internal->local_idp, idp_len);
-  silc_buffer_put(conn->internal->local_idp, idp, idp_len);
-  silc_client_nickname_format(client, conn, conn->local_entry);
-  silc_packet_set_ids(conn->stream, SILC_ID_CLIENT, conn->local_id, 0, NULL);
-
   /* Notify application */
   silc_client_command_callback(cmd, conn->local_entry,
                               conn->local_entry->nickname, &old_client_id);
@@ -1099,7 +1112,6 @@ SILC_FSM_STATE(silc_client_command_reply_join)
   const char *cipher;
   SilcBufferStruct client_id_list, client_mode_list, keyp;
   SilcHashTableList htl;
-  SilcDList chpks = NULL;
   SilcID id;
   int i;
 
@@ -1253,8 +1265,8 @@ SILC_FSM_STATE(silc_client_command_reply_join)
   /* Get channel public key list */
   tmp = silc_argument_get_arg_type(args, 16, &len);
   if (tmp)
-    chpks = silc_argument_list_parse_decoded(tmp, len,
-                                            SILC_ARGUMENT_PUBLIC_KEY);
+    channel->channel_pubkeys =
+      silc_argument_list_parse_decoded(tmp, len, SILC_ARGUMENT_PUBLIC_KEY);
 
   /* Set current channel */
   conn->current_channel = channel;
@@ -1266,10 +1278,8 @@ SILC_FSM_STATE(silc_client_command_reply_join)
   /* Notify application */
   silc_client_command_callback(cmd, channel_name, channel, mode, &htl,
                               topic, cipher, hmac, channel->founder_key,
-                              chpks, channel->user_limit);
+                              channel->channel_pubkeys, channel->user_limit);
 
-  if (chpks)
-    silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
   silc_hash_table_list_reset(&htl);
   silc_client_unref_channel(client, conn, channel);
 
@@ -1621,20 +1631,18 @@ SILC_FSM_STATE(silc_client_command_reply_detach)
   CHECK_STATUS("Cannot detach: ");
   CHECK_ARGS(1, 1);
 
-  /* Notify application */
-  silc_client_command_callback(cmd);
-
-#if 0
-  /* Generate the detachment data and deliver it to the client in the
-     detach client operation */
+  /* Get detachment data */
   detach = silc_client_get_detach_data(client, conn);
-  if (detach) {
-    client->internal->ops->detach(client, conn, silc_buffer_data(detach),
-                                 silc_buffer_len(detach));
-    silc_buffer_free(detach);
+  if (!detach) {
+    ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
+    goto out;
   }
-#endif /* 0 */
 
+  /* Notify application */
+  silc_client_command_callback(cmd, detach);
+  silc_buffer_free(detach);
+
+ out:
   silc_fsm_next(fsm, silc_client_command_reply_processed);
   return SILC_FSM_CONTINUE;
 }
index ee1e0edd039bd308d52cdac1854d0826233010bf..a94648bcf58d9095f45127be5b0ac80ff6b1adee 100644 (file)
@@ -607,26 +607,6 @@ typedef struct {
   void (*ftp)(SilcClient client, SilcClientConnection conn,
              SilcClientEntry client_entry, SilcUInt32 session_id,
              const char *hostname, SilcUInt16 port);
-
-  /* Delivers SILC session detachment data indicated by `detach_data' to the
-     application.  If application has issued SILC_COMMAND_DETACH command
-     the client session in the SILC network is not quit.  The client remains
-     in the network but is detached.  The detachment data may be used later
-     to resume the session in the SILC Network.  The appliation is
-     responsible of saving the `detach_data', to for example in a file.
-
-     The detachment data can be given as argument to the functions
-     silc_client_connect_to_server or silc_client_key_exchange when creating
-     connection to remote host, inside SilcClientConnectionParams structure.
-     If it is provided the client library will attempt to resume the session
-     in the network.  After the connection is created successfully, the
-     application is responsible of setting the user interface for user into
-     the same state it was before detaching (showing same channels, channel
-     modes, etc).  It can do this by fetching the information (like joined
-     channels) from the client library. */
-  void (*detach)(SilcClient client, SilcClientConnection conn,
-                const unsigned char *detach_data,
-                SilcUInt32 detach_data_len);
 } SilcClientOperations;
 /***/
 
@@ -949,17 +929,14 @@ typedef struct {
      client, but must be FALSE with server connections. */
   SilcBool no_authentication;
 
-  /* The SILC session detachment data that was returned by `detach' client
-     operation when the application detached from the network.  Application
-     is responsible of saving the data and giving it as argument here
-     for resuming the session in the SILC network.
-
-     If this is provided here the client library will attempt to resume
-     the session in the network.  After the connection is created
-     successfully, the application is responsible of setting the user
-     interface for user into the same state it was before detaching (showing
-     same channels, channel modes, etc).  It can do this by fetching the
-     information (like joined channels) from the client library. */
+  /* The SILC session detachment data that was returned in the `command_reply'
+     client operation for SILC_COMMAND_DETACH command.  If this is provided
+     here the client library will attempt to resume the session in the network.
+     After the connection is created and the session has been resumed the
+     client will receive SILC_COMMAND_NICK command_reply for the client's
+     nickname in the network and SILC_COMMAND_JOIN command reply for all the
+     channels that the client has joined in the network.  It may also receive
+     SILC_COMMAND_UMODE command reply to set user's mode on the network. */
   unsigned char *detach_data;
   SilcUInt32 detach_data_len;
 
index ced8f4b1795f0317ed8f4c55068245b9f44cb8db..8b6cca255d4e4d98a558a62074fb6a7d2752a7de 100644 (file)
@@ -107,6 +107,7 @@ struct SilcChannelEntryStruct {
   char *channel_name;               /* Channel name */
   char *topic;                      /* Current topic, may be NULL */
   SilcPublicKey founder_key;        /* Founder key, may be NULL */
+  SilcDList channel_pubkeys;        /* Channel public keys, may be NULL */
   SilcChannelID id;                 /* Channel ID */
   SilcUInt32 mode;                  /* Channel mode, ChannelModes. */
   SilcUInt32 user_limit;            /* User limit on channel */