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