Merged from silc_1_0_branch.
[silc.git] / lib / silcclient / client_channel.c
index 376572ca05725da826c91c65686dbca4c18d315d..68983d59c6f6692dc5adf3837deca7c95632cd1f 100644 (file)
@@ -1,16 +1,15 @@
 /*
 
-  client_channel.c
+  client_channel.c 
 
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+  Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2001 Pekka Riikonen
+  Copyright (C) 1997 - 2002 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-  
+  the Free Software Foundation; version 2 of the License.
+
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
@@ -22,7 +21,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,20 +38,39 @@ void silc_client_send_channel_message(SilcClient client,
                                      SilcChannelPrivateKey key,
                                      SilcMessageFlags flags,
                                      unsigned char *data, 
-                                     uint32 data_len, 
-                                     int force_send)
+                                     SilcUInt32 data_len, 
+                                     bool force_send)
 {
-  int i;
-  SilcSocketConnection sock = conn->sock;
+  SilcSocketConnection sock;
   SilcBuffer payload;
   SilcPacketContext packetdata;
+  const SilcBufferStruct packet;
   SilcCipher cipher;
   SilcHmac hmac;
   unsigned char *id_string;
-  uint32 iv_len;
+  int block_len;
+  SilcChannelUser chu;
 
+  assert(client && conn && channel);
+  sock = conn->sock;
   SILC_LOG_DEBUG(("Sending packet to channel"));
 
+  chu = silc_client_on_channel(channel, conn->local_entry);
+  if (!chu) {
+    SILC_LOG_ERROR(("Cannot send message to channel we are not joined"));
+    return;
+  }
+
+  /* Check if it is allowed to send messages to this channel by us. */
+  if (channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS && !chu->mode)
+    return;
+  if (channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS && 
+      chu->mode & SILC_CHANNEL_UMODE_CHANOP &&
+      !(chu->mode & SILC_CHANNEL_UMODE_CHANFO))
+    return;
+  if (chu->mode & SILC_CHANNEL_UMODE_QUIET)
+    return;
+
   /* Take the key to be used */
   if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
     if (key) {
@@ -86,26 +105,23 @@ void silc_client_send_channel_message(SilcClient client,
   if (!cipher || !hmac)
     return;
 
-  /* Generate IV */
-  iv_len = silc_cipher_get_block_len(cipher);
-  if (channel->iv[0] == '\0')
-    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);
+  block_len = silc_cipher_get_block_len(cipher);
 
-  /* Encode the channel payload. This also encrypts the message payload. */
-  payload = silc_channel_message_payload_encode(flags, data_len, data, iv_len, 
-                                               channel->iv, cipher, hmac);
+  /* Encode the message payload. This also encrypts the message payload. */
+  payload = silc_message_payload_encode(flags, data, data_len, TRUE, FALSE,
+                                       cipher, hmac, client->rng, NULL,
+                                       client->private_key, client->sha1hash);
 
   /* Get data used in packet header encryption, keys and stuff. */
-  cipher = conn->send_key;
-  hmac = conn->hmac_send;
+  cipher = conn->internal->send_key;
+  hmac = conn->internal->hmac_send;
   id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
 
   /* Set the packet context pointers. The destination ID is always
      the Channel ID of the channel. Server and router will handle the
      distribution of the packet. */
+  data = payload->data;
+  data_len = payload->len;
   packetdata.flags = 0;
   packetdata.type = SILC_PACKET_CHANNEL_MESSAGE;
   packetdata.src_id = conn->local_id_data;
@@ -114,59 +130,96 @@ void silc_client_send_channel_message(SilcClient client,
   packetdata.dst_id = id_string;
   packetdata.dst_id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
   packetdata.dst_id_type = SILC_ID_CHANNEL;
-  packetdata.truelen = payload->len + SILC_PACKET_HEADER_LEN + 
+  data_len = SILC_PACKET_DATALEN(data_len, SILC_PACKET_HEADER_LEN +
+                                packetdata.src_id_len +
+                                packetdata.dst_id_len);
+  packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
     packetdata.src_id_len + packetdata.dst_id_len;
-  packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
-                                         packetdata.src_id_len +
-                                         packetdata.dst_id_len));
-
-  /* Prepare outgoing data buffer for packet sending */
-  silc_packet_send_prepare(sock, 
-                          SILC_PACKET_HEADER_LEN +
-                          packetdata.src_id_len + 
-                          packetdata.dst_id_len,
-                          packetdata.padlen,
-                          payload->len);
-
-  packetdata.buffer = sock->outbuf;
-
-  /* Put the channel message payload to the outgoing data buffer */
-  silc_buffer_put(sock->outbuf, payload->data, payload->len);
+  SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
+                     packetdata.src_id_len +
+                     packetdata.dst_id_len), block_len, packetdata.padlen);
 
   /* Create the outgoing packet */
-  silc_packet_assemble(&packetdata);
+  if (!silc_packet_assemble(&packetdata, client->rng, cipher, hmac, sock,
+                            data, data_len, (const SilcBuffer)&packet)) {
+    SILC_LOG_ERROR(("Error assembling packet"));
+    goto out;
+  }
 
   /* Encrypt the header and padding of the packet. This is encrypted 
      with normal session key shared with our server. */
-  silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN + 
+  silc_packet_encrypt(cipher, hmac, conn->internal->psn_send++,
+                     (SilcBuffer)&packet, SILC_PACKET_HEADER_LEN + 
                      packetdata.src_id_len + packetdata.dst_id_len +
                      packetdata.padlen);
 
-  SILC_LOG_HEXDUMP(("Packet to channel, len %d", sock->outbuf->len),
-                  sock->outbuf->data, sock->outbuf->len);
+  SILC_LOG_HEXDUMP(("Packet to channel, len %d", packet.len),
+                   packet.data, packet.len);
 
   /* Now actually send the packet */
-  silc_client_packet_send_real(client, sock, force_send, FALSE);
+  silc_client_packet_send_real(client, sock, force_send);
+
+  /* Check for mandatory rekey */
+  if (conn->internal->psn_send == SILC_CLIENT_REKEY_THRESHOLD)
+    silc_schedule_task_add(client->schedule, sock->sock,
+                          silc_client_rekey_callback, sock, 0, 1,
+                          SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+
+ out:
   silc_buffer_free(payload);
   silc_free(id_string);
 }
 
+typedef struct {
+  SilcMessagePayload 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;
+    SilcUInt32 message_len;
+
+    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_message_get_data(res->payload, &message_len);
+    
+    /* Pass the message to application */
+    client->internal->ops->channel_message(
+                           client, conn, clients[0], channel, res->payload,
+                           silc_message_get_flags(res->payload),
+                           message, message_len);
+  }
 
-  if (clients)
-    silc_client_channel_message(client, conn->sock, packet);
-  silc_packet_context_free(packet);
+ out:
+  silc_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
    decrypts the channel message with channel specific key and parses the
-   channel payload. Finally it displays the message on the screen. */
+   message payload. Finally it displays the message on the screen. */
 
 void silc_client_channel_message(SilcClient client, 
                                 SilcSocketConnection sock, 
@@ -174,14 +227,13 @@ void silc_client_channel_message(SilcClient client,
 {
   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
   SilcBuffer buffer = packet->buffer;
-  SilcChannelMessagePayload payload = NULL;
+  SilcMessagePayload 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;
+  SilcUInt32 message_len;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -198,40 +250,44 @@ 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,
-                                                channel->hmac);
+    payload = silc_message_payload_parse(buffer->data, buffer->len, FALSE,
+                                        FALSE, 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, 
-                                                  channel->old_channel_key,
-                                                  channel->old_hmac);
-      if (!payload)
+      payload = silc_message_payload_parse(buffer->data, buffer->len,
+                                          FALSE, FALSE,
+                                          channel->old_channel_key,
+                                          channel->old_hmac);
+      if (!payload) {
        goto out;
+      }
     }
   } else if (channel->private_keys) {
     SilcChannelPrivateKey entry;
 
     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,
-                                                  entry->hmac);
+      /* Parse the message payload. This also decrypts the payload */
+      payload = silc_message_payload_parse(buffer->data, buffer->len, 
+                                          FALSE, FALSE,
+                                          entry->cipher, entry->hmac);
       if (payload)
        break;
     }
@@ -242,36 +298,34 @@ 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 ||
+      !silc_client_on_channel(channel, client_entry)) {
     /* Resolve the client info */
-    silc_client_get_client_by_id_resolve(client, conn, client_id,
+    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, NULL,
                                         silc_client_channel_message_cb,
-                                        silc_packet_context_dup(packet));
+                                        res);
+    payload = NULL;
+    id = NULL;
     goto out;
   }
 
-  message = silc_channel_message_get_data(payload, NULL);
+  message = silc_message_get_data(payload, &message_len);
 
   /* 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, payload,
+                            silc_message_get_flags(payload),
+                            message, message_len);
 
  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);
+    silc_message_payload_free(payload);
 }
 
 /* Timeout callback that is called after a short period of time after the
@@ -295,17 +349,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;
 
@@ -323,15 +378,13 @@ 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 ? channel->hmac->hmac->name : SILC_DEFAULT_HMAC;
+  hmac = (channel->hmac ? (char *)silc_hmac_get_name(channel->hmac) : 
+         SILC_DEFAULT_HMAC);
 
   /* Save the old key for a short period of time so that we can decrypt
      channel message even after the rekey if some client would be sending
@@ -341,11 +394,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);
 
@@ -356,11 +409,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;
@@ -371,8 +425,9 @@ void silc_client_save_channel_key(SilcClientConnection conn,
 
   /* Generate HMAC key from the channel key data and set it */
   silc_hmac_alloc(hmac, NULL, &channel->hmac);
-  silc_hash_make(channel->hmac->hash, key, tmp_len, hash);
-  silc_hmac_set_key(channel->hmac, hash, silc_hash_len(channel->hmac->hash));
+  silc_hash_make(silc_hmac_get_hash(channel->hmac), key, tmp_len, hash);
+  silc_hmac_set_key(channel->hmac, hash, 
+                   silc_hash_len(silc_hmac_get_hash(channel->hmac)));
   memset(hash, 0, sizeof(hash));
 
  out:
@@ -393,7 +448,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
@@ -425,18 +480,21 @@ void silc_client_receive_channel_key(SilcClient client,
    currently it is not expected that the SKE key material would be used
    as channel private key. However, this API allows it. */
 
-int silc_client_add_channel_private_key(SilcClient client,
+bool silc_client_add_channel_private_key(SilcClient client,
                                        SilcClientConnection conn,
                                        SilcChannelEntry channel,
+                                       const char *name,
                                        char *cipher,
                                        char *hmac,
                                        unsigned char *key,
-                                       uint32 key_len)
+                                       SilcUInt32 key_len)
 {
   SilcChannelPrivateKey entry;
   unsigned char hash[32];
   SilcSKEKeyMaterial *keymat;
 
+  assert(client && channel);
+
   if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
     return FALSE;
 
@@ -454,7 +512,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->sha1hash, keymat) 
       != SILC_SKE_STATUS_OK)
     return FALSE;
 
@@ -477,8 +535,8 @@ 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->name = name ? strdup(name) : NULL;
+  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*/
@@ -487,8 +545,10 @@ int silc_client_add_channel_private_key(SilcClient client,
 
   /* Generate HMAC key from the channel key data and set it */
   silc_hmac_alloc(hmac, NULL, &entry->hmac);
-  silc_hash_make(entry->hmac->hash, entry->key, entry->key_len, hash);
-  silc_hmac_set_key(entry->hmac, hash, silc_hash_len(entry->hmac->hash));
+  silc_hash_make(silc_hmac_get_hash(entry->hmac), entry->key, 
+                entry->key_len, hash);
+  silc_hmac_set_key(entry->hmac, hash, 
+                   silc_hash_len(silc_hmac_get_hash(entry->hmac)));
   memset(hash, 0, sizeof(hash));
 
   /* Add to the private keys list */
@@ -507,12 +567,14 @@ int silc_client_add_channel_private_key(SilcClient client,
    after calling this to protect the channel messages. Returns FALSE on
    on error, TRUE otherwise. */
 
-int silc_client_del_channel_private_keys(SilcClient client,
+bool silc_client_del_channel_private_keys(SilcClient client,
                                         SilcClientConnection conn,
                                         SilcChannelEntry channel)
 {
   SilcChannelPrivateKey entry;
 
+  assert(client && channel);
+
   if (!channel->private_keys)
     return FALSE;
 
@@ -521,6 +583,7 @@ int silc_client_del_channel_private_keys(SilcClient client,
     silc_dlist_del(channel->private_keys, entry);
     memset(entry->key, 0, entry->key_len);
     silc_free(entry->key);
+    silc_free(entry->name);
     silc_cipher_free(entry->cipher);
     silc_hmac_free(entry->hmac);
     silc_free(entry);
@@ -540,13 +603,15 @@ int silc_client_del_channel_private_keys(SilcClient client,
    old channel key is used hereafter to protect the channel messages. This
    returns FALSE on error, TRUE otherwise. */
 
-int silc_client_del_channel_private_key(SilcClient client,
+bool silc_client_del_channel_private_key(SilcClient client,
                                        SilcClientConnection conn,
                                        SilcChannelEntry channel,
                                        SilcChannelPrivateKey key)
 {
   SilcChannelPrivateKey entry;
 
+  assert(client && channel);
+
   if (!channel->private_keys)
     return FALSE;
 
@@ -559,6 +624,7 @@ int silc_client_del_channel_private_key(SilcClient client,
       silc_dlist_del(channel->private_keys, entry);
       memset(entry->key, 0, entry->key_len);
       silc_free(entry->key);
+      silc_free(entry->name);
       silc_cipher_free(entry->cipher);
       silc_hmac_free(entry->hmac);
       silc_free(entry);
@@ -585,10 +651,12 @@ 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;
+
+  assert(client && channel);
 
   if (!channel->private_keys)
     return NULL;
@@ -609,7 +677,36 @@ 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);
 }
+
+/* Sets the `key' to be used as current channel private key on the
+   `channel'.  Packet sent after calling this function will be secured
+   with `key'. */
+
+void silc_client_current_channel_private_key(SilcClient client,
+                                            SilcClientConnection conn,
+                                            SilcChannelEntry channel,
+                                            SilcChannelPrivateKey key)
+{
+  assert(client && channel);
+  channel->curr_key = key;
+}
+
+/* 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;
+}