Integer type name change.
[silc.git] / lib / silcclient / client_channel.c
index 8bc011e1155d5626cdb833e5ecabd2ac6dc58116..c98a8823909d602fe8b666995b99e7e0f5e4e5ed 100644 (file)
@@ -22,7 +22,8 @@
    channel key receiving and setting, and channel private key handling 
    routines. */
 
-#include "clientlibincludes.h"
+#include "silcincludes.h"
+#include "silcclient.h"
 #include "client_internal.h"
 
 /* Sends packet to the `channel'. Packet to channel is always encrypted
@@ -38,7 +39,7 @@ void silc_client_send_channel_message(SilcClient client,
                                      SilcChannelPrivateKey key,
                                      SilcMessageFlags flags,
                                      unsigned char *data, 
-                                     uint32 data_len, 
+                                     SilcUInt32 data_len, 
                                      int force_send)
 {
   int i;
@@ -48,7 +49,7 @@ void silc_client_send_channel_message(SilcClient client,
   SilcCipher cipher;
   SilcHmac hmac;
   unsigned char *id_string;
-  uint32 iv_len;
+  SilcUInt32 iv_len;
   int block_len;
 
   SILC_LOG_DEBUG(("Sending packet to channel"));
@@ -95,7 +96,8 @@ void silc_client_send_channel_message(SilcClient client,
     for (i = 0; i < iv_len; i++) channel->iv[i] = 
                                   silc_rng_get_byte(client->rng);
   else
-    silc_hash_make(client->md5hash, channel->iv, iv_len, channel->iv);
+    silc_hash_make(client->internal->md5hash, channel->iv, iv_len, 
+                  channel->iv);
 
   /* Encode the channel payload. This also encrypts the message payload. */
   payload = silc_channel_message_payload_encode(flags, data_len, data, iv_len, 
@@ -155,17 +157,50 @@ void silc_client_send_channel_message(SilcClient client,
   silc_free(id_string);
 }
 
+typedef struct {
+  SilcChannelMessagePayload payload;
+  SilcChannelID *channel_id;
+} *SilcChannelClientResolve;
+
 static void silc_client_channel_message_cb(SilcClient client,
                                           SilcClientConnection conn,
                                           SilcClientEntry *clients,
-                                          uint32 clients_count,
+                                          SilcUInt32 clients_count,
                                           void *context)
 {
-  SilcPacketContext *packet = (SilcPacketContext *)context;
+  SilcChannelClientResolve res = (SilcChannelClientResolve)context;
+
+  if (clients_count == 1) {
+    SilcChannelEntry channel;
+    unsigned char *message;
+
+    channel = silc_client_get_channel_by_id(client, conn, res->channel_id);
+    if (!channel)
+      goto out;
+
+    /* If this client is not on channel, add it there since it clearly
+       is there. */
+    if (!silc_client_on_channel(channel, clients[0])) {
+      SilcChannelUser chu = silc_calloc(1, sizeof(*chu));
+      chu->client = clients[0];
+      chu->channel = channel;
+      silc_hash_table_add(channel->user_list, clients[0], chu);
+      silc_hash_table_add(clients[0]->channels, channel, chu);
+    }
+
+    message = silc_channel_message_get_data(res->payload, NULL);
+    
+    /* Pass the message to application */
+    client->internal->ops->channel_message(
+                              client, conn, clients[0], channel,
+                              silc_channel_message_get_flags(res->payload),
+                              message);
+  }
 
-  if (clients)
-    silc_client_channel_message(client, conn->sock, packet);
-  silc_packet_context_free(packet);
+ out:
+  silc_channel_message_payload_free(res->payload);
+  silc_free(res->channel_id);
+  silc_free(res);
 }
 
 /* Process received message to a channel (or from a channel, really). This
@@ -181,10 +216,8 @@ void silc_client_channel_message(SilcClient client,
   SilcChannelMessagePayload payload = NULL;
   SilcChannelID *id = NULL;
   SilcChannelEntry channel;
-  SilcChannelUser chu;
-  SilcIDCacheEntry id_cache = NULL;
+  SilcClientEntry client_entry;
   SilcClientID *client_id = NULL;
-  bool found = FALSE;
   unsigned char *message;
 
   SILC_LOG_DEBUG(("Start"));
@@ -202,31 +235,33 @@ void silc_client_channel_message(SilcClient client,
     goto out;
 
   /* Find the channel entry from channels on this connection */
-  if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)id, &id_cache))
+  channel = silc_client_get_channel_by_id(client, conn, id);
+  if (!channel)
     goto out;
 
-  channel = (SilcChannelEntry)id_cache->context;
-
   /* 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. */
   if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
     /* Parse the channel message payload. This also decrypts the payload */
-    payload = silc_channel_message_payload_parse(buffer, channel->channel_key,
+    payload = silc_channel_message_payload_parse(buffer->data, buffer->len, 
+                                                channel->channel_key,
                                                 channel->hmac);
 
     /* 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 (!channel->old_channel_key)
+      if (!channel->old_channel_key) {
        goto out;
+      }
 
-      payload = silc_channel_message_payload_parse(buffer, 
+      payload = silc_channel_message_payload_parse(buffer->data, buffer->len
                                                   channel->old_channel_key,
                                                   channel->old_hmac);
-      if (!payload)
+      if (!payload) {
        goto out;
+      }
     }
   } else if (channel->private_keys) {
     SilcChannelPrivateKey entry;
@@ -234,7 +269,8 @@ void silc_client_channel_message(SilcClient client,
     silc_dlist_start(channel->private_keys);
     while ((entry = silc_dlist_get(channel->private_keys)) != SILC_LIST_END) {
       /* Parse the channel message payload. This also decrypts the payload */
-      payload = silc_channel_message_payload_parse(buffer, entry->cipher,
+      payload = silc_channel_message_payload_parse(buffer->data, buffer->len, 
+                                                  entry->cipher,
                                                   entry->hmac);
       if (payload)
        break;
@@ -246,34 +282,36 @@ void silc_client_channel_message(SilcClient client,
   }
 
   /* Find client entry */
-  silc_list_start(channel->clients);
-  while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
-    if (SILC_ID_CLIENT_COMPARE(chu->client->id, client_id)) {
-      found = TRUE;
-      break;
-    }
-  }
-
-  if (!found) {
+  client_entry = silc_client_get_client_by_id(client, conn, client_id);
+  if (!client_entry || !client_entry->nickname) {
     /* Resolve the client info */
+    SilcChannelClientResolve res = silc_calloc(1, sizeof(*res));
+    res->payload = payload;
+    res->channel_id = id;
     silc_client_get_client_by_id_resolve(client, conn, client_id,
                                         silc_client_channel_message_cb,
-                                        silc_packet_context_dup(packet));
+                                        res);
+    payload = NULL;
+    id = NULL;
+    goto out;
+  }
+
+  if (!silc_client_on_channel(channel, client_entry)) {
+    SILC_LOG_WARNING(("Received channel message from client not on channel"));
     goto out;
   }
 
   message = silc_channel_message_get_data(payload, NULL);
 
   /* Pass the message to application */
-  client->ops->channel_message(client, conn, chu->client, channel,
-                              silc_channel_message_get_flags(payload),
-                              message);
+  client->internal->ops->channel_message(
+                                client, conn, client_entry, channel,
+                                silc_channel_message_get_flags(payload),
+                                message);
 
  out:
-  if (id)
-    silc_free(id);
-  if (client_id)
-    silc_free(client_id);
+  silc_free(id);
+  silc_free(client_id);
   if (payload)
     silc_channel_message_payload_free(payload);
 }
@@ -299,17 +337,18 @@ SILC_TASK_CALLBACK(silc_client_save_channel_key_rekey)
    receive Channel Key Payload and when we are processing JOIN command 
    reply. */
 
-void silc_client_save_channel_key(SilcClientConnection conn,
+void silc_client_save_channel_key(SilcClient client,
+                                 SilcClientConnection conn,
                                  SilcBuffer key_payload, 
                                  SilcChannelEntry channel)
 {
   unsigned char *id_string, *key, *cipher, *hmac, hash[32];
-  uint32 tmp_len;
+  SilcUInt32 tmp_len;
   SilcChannelID *id;
-  SilcIDCacheEntry id_cache = NULL;
   SilcChannelKeyPayload payload;
 
-  payload = silc_channel_key_payload_parse(key_payload);
+  payload = silc_channel_key_payload_parse(key_payload->data,
+                                          key_payload->len);
   if (!payload)
     return;
 
@@ -327,12 +366,9 @@ void silc_client_save_channel_key(SilcClientConnection conn,
 
   /* Find channel. */
   if (!channel) {
-    if (!silc_idcache_find_by_id_one(conn->channel_cache, 
-                                    (void *)id, &id_cache))
+    channel = silc_client_get_channel_by_id(client, conn, id);
+    if (!channel)
       goto out;
-    
-    /* Get channel entry */
-    channel = (SilcChannelEntry)id_cache->context;
   }
 
   hmac = (channel->hmac ? (char *)silc_hmac_get_name(channel->hmac) : 
@@ -346,11 +382,11 @@ void silc_client_save_channel_key(SilcClientConnection conn,
   if (channel->old_hmac)
     silc_hmac_free(channel->old_hmac);
   if (channel->rekey_task)
-    silc_schedule_task_del(conn->client->schedule, channel->rekey_task);
+    silc_schedule_task_del(client->schedule, channel->rekey_task);
   channel->old_channel_key = channel->channel_key;
   channel->old_hmac = channel->hmac;
   channel->rekey_task = 
-    silc_schedule_task_add(conn->client->schedule, 0,
+    silc_schedule_task_add(client->schedule, 0,
                           silc_client_save_channel_key_rekey, channel,
                           10, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
 
@@ -361,11 +397,12 @@ void silc_client_save_channel_key(SilcClientConnection conn,
   key = silc_channel_key_get_key(payload, &tmp_len);
   cipher = silc_channel_key_get_cipher(payload, NULL);
   channel->key_len = tmp_len * 8;
-  channel->key = silc_calloc(tmp_len, sizeof(*channel->key));
-  memcpy(channel->key, key, tmp_len);
+  channel->key = silc_memdup(key, tmp_len);
 
   if (!silc_cipher_alloc(cipher, &channel->channel_key)) {
-    conn->client->ops->say(conn->client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+    client->internal->ops->say(
+                          conn->client, conn, 
+                          SILC_CLIENT_MESSAGE_AUDIT,
                           "Cannot talk to channel: unsupported cipher %s", 
                           cipher);
     goto out;
@@ -399,7 +436,7 @@ void silc_client_receive_channel_key(SilcClient client,
   SILC_LOG_DEBUG(("Received key for channel"));
 
   /* Save the key */
-  silc_client_save_channel_key(sock->user_data, packet, NULL);
+  silc_client_save_channel_key(client, sock->user_data, packet, NULL);
 }
 
 /* Adds private key for channel. This may be set only if the channel's mode
@@ -437,7 +474,7 @@ int silc_client_add_channel_private_key(SilcClient client,
                                        char *cipher,
                                        char *hmac,
                                        unsigned char *key,
-                                       uint32 key_len)
+                                       SilcUInt32 key_len)
 {
   SilcChannelPrivateKey entry;
   unsigned char hash[32];
@@ -460,7 +497,7 @@ int silc_client_add_channel_private_key(SilcClient client,
   /* Produce the key material */
   keymat = silc_calloc(1, sizeof(*keymat));
   if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16, 
-                                        client->md5hash, keymat) 
+                                        client->internal->md5hash, keymat) 
       != SILC_SKE_STATUS_OK)
     return FALSE;
 
@@ -483,8 +520,7 @@ int silc_client_add_channel_private_key(SilcClient client,
 
   /* Save the key */
   entry = silc_calloc(1, sizeof(*entry));
-  entry->key = silc_calloc(keymat->enc_key_len / 8, sizeof(*entry->key));
-  memcpy(entry->key, keymat->send_enc_key, keymat->enc_key_len / 8);
+  entry->key = silc_memdup(keymat->send_enc_key, keymat->enc_key_len / 8);
   entry->key_len = keymat->enc_key_len / 8;
 
   /* Allocate the cipher and set the key*/
@@ -593,10 +629,10 @@ SilcChannelPrivateKey *
 silc_client_list_channel_private_keys(SilcClient client,
                                      SilcClientConnection conn,
                                      SilcChannelEntry channel,
-                                     uint32 *key_count)
+                                     SilcUInt32 *key_count)
 {
   SilcChannelPrivateKey *keys = NULL, entry;
-  uint32 count = 0;
+  SilcUInt32 count = 0;
 
   if (!channel->private_keys)
     return NULL;
@@ -617,7 +653,23 @@ silc_client_list_channel_private_keys(SilcClient client,
 /* Frees the SilcChannelPrivateKey array. */
 
 void silc_client_free_channel_private_keys(SilcChannelPrivateKey *keys,
-                                          uint32 key_count)
+                                          SilcUInt32 key_count)
 {
   silc_free(keys);
 }
+
+/* Returns the SilcChannelUser entry if the `client_entry' is joined on the 
+   channel indicated by the `channel'. NULL if client is not joined on
+   the channel. */
+
+SilcChannelUser silc_client_on_channel(SilcChannelEntry channel,
+                                      SilcClientEntry client_entry)
+{
+  SilcChannelUser chu;
+
+  if (silc_hash_table_find(channel->user_list, client_entry, NULL, 
+                          (void *)&chu))
+    return chu;
+
+  return NULL;
+}