The silc_client_connect_to_[server|client] and
[silc.git] / lib / silcclient / client_channel.c
1 /*
2
3   client_channel.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2004, 2006 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
21 #include "silc.h"
22 #include "silcclient.h"
23 #include "client_internal.h"
24
25 /************************** Channel Message Send ****************************/
26
27 /* Sends channel message to `channel'. */
28
29 SilcBool silc_client_send_channel_message(SilcClient client,
30                                           SilcClientConnection conn,
31                                           SilcChannelEntry channel,
32                                           SilcChannelPrivateKey key,
33                                           SilcMessageFlags flags,
34                                           SilcHash hash,
35                                           unsigned char *data,
36                                           SilcUInt32 data_len)
37 {
38   SilcChannelUser chu;
39   SilcBuffer buffer;
40   SilcCipher cipher;
41   SilcHmac hmac;
42   SilcBool ret;
43
44   SILC_LOG_DEBUG(("Sending channel message"));
45
46   if (!client || !conn || !channel)
47     return FALSE;
48   if (flags & SILC_MESSAGE_FLAG_SIGNED && !hash)
49     return FALSE;
50   if (conn->internal->disconnected)
51     return FALSE;
52
53   chu = silc_client_on_channel(channel, conn->local_entry);
54   if (!chu) {
55     client->internal->ops->say(conn->client, conn,
56                                SILC_CLIENT_MESSAGE_AUDIT,
57                                "Cannot talk to channel: not joined");
58     return FALSE;
59   }
60
61   /* Check if it is allowed to send messages to this channel by us. */
62   if (channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS && !chu->mode)
63     return FALSE;
64   if (channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS &&
65       chu->mode & SILC_CHANNEL_UMODE_CHANOP &&
66       !(chu->mode & SILC_CHANNEL_UMODE_CHANFO))
67     return FALSE;
68   if (chu->mode & SILC_CHANNEL_UMODE_QUIET)
69     return FALSE;
70
71   /* Take the key to be used */
72   if (channel->internal.private_keys) {
73     if (key) {
74       /* Use key application specified */
75       cipher = key->cipher;
76       hmac = key->hmac;
77     } else if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY &&
78                channel->internal.curr_key) {
79       /* Use current private key */
80       cipher = channel->internal.curr_key->cipher;
81       hmac = channel->internal.curr_key->hmac;
82     } else if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY &&
83                !channel->internal.curr_key &&
84                channel->internal.private_keys) {
85       /* Use just some private key since we don't know what to use
86          and private keys are set. */
87       silc_dlist_start(channel->internal.private_keys);
88       key = silc_dlist_get(channel->internal.private_keys);
89       cipher = key->cipher;
90       hmac = key->hmac;
91
92       /* Use this key as current private key */
93       channel->internal.curr_key = key;
94     } else {
95       /* Use normal channel key generated by the server */
96       cipher = channel->internal.channel_key;
97       hmac = channel->internal.hmac;
98     }
99   } else {
100     /* Use normal channel key generated by the server */
101     cipher = channel->internal.channel_key;
102     hmac = channel->internal.hmac;
103   }
104
105   if (!cipher || !hmac) {
106     SILC_LOG_ERROR(("No cipher and HMAC for channel"));
107     return FALSE;
108   }
109
110   /* Encode the message payload. This also encrypts the message payload. */
111   buffer = silc_message_payload_encode(flags, data, data_len, TRUE, FALSE,
112                                        cipher, hmac, client->rng, NULL,
113                                        conn->private_key, hash, NULL);
114   if (!buffer) {
115     SILC_LOG_ERROR(("Error encoding channel message"));
116     return FALSE;
117   }
118
119   /* Send the channel message */
120   ret = silc_packet_send_ext(conn->stream, SILC_PACKET_CHANNEL_MESSAGE, 0,
121                              0, NULL, SILC_ID_CHANNEL, &channel->id,
122                              silc_buffer_datalen(buffer), NULL, NULL);
123
124   silc_buffer_free(buffer);
125   return ret;
126 }
127
128 /************************* Channel Message Receive **************************/
129
130 /* Client resolving callback.  Continues with the channel message processing */
131
132 static void silc_client_channel_message_resolved(SilcClient client,
133                                                  SilcClientConnection conn,
134                                                  SilcStatus status,
135                                                  SilcDList clients,
136                                                  void *context)
137 {
138   /* If no client found, ignore the channel message, a silent error */
139   if (!clients)
140     silc_fsm_next(context, silc_client_channel_message_error);
141
142   /* Continue processing the channel message packet */
143   SILC_FSM_CALL_CONTINUE(context);
144 }
145
146 /* Process received channel message */
147
148 SILC_FSM_STATE(silc_client_channel_message)
149 {
150   SilcClientConnection conn = fsm_context;
151   SilcClient client = conn->client;
152   SilcPacket packet = state_context;
153   SilcBuffer buffer = &packet->buffer;
154   SilcMessagePayload payload = NULL;
155   SilcChannelEntry channel;
156   SilcClientEntry client_entry;
157   SilcClientID remote_id;
158   SilcChannelID channel_id;
159   unsigned char *message;
160   SilcUInt32 message_len;
161   SilcChannelPrivateKey key = NULL;
162
163   SILC_LOG_DEBUG(("Received channel message"));
164
165   if (packet->dst_id_type != SILC_ID_CHANNEL) {
166     /** Invalid packet */
167     silc_fsm_next(fsm, silc_client_channel_message_error);
168     return SILC_FSM_CONTINUE;
169   }
170
171   if (!silc_id_str2id(packet->src_id, packet->src_id_len, SILC_ID_CLIENT,
172                       &remote_id, sizeof(remote_id))) {
173     /** Invalid source ID */
174     silc_fsm_next(fsm, silc_client_channel_message_error);
175     return SILC_FSM_CONTINUE;
176   }
177
178   /* Get sender client entry */
179   client_entry = silc_client_get_client_by_id(client, conn, &remote_id);
180   if (!client_entry || !client_entry->nickname[0]) {
181     /** Resolve client info */
182     silc_client_unref_client(client, conn, client_entry);
183     SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
184                                          client, conn, &remote_id, NULL,
185                                          silc_client_channel_message_resolved,
186                                          fsm));
187     /* NOT REACHED */
188   }
189
190   if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
191                       &channel_id, sizeof(channel_id))) {
192     /** Invalid destination ID */
193     silc_fsm_next(fsm, silc_client_channel_message_error);
194     return SILC_FSM_CONTINUE;
195   }
196
197   /* Find the channel */
198   channel = silc_client_get_channel_by_id(client, conn, &channel_id);
199   if (!channel) {
200     /** Unknown channel */
201     silc_fsm_next(fsm, silc_client_channel_message_error);
202     return SILC_FSM_CONTINUE;
203   }
204
205   /* If there is no channel private key then just decrypt the message
206      with the channel key. If private keys are set then just go through
207      all private keys and check what decrypts correctly. */
208   if (!channel->internal.private_keys) {
209     /* Parse the channel message payload. This also decrypts the payload */
210     payload = silc_message_payload_parse(silc_buffer_data(buffer),
211                                          silc_buffer_len(buffer), FALSE,
212                                          FALSE, channel->internal.channel_key,
213                                          channel->internal.hmac, NULL,
214                                          FALSE, NULL);
215
216     /* If decryption failed and we have just performed channel key rekey
217        we will use the old key in decryption. If that fails too then we
218        cannot do more and will drop the packet. */
219     if (!payload) {
220       SilcCipher cipher;
221       SilcHmac hmac;
222
223       if (!channel->internal.old_channel_keys ||
224           !silc_dlist_count(channel->internal.old_channel_keys))
225         goto out;
226
227       SILC_LOG_DEBUG(("Attempting to decrypt with old channel key(s)"));
228
229       silc_dlist_end(channel->internal.old_channel_keys);
230       silc_dlist_end(channel->internal.old_hmacs);
231       while ((cipher = silc_dlist_get(channel->internal.old_channel_keys))) {
232         hmac = silc_dlist_get(channel->internal.old_hmacs);
233         if (!hmac)
234           break;
235
236         payload = silc_message_payload_parse(silc_buffer_data(buffer),
237                                              silc_buffer_len(buffer),
238                                              FALSE, FALSE, cipher, hmac,
239                                              NULL, FALSE, NULL);
240         if (payload)
241           break;
242       }
243       if (!payload)
244         goto out;
245     }
246   } else {
247     /* If the private key mode is not set on the channel then try the actual
248        channel key first before trying private keys. */
249     if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
250       payload = silc_message_payload_parse(silc_buffer_data(buffer),
251                                            silc_buffer_len(buffer),
252                                            FALSE, FALSE,
253                                            channel->internal.channel_key,
254                                            channel->internal.hmac, NULL,
255                                            FALSE, NULL);
256
257     if (!payload) {
258       silc_dlist_start(channel->internal.private_keys);
259       while ((key = silc_dlist_get(channel->internal.private_keys))) {
260         /* Parse the message payload. This also decrypts the payload */
261         payload = silc_message_payload_parse(silc_buffer_data(buffer),
262                                              silc_buffer_len(buffer),
263                                              FALSE, FALSE, key->cipher,
264                                              key->hmac, NULL, FALSE, NULL);
265         if (payload)
266           break;
267       }
268       if (key == SILC_LIST_END)
269         goto out;
270     }
271   }
272
273   message = silc_message_get_data(payload, &message_len);
274
275   /* Pass the message to application */
276   client->internal->ops->channel_message(
277                              client, conn, client_entry, channel, payload,
278                              key, silc_message_get_flags(payload),
279                              message, message_len);
280
281  out:
282   silc_client_unref_client(client, conn, client_entry);
283   silc_client_unref_channel(client, conn, channel);
284   if (payload)
285     silc_message_payload_free(payload);
286   return SILC_FSM_FINISH;
287 }
288
289 /* Channel message error. */
290
291 SILC_FSM_STATE(silc_client_channel_message_error)
292 {
293   SilcPacket packet = state_context;
294   silc_packet_free(packet);
295   return SILC_FSM_FINISH;
296 }
297
298 /******************************* Channel Key ********************************/
299
300 /* Timeout callback that is called after a short period of time after the
301    new channel key has been created.  This removes the first channel key
302    in the list. */
303
304 SILC_TASK_CALLBACK(silc_client_save_channel_key_rekey)
305 {
306   SilcChannelEntry channel = (SilcChannelEntry)context;
307   SilcCipher key;
308   SilcHmac hmac;
309
310   if (channel->internal.old_channel_keys) {
311     silc_dlist_start(channel->internal.old_channel_keys);
312     key = silc_dlist_get(channel->internal.old_channel_keys);
313     if (key) {
314       silc_dlist_del(channel->internal.old_channel_keys, key);
315       silc_cipher_free(key);
316     }
317   }
318
319   if (channel->internal.old_hmacs) {
320     silc_dlist_start(channel->internal.old_hmacs);
321     hmac = silc_dlist_get(channel->internal.old_hmacs);
322     if (hmac) {
323       silc_dlist_del(channel->internal.old_hmacs, hmac);
324       silc_hmac_free(hmac);
325     }
326   }
327 }
328
329 /* Saves channel key from encoded `key_payload'. This is used when we receive
330    Channel Key Payload and when we are processing JOIN command reply. */
331
332 SilcBool silc_client_save_channel_key(SilcClient client,
333                                       SilcClientConnection conn,
334                                       SilcBuffer key_payload,
335                                       SilcChannelEntry channel)
336 {
337   unsigned char *id_string, *key, *cipher, *hmac, hash[SILC_HASH_MAXLEN];
338   SilcUInt32 tmp_len;
339   SilcChannelID id;
340   SilcChannelKeyPayload payload;
341
342   payload = silc_channel_key_payload_parse(silc_buffer_data(key_payload),
343                                            silc_buffer_len(key_payload));
344   if (!payload)
345     return FALSE;
346
347   id_string = silc_channel_key_get_id(payload, &tmp_len);
348   if (!id_string) {
349     silc_channel_key_payload_free(payload);
350     return FALSE;
351   }
352
353   if (!silc_id_str2id(id_string, tmp_len, SILC_ID_CHANNEL, &id, sizeof(id))) {
354     silc_channel_key_payload_free(payload);
355     return FALSE;
356   }
357
358   /* Find channel. */
359   if (!channel) {
360     channel = silc_client_get_channel_by_id(client, conn, &id);
361     if (!channel) {
362       silc_channel_key_payload_free(payload);
363       return FALSE;
364     }
365   } else {
366     silc_client_ref_channel(client, conn, channel);
367   }
368
369   /* Save the old key for a short period of time so that we can decrypt
370      channel message even after the rekey if some client would be sending
371      messages with the old key after the rekey. */
372   if (!channel->internal.old_channel_keys)
373     channel->internal.old_channel_keys = silc_dlist_init();
374   if (!channel->internal.old_hmacs)
375     channel->internal.old_hmacs = silc_dlist_init();
376   if (channel->internal.old_channel_keys && channel->internal.old_hmacs) {
377     silc_dlist_add(channel->internal.old_channel_keys,
378                    channel->internal.channel_key);
379     silc_dlist_add(channel->internal.old_hmacs, channel->internal.hmac);
380     silc_schedule_task_add_timeout(client->schedule,
381                                    silc_client_save_channel_key_rekey,
382                                    channel, 15, 0);
383   }
384
385   /* Get channel cipher */
386   cipher = silc_channel_key_get_cipher(payload, NULL);
387   if (!silc_cipher_alloc(cipher, &channel->internal.channel_key)) {
388     client->internal->ops->say(
389                            conn->client, conn,
390                            SILC_CLIENT_MESSAGE_AUDIT,
391                            "Cannot talk to channel: unsupported cipher %s",
392                            cipher);
393     silc_client_unref_channel(client, conn, channel);
394     silc_channel_key_payload_free(payload);
395     return FALSE;
396   }
397
398   /* Set the cipher key */
399   key = silc_channel_key_get_key(payload, &tmp_len);
400   silc_cipher_set_key(channel->internal.channel_key, key, tmp_len * 8);
401
402   /* Get channel HMAC */
403   hmac = (channel->internal.hmac ?
404           (char *)silc_hmac_get_name(channel->internal.hmac) :
405           SILC_DEFAULT_HMAC);
406   if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
407     client->internal->ops->say(
408                            conn->client, conn,
409                            SILC_CLIENT_MESSAGE_AUDIT,
410                            "Cannot talk to channel: unsupported HMAC %s",
411                            hmac);
412     silc_client_unref_channel(client, conn, channel);
413     silc_channel_key_payload_free(payload);
414     return FALSE;
415   }
416
417   /* Set HMAC key */
418   silc_hash_make(silc_hmac_get_hash(channel->internal.hmac), key,
419                  tmp_len, hash);
420   silc_hmac_set_key(channel->internal.hmac, hash,
421                     silc_hash_len(silc_hmac_get_hash(channel->internal.hmac)));
422   memset(hash, 0, sizeof(hash));
423
424   silc_client_unref_channel(client, conn, channel);
425
426   return TRUE;
427 }
428
429 /* Received channel key packet.  The key will replace old channel key. */
430
431 SILC_FSM_STATE(silc_client_channel_key)
432 {
433   SilcClientConnection conn = fsm_context;
434   SilcClient client = conn->client;
435   SilcPacket packet = state_context;
436
437   SILC_LOG_DEBUG(("Received channel key"));
438
439   /* Save the key */
440   silc_client_save_channel_key(client, conn, &packet->buffer, NULL);
441   silc_packet_free(packet);
442
443   return SILC_FSM_FINISH;
444 }
445
446 /**************************** Channel Private Key ***************************/
447
448 /* Add new channel private key */
449
450 SilcBool silc_client_add_channel_private_key(SilcClient client,
451                                              SilcClientConnection conn,
452                                              SilcChannelEntry channel,
453                                              const char *name,
454                                              char *cipher,
455                                              char *hmac,
456                                              unsigned char *key,
457                                              SilcUInt32 key_len,
458                                              SilcChannelPrivateKey *ret_key)
459 {
460   SilcChannelPrivateKey entry;
461   unsigned char hash[SILC_HASH_MAXLEN];
462   SilcSKEKeyMaterial keymat;
463
464   if (!client || !conn || !channel)
465     return FALSE;
466
467   if (!cipher)
468     cipher = SILC_DEFAULT_CIPHER;
469   if (!hmac)
470     hmac = SILC_DEFAULT_HMAC;
471
472   if (!silc_cipher_is_supported(cipher))
473     return FALSE;
474   if (!silc_hmac_is_supported(hmac))
475     return FALSE;
476
477   if (!channel->internal.private_keys) {
478     channel->internal.private_keys = silc_dlist_init();
479     if (!channel->internal.private_keys)
480       return FALSE;
481   }
482
483   /* Produce the key material */
484   keymat = silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
485                                               conn->internal->sha1hash);
486   if (!keymat)
487     return FALSE;
488
489   /* Save the key */
490   entry = silc_calloc(1, sizeof(*entry));
491   if (!entry) {
492     silc_ske_free_key_material(keymat);
493     return FALSE;
494   }
495   entry->name = name ? strdup(name) : NULL;
496
497   /* Allocate the cipher and set the key*/
498   if (!silc_cipher_alloc(cipher, &entry->cipher)) {
499     silc_free(entry);
500     silc_free(entry->name);
501     silc_ske_free_key_material(keymat);
502     return FALSE;
503   }
504   silc_cipher_set_key(entry->cipher, keymat->send_enc_key,
505                       keymat->enc_key_len);
506
507   /* Generate HMAC key from the channel key data and set it */
508   if (!silc_hmac_alloc(hmac, NULL, &entry->hmac)) {
509     silc_free(entry);
510     silc_free(entry->name);
511     silc_cipher_free(entry->cipher);
512     silc_ske_free_key_material(keymat);
513     return FALSE;
514   }
515   silc_hash_make(silc_hmac_get_hash(entry->hmac), keymat->send_enc_key,
516                  keymat->enc_key_len / 8, hash);
517   silc_hmac_set_key(entry->hmac, hash,
518                     silc_hash_len(silc_hmac_get_hash(entry->hmac)));
519   memset(hash, 0, sizeof(hash));
520
521   /* Add to the private keys list */
522   silc_dlist_add(channel->internal.private_keys, entry);
523
524   if (!channel->internal.curr_key)
525     channel->internal.curr_key = entry;
526
527   /* Free the key material */
528   silc_ske_free_key_material(keymat);
529
530   if (ret_key)
531     *ret_key = entry;
532
533   return TRUE;
534 }
535
536 /* Removes all private keys from the `channel'. The old channel key is used
537    after calling this to protect the channel messages. Returns FALSE on
538    on error, TRUE otherwise. */
539
540 SilcBool silc_client_del_channel_private_keys(SilcClient client,
541                                               SilcClientConnection conn,
542                                               SilcChannelEntry channel)
543 {
544   SilcChannelPrivateKey entry;
545
546   if (!client || !conn || !channel)
547     return FALSE;
548
549   if (!channel->internal.private_keys)
550     return FALSE;
551
552   silc_dlist_start(channel->internal.private_keys);
553   while ((entry = silc_dlist_get(channel->internal.private_keys))) {
554     silc_dlist_del(channel->internal.private_keys, entry);
555     silc_free(entry->name);
556     silc_cipher_free(entry->cipher);
557     silc_hmac_free(entry->hmac);
558     silc_free(entry);
559   }
560
561   channel->internal.curr_key = NULL;
562
563   silc_dlist_uninit(channel->internal.private_keys);
564   channel->internal.private_keys = NULL;
565
566   return TRUE;
567 }
568
569 /* Removes and frees private key `key' from the channel `channel'. The `key'
570    is retrieved by calling the function silc_client_list_channel_private_keys.
571    The key is not used after this. If the key was last private key then the
572    old channel key is used hereafter to protect the channel messages. This
573    returns FALSE on error, TRUE otherwise. */
574
575 SilcBool silc_client_del_channel_private_key(SilcClient client,
576                                              SilcClientConnection conn,
577                                              SilcChannelEntry channel,
578                                              SilcChannelPrivateKey key)
579 {
580   SilcChannelPrivateKey entry;
581
582   if (!client || !conn || !channel)
583     return FALSE;
584
585   if (!channel->internal.private_keys)
586     return FALSE;
587
588   silc_dlist_start(channel->internal.private_keys);
589   while ((entry = silc_dlist_get(channel->internal.private_keys))) {
590     if (entry != key)
591       continue;
592
593     if (channel->internal.curr_key == entry)
594       channel->internal.curr_key = NULL;
595
596     silc_dlist_del(channel->internal.private_keys, entry);
597     silc_free(entry->name);
598     silc_cipher_free(entry->cipher);
599     silc_hmac_free(entry->hmac);
600     silc_free(entry);
601
602     if (silc_dlist_count(channel->internal.private_keys) == 0) {
603       silc_dlist_uninit(channel->internal.private_keys);
604       channel->internal.private_keys = NULL;
605     }
606
607     return TRUE;
608   }
609
610   return FALSE;
611 }
612
613 /* Returns array (pointers) of private keys associated to the `channel'.
614    The caller must free the array by calling the function
615    silc_client_free_channel_private_keys. The pointers in the array may be
616    used to delete the specific key by giving the pointer as argument to the
617    function silc_client_del_channel_private_key. */
618
619 SilcDList silc_client_list_channel_private_keys(SilcClient client,
620                                                 SilcClientConnection conn,
621                                                 SilcChannelEntry channel)
622 {
623   SilcChannelPrivateKey entry;
624   SilcDList list;
625
626   if (!client || !conn || !channel)
627     return FALSE;
628
629   if (!channel->internal.private_keys)
630     return NULL;
631
632   list = silc_dlist_init();
633   if (!list)
634     return NULL;
635
636   silc_dlist_start(channel->internal.private_keys);
637   while ((entry = silc_dlist_get(channel->internal.private_keys)))
638     silc_dlist_add(list, entry);
639
640   return list;
641 }
642
643 /* Sets the `key' to be used as current channel private key on the
644    `channel'.  Packet sent after calling this function will be secured
645    with `key'. */
646
647 void silc_client_current_channel_private_key(SilcClient client,
648                                              SilcClientConnection conn,
649                                              SilcChannelEntry channel,
650                                              SilcChannelPrivateKey key)
651 {
652   if (!channel)
653     return;
654   channel->internal.curr_key = key;
655 }
656
657 /***************************** Utility routines *****************************/
658
659 /* Returns the SilcChannelUser entry if the `client_entry' is joined on the
660    channel indicated by the `channel'. NULL if client is not joined on
661    the channel. */
662
663 SilcChannelUser silc_client_on_channel(SilcChannelEntry channel,
664                                        SilcClientEntry client_entry)
665 {
666   SilcChannelUser chu;
667
668   if (silc_hash_table_find(channel->user_list, client_entry, NULL,
669                            (void *)&chu))
670     return chu;
671
672   return NULL;
673 }
674
675 /* Adds client to channel.  Returns TRUE if user was added or is already
676    added to the channel, FALSE on error. */
677
678 SilcBool silc_client_add_to_channel(SilcClient client,
679                                     SilcClientConnection conn,
680                                     SilcChannelEntry channel,
681                                     SilcClientEntry client_entry,
682                                     SilcUInt32 cumode)
683 {
684   SilcChannelUser chu;
685
686   if (silc_client_on_channel(channel, client_entry))
687     return TRUE;
688
689   chu = silc_calloc(1, sizeof(*chu));
690   if (!chu)
691     return FALSE;
692
693   chu->client = client_entry;
694   chu->channel = channel;
695   chu->mode = cumode;
696
697   silc_client_ref_client(client, conn, client_entry);
698   silc_client_ref_channel(client, conn, channel);
699
700   silc_hash_table_add(channel->user_list, client_entry, chu);
701   silc_hash_table_add(client_entry->channels, channel, chu);
702
703   return TRUE;
704 }
705
706 /* Removes client from a channel */
707
708 SilcBool silc_client_remove_from_channel(SilcClient client,
709                                          SilcClientConnection conn,
710                                          SilcChannelEntry channel,
711                                          SilcClientEntry client_entry)
712 {
713   SilcChannelUser chu;
714
715   chu = silc_client_on_channel(channel, client_entry);
716   if (!chu)
717     return FALSE;
718
719   silc_hash_table_del(chu->client->channels, chu->channel);
720   silc_hash_table_del(chu->channel->user_list, chu->client);
721   silc_free(chu);
722
723   silc_client_unref_client(client, conn, client_entry);
724   silc_client_unref_channel(client, conn, channel);
725
726   return TRUE;
727 }
728
729 /* Removes a client entry from all channels it has joined. */
730
731 void silc_client_remove_from_channels(SilcClient client,
732                                       SilcClientConnection conn,
733                                       SilcClientEntry client_entry)
734 {
735   SilcHashTableList htl;
736   SilcChannelUser chu;
737
738   silc_hash_table_list(client_entry->channels, &htl);
739   while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
740     silc_hash_table_del(chu->client->channels, chu->channel);
741     silc_hash_table_del(chu->channel->user_list, chu->client);
742     silc_client_unref_client(client, conn, chu->client);
743     silc_client_unref_channel(client, conn, chu->channel);
744     silc_free(chu);
745   }
746
747   silc_hash_table_list_reset(&htl);
748 }
749
750 /* Empties channel from users. */
751
752 void silc_client_empty_channel(SilcClient client,
753                                SilcClientConnection conn,
754                                SilcChannelEntry channel)
755 {
756   SilcHashTableList htl;
757   SilcChannelUser chu;
758
759   silc_hash_table_list(channel->user_list, &htl);
760   while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
761     silc_hash_table_del(chu->client->channels, chu->channel);
762     silc_hash_table_del(chu->channel->user_list, chu->client);
763     silc_client_unref_client(client, conn, chu->client);
764     silc_client_unref_channel(client, conn, chu->channel);
765     silc_free(chu);
766   }
767   silc_hash_table_list_reset(&htl);
768 }