Handle command reply lists in threads.
[silc.git] / lib / silcclient / client_channel.c
index c843b63b9c3a558350f69e362efac5e73ed61336..51fc85471d11a358d2be3727a237c9bfc60957de 100644 (file)
@@ -47,6 +47,8 @@ SilcBool silc_client_send_channel_message(SilcClient client,
     return FALSE;
   if (flags & SILC_MESSAGE_FLAG_SIGNED && !hash)
     return FALSE;
+  if (conn->internal->disconnected)
+    return FALSE;
 
   chu = silc_client_on_channel(channel, conn->local_entry);
   if (!chu) {
@@ -200,6 +202,13 @@ SILC_FSM_STATE(silc_client_channel_message)
     return SILC_FSM_CONTINUE;
   }
 
+  /* Check that user is on channel */
+  if (!silc_client_on_channel(channel, client_entry)) {
+    /** User not on channel */
+    silc_fsm_next(fsm, silc_client_channel_message_error);
+    return SILC_FSM_CONTINUE;
+  }
+
   /* If there is no channel private key then just decrypt the message
      with the channel key. If private keys are set then just go through
      all private keys and check what decrypts correctly. */
@@ -480,7 +489,7 @@ SilcBool silc_client_add_channel_private_key(SilcClient client,
 
   /* Produce the key material */
   keymat = silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
-                                             client->sha1hash);
+                                             conn->internal->sha1hash);
   if (!keymat)
     return FALSE;
 
@@ -670,16 +679,19 @@ SilcChannelUser silc_client_on_channel(SilcChannelEntry channel,
   return NULL;
 }
 
-/* Adds client to channel */
+/* Adds client to channel.  Returns TRUE if user was added or is already
+   added to the channel, FALSE on error. */
 
-SilcBool silc_client_add_to_channel(SilcChannelEntry channel,
+SilcBool silc_client_add_to_channel(SilcClient client,
+                                   SilcClientConnection conn,
+                                   SilcChannelEntry channel,
                                    SilcClientEntry client_entry,
                                    SilcUInt32 cumode)
 {
   SilcChannelUser chu;
 
   if (silc_client_on_channel(channel, client_entry))
-    return FALSE;
+    return TRUE;
 
   chu = silc_calloc(1, sizeof(*chu));
   if (!chu)
@@ -688,6 +700,10 @@ SilcBool silc_client_add_to_channel(SilcChannelEntry channel,
   chu->client = client_entry;
   chu->channel = channel;
   chu->mode = cumode;
+
+  silc_client_ref_client(client, conn, client_entry);
+  silc_client_ref_channel(client, conn, channel);
+
   silc_hash_table_add(channel->user_list, client_entry, chu);
   silc_hash_table_add(client_entry->channels, channel, chu);
 
@@ -696,7 +712,9 @@ SilcBool silc_client_add_to_channel(SilcChannelEntry channel,
 
 /* Removes client from a channel */
 
-SilcBool silc_client_remove_from_channel(SilcChannelEntry channel,
+SilcBool silc_client_remove_from_channel(SilcClient client,
+                                        SilcClientConnection conn,
+                                        SilcChannelEntry channel,
                                         SilcClientEntry client_entry)
 {
   SilcChannelUser chu;
@@ -709,6 +727,9 @@ SilcBool silc_client_remove_from_channel(SilcChannelEntry channel,
   silc_hash_table_del(chu->channel->user_list, chu->client);
   silc_free(chu);
 
+  silc_client_unref_client(client, conn, client_entry);
+  silc_client_unref_channel(client, conn, channel);
+
   return TRUE;
 }
 
@@ -725,8 +746,30 @@ void silc_client_remove_from_channels(SilcClient client,
   while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
     silc_hash_table_del(chu->client->channels, chu->channel);
     silc_hash_table_del(chu->channel->user_list, chu->client);
+    silc_client_unref_client(client, conn, chu->client);
+    silc_client_unref_channel(client, conn, chu->channel);
     silc_free(chu);
   }
 
   silc_hash_table_list_reset(&htl);
 }
+
+/* Empties channel from users. */
+
+void silc_client_empty_channel(SilcClient client,
+                              SilcClientConnection conn,
+                              SilcChannelEntry channel)
+{
+  SilcHashTableList htl;
+  SilcChannelUser chu;
+
+  silc_hash_table_list(channel->user_list, &htl);
+  while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
+    silc_hash_table_del(chu->client->channels, chu->channel);
+    silc_hash_table_del(chu->channel->user_list, chu->client);
+    silc_client_unref_client(client, conn, chu->client);
+    silc_client_unref_channel(client, conn, chu->channel);
+    silc_free(chu);
+  }
+  silc_hash_table_list_reset(&htl);
+}