updates.
[silc.git] / lib / silcclient / client_prvmsg.c
index 98ccd69954258a499fbbfbfacd76b6d4c066dafc..d0695efdf7d4d40af6caec0f16281a6c08be4035 100644 (file)
@@ -126,6 +126,11 @@ static void silc_client_private_message_cb(SilcClient client,
 {
   SilcPacketContext *packet = (SilcPacketContext *)context;
 
+  if (!clients) {
+    silc_packet_context_free(packet);
+    return;
+  }
+
   silc_client_private_message(client, conn->sock, packet);
   silc_packet_context_free(packet);
 }
@@ -142,6 +147,7 @@ void silc_client_private_message(SilcClient client,
   SilcIDCacheEntry id_cache;
   SilcClientID *remote_id = NULL;
   SilcClientEntry remote_client;
+  SilcMessageFlags flags;
 
   if (packet->src_id_type != SILC_ID_CLIENT)
     goto out;
@@ -167,28 +173,30 @@ void silc_client_private_message(SilcClient client,
 
   /* Parse the payload and decrypt it also if private message key is set */
   payload = silc_private_message_payload_parse(packet->buffer,
-                                              remote_client->send_key);
+                                              remote_client->receive_key);
   if (!payload) {
     silc_free(remote_id);
     return;
   }
 
+  flags = silc_private_message_get_flags(payload);
+
   /* Pass the private message to application */
-  client->ops->private_message(client, conn, remote_client,
-                              silc_private_message_get_flags(payload),
+  client->ops->private_message(client, conn, remote_client, flags,
                               silc_private_message_get_message(payload, 
                                                                NULL));
 
   /* See if we are away (gone). If we are away we will reply to the
      sender with the set away message. */
-  if (conn->away && conn->away->away) {
+  if (conn->away && conn->away->away && !(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
     /* If it's me, ignore */
     if (SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
       goto out;
 
     /* Send the away message */
     silc_client_send_private_message(client, conn, remote_client,
-                                    SILC_MESSAGE_FLAG_AUTOREPLY,
+                                    SILC_MESSAGE_FLAG_AUTOREPLY |
+                                    SILC_MESSAGE_FLAG_NOREPLY,
                                     conn->away->away,
                                     strlen(conn->away->away), TRUE);
   }
@@ -230,11 +238,11 @@ static void silc_client_private_message_key_cb(SilcClient client,
 
   /* Now take the key in use */
   if (!silc_client_add_private_message_key(client, conn, clients[0],
-                                          cipher, key, key_len, FALSE))
+                                          cipher, key, key_len, FALSE, TRUE))
     goto out;
 
   /* Print some info for application */
-  client->ops->say(client, conn, 
+  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 ? "@" : "",
@@ -279,6 +287,11 @@ void silc_client_private_message_key(SilcClient client,
    requirements of the SILC protocol are met. The API, however, allows
    to allocate any cipher.
 
+   If `responder' is TRUE then the sending and receiving keys will be
+   set according the client being the receiver of the private key.  If
+   FALSE the client is being the sender (or negotiator) of the private
+   key.
+
    It is not necessary to set key for normal private message usage. If the
    key is not set then the private messages are encrypted using normal
    session keys. Setting the private key, however, increases the security. 
@@ -292,7 +305,8 @@ int silc_client_add_private_message_key(SilcClient client,
                                        char *cipher,
                                        unsigned char *key,
                                        uint32 key_len,
-                                       int generate_key)
+                                       bool generate_key,
+                                       bool responder)
 {
   unsigned char private_key[32];
   uint32 len;
@@ -338,12 +352,21 @@ int silc_client_add_private_message_key(SilcClient client,
   silc_cipher_alloc(cipher, &client_entry->receive_key);
 
   /* Set the keys */
-  silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key,
-                     keymat->enc_key_len);
-  silc_cipher_set_iv(client_entry->send_key, keymat->send_iv);
-  silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key,
-                     keymat->enc_key_len);
-  silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv);
+  if (responder == TRUE) {
+    silc_cipher_set_key(client_entry->send_key, keymat->receive_enc_key,
+                       keymat->enc_key_len);
+    silc_cipher_set_iv(client_entry->send_key, keymat->receive_iv);
+    silc_cipher_set_key(client_entry->receive_key, keymat->send_enc_key,
+                       keymat->enc_key_len);
+    silc_cipher_set_iv(client_entry->receive_key, keymat->send_iv);
+  } else {
+    silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key,
+                       keymat->enc_key_len);
+    silc_cipher_set_iv(client_entry->send_key, keymat->send_iv);
+    silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key,
+                       keymat->enc_key_len);
+    silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv);
+  }
 
   /* Free the key material */
   silc_ske_free_key_material(keymat);
@@ -361,7 +384,8 @@ int silc_client_add_private_message_key_ske(SilcClient client,
                                            SilcClientConnection conn,
                                            SilcClientEntry client_entry,
                                            char *cipher,
-                                           SilcSKEKeyMaterial *key)
+                                           SilcSKEKeyMaterial *key,
+                                           bool responder)
 {
   assert(client_entry);
 
@@ -381,12 +405,21 @@ int silc_client_add_private_message_key_ske(SilcClient client,
   silc_cipher_alloc(cipher, &client_entry->receive_key);
 
   /* Set the keys */
-  silc_cipher_set_key(client_entry->send_key, key->send_enc_key,
-                     key->enc_key_len);
-  silc_cipher_set_iv(client_entry->send_key, key->send_iv);
-  silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key,
-                     key->enc_key_len);
-  silc_cipher_set_iv(client_entry->receive_key, key->receive_iv);
+  if (responder == TRUE) {
+    silc_cipher_set_key(client_entry->send_key, key->receive_enc_key,
+                       key->enc_key_len);
+    silc_cipher_set_iv(client_entry->send_key, key->receive_iv);
+    silc_cipher_set_key(client_entry->receive_key, key->send_enc_key,
+                       key->enc_key_len);
+    silc_cipher_set_iv(client_entry->receive_key, key->send_iv);
+  } else {
+    silc_cipher_set_key(client_entry->send_key, key->send_enc_key,
+                       key->enc_key_len);
+    silc_cipher_set_iv(client_entry->send_key, key->send_iv);
+    silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key,
+                       key->enc_key_len);
+    silc_cipher_set_iv(client_entry->receive_key, key->receive_iv);
+  }
 
   return TRUE;
 }