Merge commit 'origin/silc.1.1.branch'
[silc.git] / lib / silcclient / command_reply.c
index 2fec85c6b8da502d97636ec479a49b57de849f7b..ede887535fdcdc97b6219d0c8d73f11b45867021 100644 (file)
@@ -118,6 +118,7 @@ static void silc_client_command_process_error(SilcClientCommandContext cmd,
     client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
     if (client_entry) {
       silc_client_remove_from_channels(client, conn, client_entry);
+      client_entry->internal.valid = FALSE;
       silc_client_del_client(client, conn, client_entry);
       silc_client_unref_client(client, conn, client_entry);
     }
@@ -947,6 +948,7 @@ SILC_FSM_STATE(silc_client_command_reply_kill)
   /* Remove the client */
   if (client_entry) {
     silc_client_remove_from_channels(client, conn, client_entry);
+    client_entry->internal.valid = FALSE;
     silc_client_del_client(client, conn, client_entry);
     silc_client_unref_client(client, conn, client_entry);
   }
@@ -1111,6 +1113,29 @@ silc_client_command_reply_join_resolved(SilcClient client,
 {
   SilcClientCommandContext cmd = context;
   SilcChannelEntry channel = cmd->context;
+  SilcCommandPayload payload = silc_fsm_get_state_context(&cmd->thread);
+  SilcArgumentPayload args = silc_command_get_args(payload);
+  SilcUInt32 list_count;
+  unsigned char *tmp;
+  char msg[512];
+
+  if (!clients) {
+    silc_snprintf(msg, sizeof(msg), "Error resolving channel %s user list",
+                 channel->channel_name);
+    SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR, msg);
+  } else {
+    tmp = silc_argument_get_arg_type(args, 12, NULL);
+    if (tmp) {
+      SILC_GET32_MSB(list_count, tmp);
+      if (list_count - silc_dlist_count(clients) > 5) {
+       silc_snprintf(msg, sizeof(msg),
+                     "Channel %s user list was not fully resolved. "
+                     "The channel may not be fully synced.",
+                     channel->channel_name);
+       SAY(client, conn, SILC_CLIENT_MESSAGE_WARNING, msg);
+      }
+    }
+  }
 
   channel->internal.resolve_cmd_ident = 0;
   silc_client_unref_channel(client, conn, channel);
@@ -1172,7 +1197,7 @@ SILC_FSM_STATE(silc_client_command_reply_join)
 
   /* Get the list count */
   tmp = silc_argument_get_arg_type(args, 12, &len);
-  if (!tmp) {
+  if (!tmp || len != 4) {
     ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
@@ -1210,7 +1235,6 @@ SILC_FSM_STATE(silc_client_command_reply_join)
   /* Add clients we received in the reply to the channel */
   for (i = 0; i < list_count; i++) {
     SilcUInt16 idp_len;
-    SilcUInt32 mode;
     SilcID id;
     SilcClientEntry client_entry;
 
@@ -1487,6 +1511,20 @@ SILC_FSM_STATE(silc_client_command_reply_cmode)
   silc_client_command_callback(cmd, channel, mode, public_key,
                               channel->channel_pubkeys, channel->user_limit);
 
+  silc_rwlock_wrlock(channel->internal.lock);
+
+  /* If founder key changed, update it */
+  if (public_key &&
+      (!channel->founder_key ||
+       !silc_pkcs_public_key_compare(public_key, channel->founder_key))) {
+    if (channel->founder_key)
+      silc_pkcs_public_key_free(channel->founder_key);
+    channel->founder_key = public_key;
+    public_key = NULL;
+  }
+
+  silc_rwlock_unlock(channel->internal.lock);
+
  out:
   silc_client_unref_channel(client, conn, channel);
   if (public_key)
@@ -1778,6 +1816,8 @@ SILC_FSM_STATE(silc_client_command_reply_leave)
   SilcCommandPayload payload = state_context;
   SilcArgumentPayload args = silc_command_get_args(payload);
   SilcChannelEntry channel;
+  SilcCipher key;
+  SilcHmac hmac;
   SilcID id;
 
   /* Sanity checks */
@@ -1803,6 +1843,32 @@ SILC_FSM_STATE(silc_client_command_reply_leave)
   /* Notify application */
   silc_client_command_callback(cmd, channel);
 
+  /* Remove old keys and stuff.  The channel may remain even after leaving
+     but we want to remove these always. */
+  if (channel->internal.send_key)
+    silc_cipher_free(channel->internal.send_key);
+  channel->internal.send_key = NULL;
+  if (channel->internal.receive_key)
+    silc_cipher_free(channel->internal.receive_key);
+  channel->internal.receive_key = NULL;
+  if (channel->internal.hmac)
+    silc_hmac_free(channel->internal.hmac);
+  channel->internal.hmac = NULL;
+  if (channel->internal.old_channel_keys) {
+    silc_dlist_start(channel->internal.old_channel_keys);
+    while ((key = silc_dlist_get(channel->internal.old_channel_keys)))
+      silc_cipher_free(key);
+    silc_dlist_uninit(channel->internal.old_channel_keys);
+  }
+  channel->internal.old_channel_keys = NULL;
+  if (channel->internal.old_hmacs) {
+    silc_dlist_start(channel->internal.old_hmacs);
+    while ((hmac = silc_dlist_get(channel->internal.old_hmacs)))
+      silc_hmac_free(hmac);
+    silc_dlist_uninit(channel->internal.old_hmacs);
+  }
+  channel->internal.old_hmacs = NULL;
+
   /* Now delete the channel. */
   silc_client_empty_channel(client, conn, channel);
   silc_client_del_channel(client, conn, channel);