+/*
+
+ silcprivate.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2001 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.
+
+ 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
+ GNU General Public License for more details.
+
+*/
+/* Includes the Private Message Payload implementation */
+/* $Id$ */
+
+#include "silcincludes.h"
+#include "silcprivate.h"
+
+/******************************************************************************
+
+ Private Message Payload
+
+******************************************************************************/
+
+/* Private Message Payload structure. Contents of this structure is parsed
+ from SILC packets. */
+struct SilcPrivateMessagePayloadStruct {
+ unsigned short nickname_len;
+ unsigned char *nickname;
+ unsigned short flags;
+ unsigned short message_len;
+ unsigned char *message;
+};
+
+/* Parses private message payload returning new private mesage payload
+ structure. This also decrypts the message if the `cipher' is provided. */
+
+SilcPrivateMessagePayload
+silc_private_message_payload_parse(SilcBuffer buffer, SilcCipher cipher)
+{
+ SilcPrivateMessagePayload new;
+ int ret;
+
+ SILC_LOG_DEBUG(("Parsing private message payload"));
+
+ /* Decrypt the payload */
+ if (cipher)
+ silc_cipher_decrypt(cipher, buffer->data, buffer->data,
+ buffer->len, cipher->iv);
+
+ new = silc_calloc(1, sizeof(*new));
+
+ /* Parse the Private Message Payload. Ignore the padding. */
+ ret = silc_buffer_unformat(buffer,
+ SILC_STR_UI16_NSTRING_ALLOC(&new->nickname,
+ &new->nickname_len),
+ SILC_STR_UI_SHORT(&new->flags),
+ SILC_STR_UI16_NSTRING_ALLOC(&new->message,
+ &new->message_len),
+ SILC_STR_END);
+ if (ret == -1)
+ goto err;
+
+ if ((new->message_len < 1 || new->message_len > buffer->len) ||
+ (new->nickname_len < 1 || new->nickname_len > buffer->len)) {
+ SILC_LOG_ERROR(("Incorrect private message payload in packet, "
+ "packet dropped"));
+ goto err;
+ }
+
+ return new;
+
+ err:
+ silc_private_message_payload_free(new);
+ return NULL;
+}
+
+/* Encodes private message payload into a buffer and returns it. If
+ the cipher is provided the packet is also encrypted here. It is provided
+ if the private message private keys are used. */
+
+SilcBuffer silc_private_message_payload_encode(unsigned int nickname_len,
+ unsigned char *nickname,
+ unsigned short flags,
+ unsigned short data_len,
+ unsigned char *data,
+ SilcCipher cipher)
+{
+ int i;
+ SilcBuffer buffer;
+ unsigned int len, pad_len = 0;
+ unsigned char pad[SILC_PACKET_MAX_PADLEN];
+
+ SILC_LOG_DEBUG(("Encoding private message payload"));
+
+ len = 2 + nickname_len + 4 + data_len;
+
+ if (cipher) {
+ /* Calculate length of padding. */
+ pad_len = SILC_PACKET_PADLEN((len + 2));
+ len += pad_len;
+
+ /* Generate padding */
+ for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte();
+ }
+
+ /* Allocate private message payload buffer */
+ buffer = silc_buffer_alloc(len);
+
+ /* Encode the Channel Message Payload */
+ silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
+ silc_buffer_format(buffer,
+ SILC_STR_UI_SHORT(nickname_len),
+ SILC_STR_UI_XNSTRING(nickname, nickname_len),
+ SILC_STR_UI_SHORT(flags),
+ SILC_STR_UI_SHORT(data_len),
+ SILC_STR_UI_XNSTRING(data, data_len),
+ SILC_STR_UI_XNSTRING(pad, pad_len),
+ SILC_STR_END);
+
+ if (cipher) {
+ /* Encrypt payload of the packet. */
+ silc_cipher_encrypt(cipher, buffer->data, buffer->data,
+ buffer->len, cipher->iv);
+ memset(pad, 0, sizeof(pad));
+ }
+
+ return buffer;
+}
+
+/* Free's Private Message Payload */
+
+void silc_private_message_payload_free(SilcPrivateMessagePayload payload)
+{
+ silc_free(payload->nickname);
+ if (payload->message) {
+ memset(payload->message, 0, payload->message_len);
+ silc_free(payload->message);
+ }
+ silc_free(payload);
+}
+
+/* Return nickname */
+
+unsigned char *
+silc_private_message_get_nickname(SilcPrivateMessagePayload payload,
+ unsigned int *nickname_len)
+{
+ if (nickname_len)
+ *nickname_len = payload->nickname_len;
+
+ return payload->nickname;
+}
+
+/* Return message */
+
+unsigned char *
+silc_private_message_get_message(SilcPrivateMessagePayload payload,
+ unsigned int *message_len)
+{
+ if (message_len)
+ *message_len = payload->message_len;
+
+ return payload->message;
+}
+
+/* Return flags */
+
+unsigned short
+silc_private_message_get_flags(SilcPrivateMessagePayload payload)
+{
+ return payload->flags;
+}