ROBODoc documented lib/silcrypt/silccipher.h. Patch by Toni
[silc.git] / lib / silcclient / client_prvmsg.c
index d9f2e65d4d02e8bc5ad09b91e92833e382ce00a8..7c251d817a5b573417b101a6bc9654d436c7b8fe 100644 (file)
@@ -21,7 +21,8 @@
 /* This file includes the private message sending and receiving routines
    and private message key handling routines. */
 
-#include "clientlibincludes.h"
+#include "silcincludes.h"
+#include "silcclient.h"
 #include "client_internal.h"
 
 /* Sends private message to remote client. If private message key has
@@ -37,12 +38,13 @@ void silc_client_send_private_message(SilcClient client,
                                      SilcClientEntry client_entry,
                                      SilcMessageFlags flags,
                                      unsigned char *data, 
-                                     uint32 data_len, 
+                                     SilcUInt32 data_len, 
                                      int force_send)
 {
   SilcSocketConnection sock = conn->sock;
   SilcBuffer buffer;
   SilcPacketContext packetdata;
+  const SilcBufferStruct packet;
   SilcCipher cipher;
   SilcHmac hmac;
   int block_len;
@@ -52,7 +54,8 @@ void silc_client_send_private_message(SilcClient client,
   /* Encode private message payload */
   buffer = silc_private_message_payload_encode(flags,
                                               data_len, data,
-                                              client_entry->send_key);
+                                              client_entry->send_key,
+                                              client->rng);
 
   /* If we don't have private message specific key then private messages
      are just as any normal packet thus call normal packet sending.  If
@@ -68,11 +71,13 @@ void silc_client_send_private_message(SilcClient client,
   /* We have private message specific key */
 
   /* Get data used in the encryption */
-  cipher = client_entry->send_key;
+  cipher = conn->send_key;
   hmac = conn->hmac_send;
   block_len = silc_cipher_get_block_len(cipher);
 
   /* Set the packet context pointers. */
+  data = buffer->data;
+  data_len = buffer->len;
   packetdata.flags = SILC_PACKET_FLAG_PRIVMSG_KEY;
   packetdata.type = SILC_PACKET_PRIVATE_MESSAGE;
   packetdata.src_id = conn->local_id_data;
@@ -81,37 +86,30 @@ void silc_client_send_private_message(SilcClient client,
   packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
   packetdata.dst_id_len = silc_id_get_len(client_entry->id, SILC_ID_CLIENT);
   packetdata.dst_id_type = SILC_ID_CLIENT;
-  packetdata.truelen = buffer->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), block_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,
-                          buffer->len);
-  
-  packetdata.buffer = sock->outbuf;
-
-  /* Put the actual encrypted message payload data into the buffer. */
-  silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
-
   /* Create the outgoing packet */
-  silc_packet_assemble(&packetdata, cipher);
+  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. */
-  cipher = conn->send_key;
   silc_packet_encrypt(cipher, hmac, conn->psn_send++,
-                     sock->outbuf, SILC_PACKET_HEADER_LEN + 
+                     (SilcBuffer)&packet, SILC_PACKET_HEADER_LEN + 
                      packetdata.src_id_len + packetdata.dst_id_len +
                      packetdata.padlen);
 
-  SILC_LOG_HEXDUMP(("Private message packet, len %d", sock->outbuf->len),
-                  sock->outbuf->data, sock->outbuf->len);
+  SILC_LOG_HEXDUMP(("Private message packet, len %d", packet.len),
+                  packet.data, packet.len);
 
   /* Now actually send the packet */
   silc_client_packet_send_real(client, sock, force_send);
@@ -124,7 +122,7 @@ void silc_client_send_private_message(SilcClient client,
 static void silc_client_private_message_cb(SilcClient client,
                                           SilcClientConnection conn,
                                           SilcClientEntry *clients,
-                                          uint32 clients_count,
+                                          SilcUInt32 clients_count,
                                           void *context)
 {
   SilcPacketContext *packet = (SilcPacketContext *)context;
@@ -147,10 +145,12 @@ void silc_client_private_message(SilcClient client,
 {
   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
   SilcPrivateMessagePayload payload = NULL;
-  SilcIDCacheEntry id_cache;
   SilcClientID *remote_id = NULL;
   SilcClientEntry remote_client;
   SilcMessageFlags flags;
+  unsigned char *message;
+  SilcUInt32 message_len;
+  SilcCipher cipher = NULL;
 
   if (packet->src_id_type != SILC_ID_CLIENT)
     goto out;
@@ -161,22 +161,33 @@ void silc_client_private_message(SilcClient client,
     goto out;
 
   /* Check whether we know this client already */
-  if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)remote_id, 
-                                      NULL, NULL, 
-                                      silc_hash_client_id_compare, NULL,
-                                      &id_cache)) {
+  remote_client = silc_client_get_client_by_id(client, conn, remote_id);
+  if (!remote_client || !remote_client->nickname) {
+    if (remote_client) {
+      if (remote_client->status & SILC_CLIENT_STATUS_RESOLVING) {
+       remote_client->status &= ~SILC_CLIENT_STATUS_RESOLVING;
+       goto out;
+      }
+      remote_client->status |= SILC_CLIENT_STATUS_RESOLVING;
+      remote_client->resolve_cmd_ident = conn->cmd_ident + 1;
+    }
+
     /* Resolve the client info */
-    silc_client_get_client_by_id_resolve(client, conn, remote_id,
+    silc_client_get_client_by_id_resolve(client, conn, remote_id, NULL,
                                         silc_client_private_message_cb,
                                         silc_packet_context_dup(packet));
     return;
   }
 
-  remote_client = (SilcClientEntry)id_cache->context;
+  cipher = remote_client->receive_key;
+  if (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY && !cipher) {
+    silc_free(remote_id);
+    return;
+  }
 
   /* Parse the payload and decrypt it also if private message key is set */
-  payload = silc_private_message_payload_parse(packet->buffer,
-                                              remote_client->receive_key);
+  payload = silc_private_message_payload_parse(packet->buffer->data,
+                                              packet->buffer->len, cipher);
   if (!payload) {
     silc_free(remote_id);
     return;
@@ -185,9 +196,9 @@ void silc_client_private_message(SilcClient client,
   flags = silc_private_message_get_flags(payload);
 
   /* Pass the private message to application */
-  client->ops->private_message(client, conn, remote_client, flags,
-                              silc_private_message_get_message(payload, 
-                                                               NULL));
+  message = silc_private_message_get_message(payload, &message_len);
+  client->internal->ops->private_message(client, conn, remote_client, flags,
+                                        message, message_len);
 
   /* See if we are away (gone). If we are away we will reply to the
      sender with the set away message. */
@@ -207,8 +218,7 @@ void silc_client_private_message(SilcClient client,
  out:
   if (payload)
     silc_private_message_payload_free(payload);
-  if (remote_id)
-    silc_free(remote_id);
+  silc_free(remote_id);
 }
 
 /* Function that actually employes the received private message key */
@@ -216,12 +226,12 @@ void silc_client_private_message(SilcClient client,
 static void silc_client_private_message_key_cb(SilcClient client,
                                               SilcClientConnection conn,
                                               SilcClientEntry *clients,
-                                              uint32 clients_count,
+                                              SilcUInt32 clients_count,
                                               void *context)
 {
   SilcPacketContext *packet = (SilcPacketContext *)context;
   unsigned char *key;
-  uint16 key_len;
+  SilcUInt16 key_len;
   unsigned char *cipher;
   int ret;
 
@@ -245,14 +255,15 @@ static void silc_client_private_message_key_cb(SilcClient client,
     goto out;
 
   /* Print some info for application */
-  client->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT, 
-                  "Received private message key from %s%s%s %s%s%s", 
-                  clients[0]->nickname,
-                  clients[0]->server ? "@" : "",
-                  clients[0]->server ? clients[0]->server : "",
-                  clients[0]->username ? "(" : "",
-                  clients[0]->username ? clients[0]->username : "",
-                  clients[0]->username ? ")" : "");
+  client->internal->ops->say(
+                    client, conn, SILC_CLIENT_MESSAGE_AUDIT, 
+                    "Received private message key from %s%s%s %s%s%s", 
+                    clients[0]->nickname,
+                    clients[0]->server ? "@" : "",
+                    clients[0]->server ? clients[0]->server : "",
+                    clients[0]->username ? "(" : "",
+                    clients[0]->username ? clients[0]->username : "",
+                    clients[0]->username ? ")" : "");
 
  out:
   silc_packet_context_free(packet);
@@ -276,6 +287,7 @@ void silc_client_private_message_key(SilcClient client,
     return;
 
   silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
+                                      NULL,
                                       silc_client_private_message_key_cb,
                                       silc_packet_context_dup(packet));
   silc_free(remote_id);
@@ -307,12 +319,12 @@ int silc_client_add_private_message_key(SilcClient client,
                                        SilcClientEntry client_entry,
                                        char *cipher,
                                        unsigned char *key,
-                                       uint32 key_len,
+                                       SilcUInt32 key_len,
                                        bool generate_key,
                                        bool responder)
 {
   unsigned char private_key[32];
-  uint32 len;
+  SilcUInt32 len;
   int i;
   SilcSKEKeyMaterial *keymat;
 
@@ -339,8 +351,7 @@ int silc_client_add_private_message_key(SilcClient client,
   }
 
   /* Save the key */
-  client_entry->key = silc_calloc(key_len, sizeof(*client_entry->key));
-  memcpy(client_entry->key, key, key_len);
+  client_entry->key = silc_memdup(key, key_len);
   client_entry->key_len = key_len;
 
   /* Produce the key material as the protocol defines */
@@ -445,13 +456,15 @@ int silc_client_send_private_message_key(SilcClient client,
   SilcSocketConnection sock = conn->sock;
   SilcBuffer buffer;
   int cipher_len;
+  const char *cipher;
 
   if (!client_entry->send_key || !client_entry->key)
     return FALSE;
 
   SILC_LOG_DEBUG(("Sending private message key"));
 
-  cipher_len = strlen(client_entry->send_key->cipher->name);
+  cipher = silc_cipher_get_name(client_entry->send_key);
+  cipher_len = strlen(cipher);
 
   /* Create private message key payload */
   buffer = silc_buffer_alloc(2 + client_entry->key_len);
@@ -461,7 +474,7 @@ int silc_client_send_private_message_key(SilcClient client,
                     SILC_STR_UI_XNSTRING(client_entry->key, 
                                          client_entry->key_len),
                     SILC_STR_UI_SHORT(cipher_len),
-                    SILC_STR_UI_XNSTRING(client_entry->send_key->cipher->name,
+                    SILC_STR_UI_XNSTRING(cipher,
                                          cipher_len),
                     SILC_STR_END);
 
@@ -513,10 +526,10 @@ int silc_client_del_private_message_key(SilcClient client,
 SilcPrivateMessageKeys
 silc_client_list_private_message_keys(SilcClient client,
                                      SilcClientConnection conn,
-                                     uint32 *key_count)
+                                     SilcUInt32 *key_count)
 {
   SilcPrivateMessageKeys keys;
-  uint32 count = 0;
+  SilcUInt32 count = 0;
   SilcIDCacheEntry id_cache;
   SilcIDCacheList list;
   SilcClientEntry entry;
@@ -537,7 +550,7 @@ silc_client_list_private_message_keys(SilcClient client,
 
     if (entry->send_key) {
       keys[count].client_entry = entry;
-      keys[count].cipher = entry->send_key->cipher->name;
+      keys[count].cipher = (char *)silc_cipher_get_name(entry->send_key);
       keys[count].key = entry->generated == FALSE ? entry->key : NULL;
       keys[count].key_len = entry->generated == FALSE ? entry->key_len : 0;
       count++;
@@ -557,7 +570,7 @@ silc_client_list_private_message_keys(SilcClient client,
    silc_client_list_private_message_keys. */
 
 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
-                                          uint32 key_count)
+                                          SilcUInt32 key_count)
 {
   silc_free(keys);
 }