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