9b6f454ab572a77a0f0a2edf8da1b87b61f704a6
[silc.git] / lib / silcclient / client_prvmsg.c
1 /*
2
3   client_prvmsg.c 
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2002 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19 /* $Id$ */
20 /* This file includes the private message sending and receiving routines
21    and private message key handling routines. */
22
23 #include "silcincludes.h"
24 #include "silcclient.h"
25 #include "client_internal.h"
26
27 /* Sends private message to remote client. If private message key has
28    not been set with this client then the message will be encrypted using
29    normal session keys. Private messages are special packets in SILC
30    network hence we need this own function for them. This is similiar
31    to silc_client_packet_send_to_channel except that we send private
32    message. The `data' is the private message. If the `force_send' is
33    TRUE the packet is sent immediately. */
34
35 void silc_client_send_private_message(SilcClient client,
36                                       SilcClientConnection conn,
37                                       SilcClientEntry client_entry,
38                                       SilcMessageFlags flags,
39                                       unsigned char *data, 
40                                       SilcUInt32 data_len, 
41                                       bool force_send)
42 {
43   SilcSocketConnection sock;
44   SilcBuffer buffer;
45   SilcPacketContext packetdata;
46   const SilcBufferStruct packet;
47   SilcCipher cipher;
48   SilcHmac hmac;
49   int block_len;
50
51   assert(client && conn && client_entry);
52   sock = conn->sock;
53   SILC_LOG_DEBUG(("Sending private message"));
54
55   /* Encode private message payload */
56   buffer = silc_message_payload_encode(flags, data, data_len,
57                                        !client_entry->send_key ? FALSE :
58                                        !client_entry->generated,
59                                        TRUE, client_entry->send_key,
60                                        client_entry->hmac_send,
61                                        client->rng, NULL, client->private_key,
62                                        client->sha1hash);
63   if (!buffer)
64     return;
65
66   /* If we don't have private message specific key then private messages
67      are just as any normal packet thus call normal packet sending.  If
68      the key exist then the encryption process is a bit different and
69      will be done in the rest of this function. */
70   if (!client_entry->send_key) {
71     silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE,
72                             client_entry->id, SILC_ID_CLIENT, NULL, NULL,
73                             buffer->data, buffer->len, force_send);
74     goto out;
75   }
76
77   /* We have private message specific key */
78
79   /* Get data used in the encryption */
80   cipher = conn->internal->send_key;
81   hmac = conn->internal->hmac_send;
82   block_len = silc_cipher_get_block_len(cipher);
83
84   /* Set the packet context pointers. */
85   data = buffer->data;
86   data_len = buffer->len;
87   packetdata.flags = SILC_PACKET_FLAG_PRIVMSG_KEY;
88   packetdata.type = SILC_PACKET_PRIVATE_MESSAGE;
89   packetdata.src_id = conn->local_id_data;
90   packetdata.src_id_len = silc_id_get_len(conn->local_id, SILC_ID_CLIENT);
91   packetdata.src_id_type = SILC_ID_CLIENT;
92   packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
93   packetdata.dst_id_len = silc_id_get_len(client_entry->id, SILC_ID_CLIENT);
94   packetdata.dst_id_type = SILC_ID_CLIENT;
95   data_len = SILC_PACKET_DATALEN(data_len, SILC_PACKET_HEADER_LEN +
96                                  packetdata.src_id_len +
97                                  packetdata.dst_id_len);
98   packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
99     packetdata.src_id_len + packetdata.dst_id_len;
100   SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
101                       packetdata.src_id_len +
102                       packetdata.dst_id_len), block_len, packetdata.padlen);
103
104   /* Create the outgoing packet */
105   if (!silc_packet_assemble(&packetdata, client->rng, cipher, hmac, sock, 
106                             data, data_len, (const SilcBuffer)&packet)) {
107     SILC_LOG_ERROR(("Error assembling packet"));
108     goto out;
109   }
110
111   /* Encrypt the header and padding of the packet. */
112   silc_packet_encrypt(cipher, hmac, conn->internal->psn_send++,
113                       (SilcBuffer)&packet, SILC_PACKET_HEADER_LEN +
114                       packetdata.src_id_len + packetdata.dst_id_len +
115                       packetdata.padlen);
116
117   SILC_LOG_HEXDUMP(("Private message packet, len %d", packet.len),
118                    packet.data, packet.len);
119
120   /* Now actually send the packet */
121   silc_client_packet_send_real(client, sock, force_send);
122
123   /* Check for mandatory rekey */
124   if (conn->internal->psn_send == SILC_CLIENT_REKEY_THRESHOLD)
125     silc_schedule_task_add(client->schedule, sock->sock,
126                            silc_client_rekey_callback, sock, 0, 1,
127                            SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
128
129   silc_free(packetdata.dst_id);
130
131  out:
132   silc_buffer_free(buffer);
133 }     
134
135 static void silc_client_private_message_cb(SilcClient client,
136                                            SilcClientConnection conn,
137                                            SilcClientEntry *clients,
138                                            SilcUInt32 clients_count,
139                                            void *context)
140 {
141   SilcPacketContext *packet = (SilcPacketContext *)context;
142
143   if (!clients) {
144     silc_packet_context_free(packet);
145     return;
146   }
147
148   silc_client_private_message(client, conn->sock, packet);
149   silc_packet_context_free(packet);
150 }
151
152 /* Private message received. This processes the private message and
153    finally displays it on the screen. */
154
155 void silc_client_private_message(SilcClient client, 
156                                  SilcSocketConnection sock, 
157                                  SilcPacketContext *packet)
158 {
159   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
160   SilcMessagePayload payload = NULL;
161   SilcClientID *remote_id = NULL;
162   SilcClientEntry remote_client;
163   SilcMessageFlags flags;
164   unsigned char *message;
165   SilcUInt32 message_len;
166   SilcCipher cipher = NULL;
167   SilcHmac hmac = NULL;
168
169   if (packet->src_id_type != SILC_ID_CLIENT)
170     goto out;
171
172   remote_id = silc_id_str2id(packet->src_id, packet->src_id_len, 
173                              SILC_ID_CLIENT);
174   if (!remote_id)
175     goto out;
176
177   /* Check whether we know this client already */
178   remote_client = silc_client_get_client_by_id(client, conn, remote_id);
179   if (!remote_client || !remote_client->nickname) {
180     if (remote_client) {
181       if (remote_client->status & SILC_CLIENT_STATUS_RESOLVING) {
182         remote_client->status &= ~SILC_CLIENT_STATUS_RESOLVING;
183         goto out;
184       }
185       remote_client->status |= SILC_CLIENT_STATUS_RESOLVING;
186       remote_client->resolve_cmd_ident = conn->cmd_ident + 1;
187     }
188
189     /* Resolve the client info */
190     silc_client_get_client_by_id_resolve(client, conn, remote_id, NULL,
191                                          silc_client_private_message_cb,
192                                          silc_packet_context_dup(packet));
193     return;
194   }
195
196   cipher = remote_client->receive_key;
197   hmac = remote_client->hmac_receive;
198   if (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY && !cipher && !hmac) {
199     silc_free(remote_id);
200     return;
201   }
202
203   /* Parse the payload and decrypt it also if private message key is set */
204   payload = silc_message_payload_parse(packet->buffer->data,
205                                        packet->buffer->len, TRUE,
206                                        !remote_client->generated,
207                                        cipher, hmac);
208   if (!payload) {
209     silc_free(remote_id);
210     return;
211   }
212
213   flags = silc_message_get_flags(payload);
214
215   /* Pass the private message to application */
216   message = silc_message_get_data(payload, &message_len);
217   client->internal->ops->private_message(client, conn, remote_client, payload,
218                                          flags, message, message_len);
219
220   /* See if we are away (gone). If we are away we will reply to the
221      sender with the set away message. */
222   if (conn->internal->away && conn->internal->away->away &&
223       !(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
224     /* If it's me, ignore */
225     if (SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
226       goto out;
227
228     /* Send the away message */
229     silc_client_send_private_message(client, conn, remote_client,
230                                      SILC_MESSAGE_FLAG_AUTOREPLY |
231                                      SILC_MESSAGE_FLAG_NOREPLY,
232                                      conn->internal->away->away,
233                                      strlen(conn->internal->away->away), TRUE);
234   }
235
236  out:
237   if (payload)
238     silc_message_payload_free(payload);
239   silc_free(remote_id);
240 }
241
242 /* Function that actually employes the received private message key */
243
244 static void silc_client_private_message_key_cb(SilcClient client,
245                                                SilcClientConnection conn,
246                                                SilcClientEntry *clients,
247                                                SilcUInt32 clients_count,
248                                                void *context)
249 {
250   SilcPacketContext *packet = (SilcPacketContext *)context;
251   unsigned char *key;
252   SilcUInt16 key_len;
253   unsigned char *cipher = NULL, *hmac = NULL;
254   int ret;
255
256   if (!clients)
257     goto out;
258
259   /* Parse the private message key payload */
260   ret = silc_buffer_unformat(packet->buffer,
261                              SILC_STR_UI16_NSTRING(&key, &key_len),
262                              SILC_STR_UI16_STRING_ALLOC(&cipher),
263                              SILC_STR_UI16_STRING_ALLOC(&hmac),
264                              SILC_STR_END);
265   if (!ret)
266     goto out;
267
268   if (key_len > packet->buffer->len)
269     goto out;
270
271   /* Now take the key in use */
272   if (!silc_client_add_private_message_key(client, conn, clients[0],
273                                            cipher, hmac, key, key_len,
274                                            FALSE, TRUE))
275     goto out;
276
277   /* Print some info for application */
278   client->internal->ops->say(
279                      client, conn, SILC_CLIENT_MESSAGE_AUDIT, 
280                      "Received private message key from %s%s%s %s%s%s", 
281                      clients[0]->nickname,
282                      clients[0]->server ? "@" : "",
283                      clients[0]->server ? clients[0]->server : "",
284                      clients[0]->username ? "(" : "",
285                      clients[0]->username ? clients[0]->username : "",
286                      clients[0]->username ? ")" : "");
287
288  out:
289   silc_free(cipher);
290   silc_free(hmac);
291   silc_packet_context_free(packet);
292 }
293
294 /* Processes incoming Private Message Key payload. The libary always
295    accepts the key and takes it into use. */
296
297 void silc_client_private_message_key(SilcClient client,
298                                      SilcSocketConnection sock,
299                                      SilcPacketContext *packet)
300 {
301   SilcClientID *remote_id;
302
303   if (packet->src_id_type != SILC_ID_CLIENT)
304     return;
305
306   remote_id = silc_id_str2id(packet->src_id, packet->src_id_len, 
307                              SILC_ID_CLIENT);
308   if (!remote_id)
309     return;
310
311   silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
312                                        NULL,
313                                        silc_client_private_message_key_cb,
314                                        silc_packet_context_dup(packet));
315   silc_free(remote_id);
316 }
317
318 /* Adds private message key to the client library. The key will be used to
319    encrypt all private message between the client and the remote client
320    indicated by the `client_entry'. If the `key' is NULL and the boolean
321    value `generate_key' is TRUE the library will generate random key.
322    The `key' maybe for example pre-shared-key, passphrase or similar.
323    The `cipher' and `hmac' MAY be provided but SHOULD be NULL to assure
324    that the requirements of the SILC protocol are met. The API, however,
325    allows to allocate any cipher and HMAC.
326
327    If `responder' is TRUE then the sending and receiving keys will be
328    set according the client being the receiver of the private key.  If
329    FALSE the client is being the sender (or negotiator) of the private
330    key.
331
332    It is not necessary to set key for normal private message usage. If the
333    key is not set then the private messages are encrypted using normal
334    session keys. Setting the private key, however, increases the security. 
335
336    Returns FALSE if the key is already set for the `client_entry', TRUE
337    otherwise. */
338
339 bool silc_client_add_private_message_key(SilcClient client,
340                                          SilcClientConnection conn,
341                                          SilcClientEntry client_entry,
342                                          const char *cipher,
343                                          const char *hmac,
344                                          unsigned char *key,
345                                          SilcUInt32 key_len,
346                                          bool generate_key,
347                                          bool responder)
348 {
349   unsigned char private_key[32];
350   SilcUInt32 len;
351   int i;
352   SilcSKEKeyMaterial *keymat;
353
354   assert(client && client_entry);
355
356   /* Return FALSE if key already set */
357   if (client_entry->send_key && client_entry->receive_key)
358     return FALSE;
359
360   if (!cipher)
361     cipher = SILC_DEFAULT_CIPHER;
362   if (!hmac)
363     hmac = SILC_DEFAULT_HMAC;
364
365   /* Check the requested cipher and HMAC */
366   if (!silc_cipher_is_supported(cipher))
367     return FALSE;
368   if (!silc_hmac_is_supported(hmac))
369     return FALSE;
370
371   /* Generate key if not provided */
372   if (generate_key == TRUE) {
373     len = 32;
374     for (i = 0; i < len; i++)
375       private_key[i] = silc_rng_get_byte_fast(client->rng);
376     key = private_key;
377     key_len = len;
378     client_entry->generated = TRUE;
379   }
380
381   /* Save the key */
382   client_entry->key = silc_memdup(key, key_len);
383   client_entry->key_len = key_len;
384
385   /* Produce the key material as the protocol defines */
386   keymat = silc_calloc(1, sizeof(*keymat));
387   if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16, 
388                                          client->sha1hash, keymat) 
389       != SILC_SKE_STATUS_OK)
390     return FALSE;
391
392   /* Allocate the cipher and HMAC */
393   silc_cipher_alloc(cipher, &client_entry->send_key);
394   silc_cipher_alloc(cipher, &client_entry->receive_key);
395   silc_hmac_alloc(hmac, NULL, &client_entry->hmac_send);
396   silc_hmac_alloc(hmac, NULL, &client_entry->hmac_receive);
397
398   /* Set the keys */
399   if (responder == TRUE) {
400     silc_cipher_set_key(client_entry->send_key, keymat->receive_enc_key,
401                         keymat->enc_key_len);
402     silc_cipher_set_iv(client_entry->send_key, keymat->receive_iv);
403     silc_cipher_set_key(client_entry->receive_key, keymat->send_enc_key,
404                         keymat->enc_key_len);
405     silc_cipher_set_iv(client_entry->receive_key, keymat->send_iv);
406     silc_hmac_set_key(client_entry->hmac_send, keymat->receive_hmac_key,
407                       keymat->hmac_key_len);
408     silc_hmac_set_key(client_entry->hmac_receive, keymat->send_hmac_key,
409                       keymat->hmac_key_len);
410   } else {
411     silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key,
412                         keymat->enc_key_len);
413     silc_cipher_set_iv(client_entry->send_key, keymat->send_iv);
414     silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key,
415                         keymat->enc_key_len);
416     silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv);
417     silc_hmac_set_key(client_entry->hmac_send, keymat->send_hmac_key,
418                       keymat->hmac_key_len);
419     silc_hmac_set_key(client_entry->hmac_receive, keymat->receive_hmac_key,
420                       keymat->hmac_key_len);
421   }
422
423   /* Free the key material */
424   silc_ske_free_key_material(keymat);
425
426   return TRUE;
427 }
428
429 /* Same as above but takes the key material from the SKE key material
430    structure. This structure is received if the application uses the
431    silc_client_send_key_agreement to negotiate the key material. The
432    `cipher' and `hmac' SHOULD be provided as it is negotiated also in
433    the SKE protocol. */
434
435 bool silc_client_add_private_message_key_ske(SilcClient client,
436                                              SilcClientConnection conn,
437                                              SilcClientEntry client_entry,
438                                              const char *cipher,
439                                              const char *hmac,
440                                              SilcSKEKeyMaterial *key,
441                                              bool responder)
442 {
443   assert(client && client_entry);
444
445   /* Return FALSE if key already set */
446   if (client_entry->send_key && client_entry->receive_key)
447     return FALSE;
448
449   if (!cipher)
450     cipher = SILC_DEFAULT_CIPHER;
451   if (!hmac)
452     hmac = SILC_DEFAULT_HMAC;
453
454   /* Check the requested cipher and HMAC */
455   if (!silc_cipher_is_supported(cipher))
456     return FALSE;
457   if (!silc_hmac_is_supported(hmac))
458     return FALSE;
459
460   client_entry->generated = TRUE;
461
462   /* Allocate the cipher and HMAC */
463   silc_cipher_alloc(cipher, &client_entry->send_key);
464   silc_cipher_alloc(cipher, &client_entry->receive_key);
465   silc_hmac_alloc(hmac, NULL, &client_entry->hmac_send);
466   silc_hmac_alloc(hmac, NULL, &client_entry->hmac_receive);
467
468   /* Set the keys */
469   if (responder == TRUE) {
470     silc_cipher_set_key(client_entry->send_key, key->receive_enc_key,
471                         key->enc_key_len);
472     silc_cipher_set_iv(client_entry->send_key, key->receive_iv);
473     silc_cipher_set_key(client_entry->receive_key, key->send_enc_key,
474                         key->enc_key_len);
475     silc_cipher_set_iv(client_entry->receive_key, key->send_iv);
476     silc_hmac_set_key(client_entry->hmac_send, key->receive_hmac_key,
477                       key->hmac_key_len);
478     silc_hmac_set_key(client_entry->hmac_receive, key->send_hmac_key,
479                       key->hmac_key_len);
480   } else {
481     silc_cipher_set_key(client_entry->send_key, key->send_enc_key,
482                         key->enc_key_len);
483     silc_cipher_set_iv(client_entry->send_key, key->send_iv);
484     silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key,
485                         key->enc_key_len);
486     silc_cipher_set_iv(client_entry->receive_key, key->receive_iv);
487     silc_hmac_set_key(client_entry->hmac_send, key->send_hmac_key,
488                       key->hmac_key_len);
489     silc_hmac_set_key(client_entry->hmac_receive, key->receive_hmac_key,
490                       key->hmac_key_len);
491   }
492
493   return TRUE;
494 }
495
496 /* Sends private message key payload to the remote client indicated by
497    the `client_entry'. If the `force_send' is TRUE the packet is sent
498    immediately. Returns FALSE if error occurs, TRUE otherwise. The
499    application should call this function after setting the key to the
500    client.
501
502    Note that the key sent using this function is sent to the remote client
503    through the SILC network. The packet is protected using normal session
504    keys. */
505
506 bool silc_client_send_private_message_key(SilcClient client,
507                                          SilcClientConnection conn,
508                                          SilcClientEntry client_entry,
509                                          bool force_send)
510 {
511   SilcSocketConnection sock;
512   SilcBuffer buffer;
513   int cipher_len, hmac_len;
514   const char *cipher, *hmac;
515
516   assert(client && conn && client_entry);
517
518   sock = conn->sock;
519   if (!client_entry->send_key || !client_entry->key)
520     return FALSE;
521
522   SILC_LOG_DEBUG(("Sending private message key"));
523
524   cipher = silc_cipher_get_name(client_entry->send_key);
525   cipher_len = strlen(cipher);
526   hmac = silc_hmac_get_name(client_entry->hmac_send);
527   hmac_len = strlen(hmac);
528
529   /* Create private message key payload */
530   buffer = silc_buffer_alloc(2 + client_entry->key_len);
531   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
532   silc_buffer_format(buffer,
533                      SILC_STR_UI_SHORT(client_entry->key_len),
534                      SILC_STR_UI_XNSTRING(client_entry->key, 
535                                           client_entry->key_len),
536                      SILC_STR_UI_SHORT(cipher_len),
537                      SILC_STR_UI_XNSTRING(cipher,
538                                           cipher_len),
539                      SILC_STR_UI_SHORT(hmac_len),
540                      SILC_STR_UI_XNSTRING(hmac,
541                                           hmac_len),
542                      SILC_STR_END);
543
544   /* Send the packet */
545   silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE_KEY,
546                           client_entry->id, SILC_ID_CLIENT, NULL, NULL,
547                           buffer->data, buffer->len, force_send);
548   silc_free(buffer);
549
550   return TRUE;
551 }
552
553 /* Removes the private message from the library. The key won't be used
554    after this to protect the private messages with the remote `client_entry'
555    client. Returns FALSE on error, TRUE otherwise. */
556
557 bool silc_client_del_private_message_key(SilcClient client,
558                                         SilcClientConnection conn,
559                                         SilcClientEntry client_entry)
560 {
561   assert(client && client_entry);
562
563   if (!client_entry->send_key && !client_entry->receive_key)
564     return FALSE;
565
566   silc_cipher_free(client_entry->send_key);
567   silc_cipher_free(client_entry->receive_key);
568
569   if (client_entry->key) {
570     memset(client_entry->key, 0, client_entry->key_len);
571     silc_free(client_entry->key);
572   }
573
574   client_entry->send_key = NULL;
575   client_entry->receive_key = NULL;
576   client_entry->key = NULL;
577
578   return TRUE;
579 }
580
581 /* Returns array of set private message keys associated to the connection
582    `conn'. Returns allocated SilcPrivateMessageKeys array and the array
583    count to the `key_count' argument. The array must be freed by the caller
584    by calling the silc_client_free_private_message_keys function. Note: 
585    the keys returned in the array is in raw format. It might not be desired
586    to show the keys as is. The application might choose not to show the keys
587    at all or to show the fingerprints of the keys. */
588
589 SilcPrivateMessageKeys
590 silc_client_list_private_message_keys(SilcClient client,
591                                       SilcClientConnection conn,
592                                       SilcUInt32 *key_count)
593 {
594   SilcPrivateMessageKeys keys;
595   SilcUInt32 count = 0;
596   SilcIDCacheEntry id_cache;
597   SilcIDCacheList list;
598   SilcClientEntry entry;
599
600   assert(client && conn);
601
602   if (!silc_idcache_get_all(conn->internal->client_cache, &list))
603     return NULL;
604
605   if (!silc_idcache_list_count(list)) {
606     silc_idcache_list_free(list);
607     return NULL;
608   }
609
610   keys = silc_calloc(silc_idcache_list_count(list), sizeof(*keys));
611
612   silc_idcache_list_first(list, &id_cache);
613   while (id_cache) {
614     entry = (SilcClientEntry)id_cache->context;
615
616     if (entry->send_key) {
617       keys[count].client_entry = entry;
618       keys[count].cipher = (char *)silc_cipher_get_name(entry->send_key);
619       keys[count].key = entry->generated == FALSE ? entry->key : NULL;
620       keys[count].key_len = entry->generated == FALSE ? entry->key_len : 0;
621       count++;
622     }
623
624     if (!silc_idcache_list_next(list, &id_cache))
625       break;
626   }
627
628   if (key_count)
629     *key_count = count;
630
631   return keys;
632 }
633
634 /* Frees the SilcPrivateMessageKeys array returned by the function
635    silc_client_list_private_message_keys. */
636
637 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
638                                            SilcUInt32 key_count)
639 {
640   silc_free(keys);
641 }
642
643 /* Sets away `message'.  The away message may be set when the client's
644    mode is changed to SILC_UMODE_GONE and the client whishes to reply
645    to anyone who sends private message.  The `message' will be sent
646    automatically back to the the client who send private message.  If
647    away message is already set this replaces the old message with the
648    new one.  If `message' is NULL the old away message is removed. 
649    The sender may freely free the memory of the `message'. */
650
651 void silc_client_set_away_message(SilcClient client,
652                                   SilcClientConnection conn,
653                                   char *message)
654 {
655   assert(client && conn);
656
657   if (!message && conn->internal->away) {
658     silc_free(conn->internal->away->away);
659     silc_free(conn->internal->away);
660     conn->internal->away = NULL;
661   }
662
663   if (message) {
664     if (!conn->internal->away)
665       conn->internal->away = silc_calloc(1, sizeof(*conn->internal->away));
666     if (conn->internal->away->away)
667       silc_free(conn->internal->away->away);
668     conn->internal->away->away = strdup(message);
669   }
670 }