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