X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=blobdiff_plain;f=lib%2Fsilcclient%2Fclient_prvmsg.c;h=36d7bbe43a7eaffd76fe308eb7980b50da6a9867;hp=56748bf477e99a66b96e17168e448f8d231e528d;hb=382d15d447b7a95390decfa783836ae4fe255b3d;hpb=a4bea30553d9f9ce717f2c658febcd43133b9f94 diff --git a/lib/silcclient/client_prvmsg.c b/lib/silcclient/client_prvmsg.c index 56748bf4..36d7bbe4 100644 --- a/lib/silcclient/client_prvmsg.c +++ b/lib/silcclient/client_prvmsg.c @@ -1,16 +1,15 @@ /* - client_prvmsg.c + client_prvmsg.c - Author: Pekka Riikonen + Author: Pekka Riikonen - 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 @@ -21,7 +20,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 @@ -35,23 +35,31 @@ void silc_client_send_private_message(SilcClient client, SilcClientConnection conn, SilcClientEntry client_entry, + SilcMessageFlags flags, unsigned char *data, - unsigned int data_len, - int force_send) + SilcUInt32 data_len, + bool force_send) { - SilcSocketConnection sock = conn->sock; + SilcSocketConnection sock; SilcBuffer buffer; SilcPacketContext packetdata; + const SilcBufferStruct packet; SilcCipher cipher; SilcHmac hmac; + int block_len; + assert(client && conn && client_entry); + sock = conn->sock; SILC_LOG_DEBUG(("Sending private message")); /* Encode private message payload */ - buffer = silc_private_message_payload_encode(strlen(conn->nickname), - conn->nickname, 0, - data_len, data, - client_entry->send_key); + buffer = silc_message_payload_encode(flags, data, data_len, + !client_entry->send_key ? FALSE : + !client_entry->generated, + TRUE, client_entry->send_key, + client_entry->hmac_send, + client->rng, NULL, client->private_key, + client->sha1hash); /* If we don't have private message specific key then private messages are just as any normal packet thus call normal packet sending. If @@ -67,51 +75,55 @@ 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; - hmac = conn->hmac; + cipher = conn->internal->send_key; + hmac = conn->internal->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; - packetdata.src_id_len = SILC_ID_CLIENT_LEN; + packetdata.src_id_len = silc_id_get_len(conn->local_id, SILC_ID_CLIENT); packetdata.src_id_type = SILC_ID_CLIENT; packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT); - packetdata.dst_id_len = SILC_ID_CLIENT_LEN; + 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)); - - /* 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); + 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. */ - cipher = conn->send_key; - 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(("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); + + /* 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); + silc_free(packetdata.dst_id); out: @@ -121,11 +133,16 @@ void silc_client_send_private_message(SilcClient client, static void silc_client_private_message_cb(SilcClient client, SilcClientConnection conn, SilcClientEntry *clients, - unsigned int clients_count, + SilcUInt32 clients_count, void *context) { 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); } @@ -138,10 +155,14 @@ void silc_client_private_message(SilcClient client, SilcPacketContext *packet) { SilcClientConnection conn = (SilcClientConnection)sock->user_data; - SilcPrivateMessagePayload payload = NULL; - SilcIDCacheEntry id_cache; + SilcMessagePayload payload = NULL; SilcClientID *remote_id = NULL; SilcClientEntry remote_client; + SilcMessageFlags flags; + unsigned char *message; + SilcUInt32 message_len; + SilcCipher cipher = NULL; + SilcHmac hmac = NULL; if (packet->src_id_type != SILC_ID_CLIENT) goto out; @@ -152,48 +173,68 @@ void silc_client_private_message(SilcClient client, goto out; /* Check whether we know this client already */ - if (!silc_idcache_find_by_id_one(conn->client_cache, remote_id, - SILC_ID_CLIENT, &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; + hmac = remote_client->hmac_receive; + if (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY && !cipher && !hmac) { + 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->send_key); + payload = silc_message_payload_parse(packet->buffer->data, + packet->buffer->len, TRUE, + !remote_client->generated, + cipher, hmac); if (!payload) { silc_free(remote_id); return; } + flags = silc_message_get_flags(payload); + /* Pass the private message to application */ - client->ops->private_message(client, conn, remote_client, - silc_private_message_get_message(payload, - NULL)); + message = silc_message_get_data(payload, &message_len); + client->internal->ops->private_message(client, conn, remote_client, payload, + 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. */ - if (conn->away && conn->away->away) { + if (conn->internal->away && conn->internal->away->away && + !(flags & SILC_MESSAGE_FLAG_NOREPLY)) { /* If it's me, ignore */ - if (!SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id)) + 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, - conn->away->away, - strlen(conn->away->away), TRUE); + SILC_MESSAGE_FLAG_AUTOREPLY | + SILC_MESSAGE_FLAG_NOREPLY, + conn->internal->away->away, + strlen(conn->internal->away->away), TRUE); } out: if (payload) - silc_private_message_payload_free(payload); - if (remote_id) - silc_free(remote_id); + silc_message_payload_free(payload); + silc_free(remote_id); } /* Function that actually employes the received private message key */ @@ -201,13 +242,13 @@ void silc_client_private_message(SilcClient client, static void silc_client_private_message_key_cb(SilcClient client, SilcClientConnection conn, SilcClientEntry *clients, - unsigned int clients_count, + SilcUInt32 clients_count, void *context) { SilcPacketContext *packet = (SilcPacketContext *)context; unsigned char *key; - unsigned short key_len; - unsigned char *cipher; + SilcUInt16 key_len; + unsigned char *cipher = NULL, *hmac = NULL; int ret; if (!clients) @@ -216,7 +257,8 @@ static void silc_client_private_message_key_cb(SilcClient client, /* Parse the private message key payload */ ret = silc_buffer_unformat(packet->buffer, SILC_STR_UI16_NSTRING(&key, &key_len), - SILC_STR_UI16_STRING(&cipher), + SILC_STR_UI16_STRING_ALLOC(&cipher), + SILC_STR_UI16_STRING_ALLOC(&hmac), SILC_STR_END); if (!ret) goto out; @@ -226,20 +268,24 @@ 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, hmac, key, key_len, + FALSE, TRUE)) goto out; /* Print some info for application */ - client->ops->say(client, conn, - "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_free(cipher); + silc_free(hmac); silc_packet_context_free(packet); } @@ -261,6 +307,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); @@ -271,9 +318,14 @@ void silc_client_private_message_key(SilcClient client, indicated by the `client_entry'. If the `key' is NULL and the boolean value `generate_key' is TRUE the library will generate random key. The `key' maybe for example pre-shared-key, passphrase or similar. - The `cipher' MAY be provided but SHOULD be NULL to assure that the - requirements of the SILC protocol are met. The API, however, allows - to allocate any cipher. + The `cipher' and `hmac' MAY be provided but SHOULD be NULL to assure + that the requirements of the SILC protocol are met. The API, however, + allows to allocate any cipher and HMAC. + + 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 @@ -282,64 +334,89 @@ void silc_client_private_message_key(SilcClient client, Returns FALSE if the key is already set for the `client_entry', TRUE otherwise. */ -int silc_client_add_private_message_key(SilcClient client, - SilcClientConnection conn, - SilcClientEntry client_entry, - char *cipher, - unsigned char *key, - unsigned int key_len, - int generate_key) +bool silc_client_add_private_message_key(SilcClient client, + SilcClientConnection conn, + SilcClientEntry client_entry, + const char *cipher, + const char *hmac, + unsigned char *key, + SilcUInt32 key_len, + bool generate_key, + bool responder) { unsigned char private_key[32]; - unsigned int len; + SilcUInt32 len; int i; SilcSKEKeyMaterial *keymat; - assert(client_entry); + assert(client && client_entry); /* Return FALSE if key already set */ if (client_entry->send_key && client_entry->receive_key) return FALSE; if (!cipher) - cipher = "aes-256-cbc"; + cipher = SILC_DEFAULT_CIPHER; + if (!hmac) + hmac = SILC_DEFAULT_HMAC; - /* Check the requested cipher */ + /* Check the requested cipher and HMAC */ if (!silc_cipher_is_supported(cipher)) return FALSE; + if (!silc_hmac_is_supported(hmac)) + return FALSE; /* Generate key if not provided */ if (generate_key == TRUE) { len = 32; - for (i = 0; i < len; i++) private_key[i] = silc_rng_get_byte(client->rng); + for (i = 0; i < len; i++) + private_key[i] = silc_rng_get_byte_fast(client->rng); key = private_key; key_len = len; client_entry->generated = TRUE; } /* 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 */ 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; - /* Allocate the ciphers */ + /* Allocate the cipher and HMAC */ silc_cipher_alloc(cipher, &client_entry->send_key); silc_cipher_alloc(cipher, &client_entry->receive_key); + silc_hmac_alloc(hmac, NULL, &client_entry->hmac_send); + silc_hmac_alloc(hmac, NULL, &client_entry->hmac_receive); /* 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); + silc_hmac_set_key(client_entry->hmac_send, keymat->receive_hmac_key, + keymat->hmac_key_len); + silc_hmac_set_key(client_entry->hmac_receive, keymat->send_hmac_key, + keymat->hmac_key_len); + } 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); + silc_hmac_set_key(client_entry->hmac_send, keymat->send_hmac_key, + keymat->hmac_key_len); + silc_hmac_set_key(client_entry->hmac_receive, keymat->receive_hmac_key, + keymat->hmac_key_len); + } /* Free the key material */ silc_ske_free_key_material(keymat); @@ -350,39 +427,66 @@ int silc_client_add_private_message_key(SilcClient client, /* Same as above but takes the key material from the SKE key material structure. This structure is received if the application uses the silc_client_send_key_agreement to negotiate the key material. The - `cipher' SHOULD be provided as it is negotiated also in the SKE - protocol. */ - -int silc_client_add_private_message_key_ske(SilcClient client, - SilcClientConnection conn, - SilcClientEntry client_entry, - char *cipher, - SilcSKEKeyMaterial *key) + `cipher' and `hmac' SHOULD be provided as it is negotiated also in + the SKE protocol. */ + +bool silc_client_add_private_message_key_ske(SilcClient client, + SilcClientConnection conn, + SilcClientEntry client_entry, + const char *cipher, + const char *hmac, + SilcSKEKeyMaterial *key, + bool responder) { - assert(client_entry); + assert(client && client_entry); /* Return FALSE if key already set */ if (client_entry->send_key && client_entry->receive_key) return FALSE; if (!cipher) - cipher = "aes-256-cbc"; + cipher = SILC_DEFAULT_CIPHER; + if (!hmac) + hmac = SILC_DEFAULT_HMAC; - /* Check the requested cipher */ + /* Check the requested cipher and HMAC */ if (!silc_cipher_is_supported(cipher)) return FALSE; + if (!silc_hmac_is_supported(hmac)) + return FALSE; + + client_entry->generated = TRUE; - /* Allocate the ciphers */ + /* Allocate the cipher and HMAC */ silc_cipher_alloc(cipher, &client_entry->send_key); silc_cipher_alloc(cipher, &client_entry->receive_key); + silc_hmac_alloc(hmac, NULL, &client_entry->hmac_send); + silc_hmac_alloc(hmac, NULL, &client_entry->hmac_receive); /* 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); + silc_hmac_set_key(client_entry->hmac_send, key->receive_hmac_key, + key->hmac_key_len); + silc_hmac_set_key(client_entry->hmac_receive, key->send_hmac_key, + key->hmac_key_len); + } 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); + silc_hmac_set_key(client_entry->hmac_send, key->send_hmac_key, + key->hmac_key_len); + silc_hmac_set_key(client_entry->hmac_receive, key->receive_hmac_key, + key->hmac_key_len); + } return TRUE; } @@ -397,21 +501,28 @@ int silc_client_add_private_message_key_ske(SilcClient client, through the SILC network. The packet is protected using normal session keys. */ -int silc_client_send_private_message_key(SilcClient client, +bool silc_client_send_private_message_key(SilcClient client, SilcClientConnection conn, SilcClientEntry client_entry, - int force_send) + bool force_send) { - SilcSocketConnection sock = conn->sock; + SilcSocketConnection sock; SilcBuffer buffer; - int cipher_len; + int cipher_len, hmac_len; + const char *cipher, *hmac; + + assert(client && conn && client_entry); + sock = conn->sock; 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); + hmac = silc_hmac_get_name(client_entry->hmac_send); + hmac_len = strlen(hmac); /* Create private message key payload */ buffer = silc_buffer_alloc(2 + client_entry->key_len); @@ -421,8 +532,11 @@ 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_UI_SHORT(hmac_len), + SILC_STR_UI_XNSTRING(hmac, + hmac_len), SILC_STR_END); /* Send the packet */ @@ -438,11 +552,11 @@ int silc_client_send_private_message_key(SilcClient client, after this to protect the private messages with the remote `client_entry' client. Returns FALSE on error, TRUE otherwise. */ -int silc_client_del_private_message_key(SilcClient client, +bool silc_client_del_private_message_key(SilcClient client, SilcClientConnection conn, SilcClientEntry client_entry) { - assert(client_entry); + assert(client && client_entry); if (!client_entry->send_key && !client_entry->receive_key) return FALSE; @@ -473,16 +587,17 @@ int silc_client_del_private_message_key(SilcClient client, SilcPrivateMessageKeys silc_client_list_private_message_keys(SilcClient client, SilcClientConnection conn, - unsigned int *key_count) + SilcUInt32 *key_count) { SilcPrivateMessageKeys keys; - unsigned int count = 0; + SilcUInt32 count = 0; SilcIDCacheEntry id_cache; SilcIDCacheList list; SilcClientEntry entry; - if (!silc_idcache_find_by_id(conn->client_cache, SILC_ID_CACHE_ANY, - SILC_ID_CLIENT, &list)) + assert(client && conn); + + if (!silc_idcache_get_all(conn->internal->client_cache, &list)) return NULL; if (!silc_idcache_list_count(list)) { @@ -498,7 +613,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++; @@ -518,7 +633,36 @@ silc_client_list_private_message_keys(SilcClient client, silc_client_list_private_message_keys. */ void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys, - unsigned int key_count) + SilcUInt32 key_count) { silc_free(keys); } + +/* Sets away `message'. The away message may be set when the client's + mode is changed to SILC_UMODE_GONE and the client whishes to reply + to anyone who sends private message. The `message' will be sent + automatically back to the the client who send private message. If + away message is already set this replaces the old message with the + new one. If `message' is NULL the old away message is removed. + The sender may freely free the memory of the `message'. */ + +void silc_client_set_away_message(SilcClient client, + SilcClientConnection conn, + char *message) +{ + assert(client && conn); + + if (!message && conn->internal->away) { + silc_free(conn->internal->away->away); + silc_free(conn->internal->away); + conn->internal->away = NULL; + } + + if (message) { + if (!conn->internal->away) + conn->internal->away = silc_calloc(1, sizeof(*conn->internal->away)); + if (conn->internal->away->away) + silc_free(conn->internal->away->away); + conn->internal->away->away = strdup(message); + } +}