5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2007 Pekka Riikonen
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.
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.
22 #include "silcclient.h"
23 #include "client_internal.h"
25 /************************** Channel Message Send ****************************/
27 /* Sends channel message to `channel'. */
29 SilcBool silc_client_send_channel_message(SilcClient client,
30 SilcClientConnection conn,
31 SilcChannelEntry channel,
32 SilcChannelPrivateKey key,
33 SilcMessageFlags flags,
45 SILC_LOG_DEBUG(("Sending channel message"));
47 if (silc_unlikely(!client || !conn || !channel))
49 if (silc_unlikely(flags & SILC_MESSAGE_FLAG_SIGNED && !hash))
51 if (silc_unlikely(conn->internal->disconnected))
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");
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 &&
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)))
70 if (silc_unlikely(chu->mode & SILC_CHANNEL_UMODE_QUIET))
73 /* Take the key to be used */
74 if (channel->internal.private_keys) {
76 /* Use key application specified */
77 cipher = key->send_key;
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->send_key;
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->send_key;
94 /* Use this key as current private key */
95 channel->internal.curr_key = key;
97 /* Use normal channel key generated by the server */
98 cipher = channel->internal.send_key;
99 hmac = channel->internal.hmac;
102 /* Use normal channel key generated by the server */
103 cipher = channel->internal.send_key;
104 hmac = channel->internal.hmac;
107 if (silc_unlikely(!cipher || !hmac)) {
108 SILC_LOG_ERROR(("No cipher and HMAC for channel"));
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,
121 if (silc_unlikely(!buffer)) {
122 SILC_LOG_ERROR(("Error encoding channel message"));
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);
131 silc_buffer_free(buffer);
135 /************************* Channel Message Receive **************************/
137 /* Client resolving callback. Continues with the channel message processing */
139 static void silc_client_channel_message_resolved(SilcClient client,
140 SilcClientConnection conn,
145 /* If no client found, ignore the channel message, a silent error */
147 silc_fsm_next(context, silc_client_channel_message_error);
149 /* Continue processing the channel message packet */
150 SILC_FSM_CALL_CONTINUE(context);
153 /* Process received channel message */
155 SILC_FSM_STATE(silc_client_channel_message)
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;
170 SILC_LOG_DEBUG(("Received channel message"));
172 SILC_LOG_HEXDUMP(("Channel message"), silc_buffer_data(buffer),
173 silc_buffer_len(buffer));
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;
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;
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,
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;
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;
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 "
222 silc_fsm_next(fsm, silc_client_channel_message_error);
223 return SILC_FSM_CONTINUE;
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,
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)) {
246 if (!channel->internal.old_channel_keys ||
247 !silc_dlist_count(channel->internal.old_channel_keys))
250 SILC_LOG_DEBUG(("Attempting to decrypt with old channel key(s)"));
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);
259 payload = silc_message_payload_parse(silc_buffer_data(buffer),
260 silc_buffer_len(buffer),
261 FALSE, FALSE, cipher, hmac,
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),
280 channel->internal.receive_key,
281 channel->internal.hmac,
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->receive_key,
295 key->hmac, packet->src_id,
303 if (key == SILC_LIST_END)
308 message = silc_message_get_data(payload, &message_len);
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);
317 silc_client_unref_client(client, conn, client_entry);
318 silc_client_unref_channel(client, conn, channel);
320 silc_message_payload_free(payload);
321 return SILC_FSM_FINISH;
324 /* Channel message error. */
326 SILC_FSM_STATE(silc_client_channel_message_error)
328 SilcPacket packet = state_context;
329 silc_packet_free(packet);
330 return SILC_FSM_FINISH;
333 /******************************* Channel Key ********************************/
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
339 SILC_TASK_CALLBACK(silc_client_save_channel_key_rekey)
341 SilcChannelEntry channel = (SilcChannelEntry)context;
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);
349 silc_dlist_del(channel->internal.old_channel_keys, key);
350 silc_cipher_free(key);
354 if (channel->internal.old_hmacs) {
355 silc_dlist_start(channel->internal.old_hmacs);
356 hmac = silc_dlist_get(channel->internal.old_hmacs);
358 silc_dlist_del(channel->internal.old_hmacs, hmac);
359 silc_hmac_free(hmac);
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. */
367 SilcBool silc_client_save_channel_key(SilcClient client,
368 SilcClientConnection conn,
369 SilcBuffer key_payload,
370 SilcChannelEntry channel)
372 unsigned char *id_string, *key, *cipher, *hmac, hash[SILC_HASH_MAXLEN];
375 SilcChannelKeyPayload payload;
377 SILC_LOG_DEBUG(("New channel key"));
379 payload = silc_channel_key_payload_parse(silc_buffer_data(key_payload),
380 silc_buffer_len(key_payload));
384 id_string = silc_channel_key_get_id(payload, &tmp_len);
386 silc_channel_key_payload_free(payload);
390 if (!silc_id_str2id(id_string, tmp_len, SILC_ID_CHANNEL, &id, sizeof(id))) {
391 silc_channel_key_payload_free(payload);
397 channel = silc_client_get_channel_by_id(client, conn, &id);
399 SILC_LOG_DEBUG(("Key for unknown channel"));
400 silc_channel_key_payload_free(payload);
404 silc_client_ref_channel(client, conn, channel);
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,
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(
428 SILC_CLIENT_MESSAGE_AUDIT,
429 "Cannot talk to channel: unsupported cipher %s",
431 silc_client_unref_channel(client, conn, channel);
432 silc_channel_key_payload_free(payload);
435 if (!silc_cipher_alloc(cipher, &channel->internal.receive_key)) {
436 client->internal->ops->say(
438 SILC_CLIENT_MESSAGE_AUDIT,
439 "Cannot talk to channel: unsupported cipher %s",
441 silc_client_unref_channel(client, conn, channel);
442 silc_channel_key_payload_free(payload);
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);
451 /* Get channel HMAC */
452 hmac = (channel->internal.hmac ?
453 (char *)silc_hmac_get_name(channel->internal.hmac) :
455 if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
456 client->internal->ops->say(
458 SILC_CLIENT_MESSAGE_AUDIT,
459 "Cannot talk to channel: unsupported HMAC %s",
461 silc_client_unref_channel(client, conn, channel);
462 silc_channel_key_payload_free(payload);
466 channel->cipher = silc_cipher_get_name(channel->internal.send_key);
467 channel->hmac = silc_hmac_get_name(channel->internal.hmac);
470 silc_hash_make(silc_hmac_get_hash(channel->internal.hmac), key,
472 silc_hmac_set_key(channel->internal.hmac, hash,
473 silc_hash_len(silc_hmac_get_hash(channel->internal.hmac)));
474 memset(hash, 0, sizeof(hash));
475 silc_channel_key_payload_free(payload);
477 silc_client_unref_channel(client, conn, channel);
482 /* Received channel key packet. The key will replace old channel key. */
484 SILC_FSM_STATE(silc_client_channel_key)
486 SilcClientConnection conn = fsm_context;
487 SilcClient client = conn->client;
488 SilcPacket packet = state_context;
490 SILC_LOG_DEBUG(("Received channel key"));
493 silc_client_save_channel_key(client, conn, &packet->buffer, NULL);
494 silc_packet_free(packet);
496 return SILC_FSM_FINISH;
499 /**************************** Channel Private Key ***************************/
501 /* Add new channel private key */
503 SilcBool silc_client_add_channel_private_key(SilcClient client,
504 SilcClientConnection conn,
505 SilcChannelEntry channel,
511 SilcChannelPrivateKey *ret_key)
513 SilcChannelPrivateKey entry;
514 unsigned char hash[SILC_HASH_MAXLEN];
515 SilcSKEKeyMaterial keymat;
517 if (!client || !conn || !channel)
521 cipher = SILC_DEFAULT_CIPHER;
523 hmac = SILC_DEFAULT_HMAC;
525 if (!silc_cipher_is_supported(cipher))
527 if (!silc_hmac_is_supported(hmac))
530 if (!channel->internal.private_keys) {
531 channel->internal.private_keys = silc_dlist_init();
532 if (!channel->internal.private_keys)
536 /* Produce the key material */
537 keymat = silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
538 conn->internal->sha1hash);
543 entry = silc_calloc(1, sizeof(*entry));
545 silc_ske_free_key_material(keymat);
548 entry->name = name ? strdup(name) : NULL;
550 /* Allocate the cipher and set the key */
551 if (!silc_cipher_alloc(cipher, &entry->send_key)) {
553 silc_free(entry->name);
554 silc_ske_free_key_material(keymat);
557 if (!silc_cipher_alloc(cipher, &entry->receive_key)) {
559 silc_free(entry->name);
560 silc_cipher_free(entry->send_key);
561 silc_ske_free_key_material(keymat);
564 silc_cipher_set_key(entry->send_key, keymat->send_enc_key,
565 keymat->enc_key_len, TRUE);
566 silc_cipher_set_key(entry->receive_key, keymat->send_enc_key,
567 keymat->enc_key_len, FALSE);
569 /* Generate HMAC key from the channel key data and set it */
570 if (!silc_hmac_alloc(hmac, NULL, &entry->hmac)) {
572 silc_free(entry->name);
573 silc_cipher_free(entry->send_key);
574 silc_cipher_free(entry->receive_key);
575 silc_ske_free_key_material(keymat);
578 silc_hash_make(silc_hmac_get_hash(entry->hmac), keymat->send_enc_key,
579 keymat->enc_key_len / 8, hash);
580 silc_hmac_set_key(entry->hmac, hash,
581 silc_hash_len(silc_hmac_get_hash(entry->hmac)));
582 memset(hash, 0, sizeof(hash));
584 /* Add to the private keys list */
585 silc_dlist_add(channel->internal.private_keys, entry);
587 if (!channel->internal.curr_key) {
588 channel->internal.curr_key = entry;
589 channel->cipher = silc_cipher_get_name(entry->send_key);
590 channel->hmac = silc_cipher_get_name(entry->send_key);
593 /* Free the key material */
594 silc_ske_free_key_material(keymat);
602 /* Removes all private keys from the `channel'. The old channel key is used
603 after calling this to protect the channel messages. Returns FALSE on
604 on error, TRUE otherwise. */
606 SilcBool silc_client_del_channel_private_keys(SilcClient client,
607 SilcClientConnection conn,
608 SilcChannelEntry channel)
610 SilcChannelPrivateKey entry;
612 if (!client || !conn || !channel)
615 if (!channel->internal.private_keys)
618 silc_dlist_start(channel->internal.private_keys);
619 while ((entry = silc_dlist_get(channel->internal.private_keys))) {
620 silc_dlist_del(channel->internal.private_keys, entry);
621 silc_free(entry->name);
622 silc_cipher_free(entry->send_key);
623 silc_cipher_free(entry->receive_key);
624 silc_hmac_free(entry->hmac);
628 channel->internal.curr_key = NULL;
629 channel->cipher = silc_cipher_get_name(channel->internal.send_key);
630 channel->hmac = silc_hmac_get_name(channel->internal.hmac);
632 silc_dlist_uninit(channel->internal.private_keys);
633 channel->internal.private_keys = NULL;
638 /* Removes and frees private key `key' from the channel `channel'. The `key'
639 is retrieved by calling the function silc_client_list_channel_private_keys.
640 The key is not used after this. If the key was last private key then the
641 old channel key is used hereafter to protect the channel messages. This
642 returns FALSE on error, TRUE otherwise. */
644 SilcBool silc_client_del_channel_private_key(SilcClient client,
645 SilcClientConnection conn,
646 SilcChannelEntry channel,
647 SilcChannelPrivateKey key)
649 SilcChannelPrivateKey entry;
651 if (!client || !conn || !channel)
654 if (!channel->internal.private_keys)
657 silc_dlist_start(channel->internal.private_keys);
658 while ((entry = silc_dlist_get(channel->internal.private_keys))) {
662 if (channel->internal.curr_key == entry) {
663 channel->internal.curr_key = NULL;
664 channel->cipher = silc_cipher_get_name(channel->internal.send_key);
665 channel->hmac = silc_hmac_get_name(channel->internal.hmac);
668 silc_dlist_del(channel->internal.private_keys, entry);
669 silc_free(entry->name);
670 silc_cipher_free(entry->send_key);
671 silc_cipher_free(entry->receive_key);
672 silc_hmac_free(entry->hmac);
675 if (silc_dlist_count(channel->internal.private_keys) == 0) {
676 silc_dlist_uninit(channel->internal.private_keys);
677 channel->internal.private_keys = NULL;
686 /* Returns array (pointers) of private keys associated to the `channel'.
687 The caller must free the array by calling the function
688 silc_client_free_channel_private_keys. The pointers in the array may be
689 used to delete the specific key by giving the pointer as argument to the
690 function silc_client_del_channel_private_key. */
692 SilcDList silc_client_list_channel_private_keys(SilcClient client,
693 SilcClientConnection conn,
694 SilcChannelEntry channel)
696 SilcChannelPrivateKey entry;
699 if (!client || !conn || !channel)
702 if (!channel->internal.private_keys)
705 list = silc_dlist_init();
709 silc_dlist_start(channel->internal.private_keys);
710 while ((entry = silc_dlist_get(channel->internal.private_keys)))
711 silc_dlist_add(list, entry);
716 /* Sets the `key' to be used as current channel private key on the
717 `channel'. Packet sent after calling this function will be secured
720 void silc_client_current_channel_private_key(SilcClient client,
721 SilcClientConnection conn,
722 SilcChannelEntry channel,
723 SilcChannelPrivateKey key)
727 channel->internal.curr_key = key;
728 channel->cipher = silc_cipher_get_name(key->send_key);
729 channel->hmac = silc_hmac_get_name(key->hmac);
732 /***************************** Utility routines *****************************/
734 /* Returns the SilcChannelUser entry if the `client_entry' is joined on the
735 channel indicated by the `channel'. NULL if client is not joined on
738 SilcChannelUser silc_client_on_channel(SilcChannelEntry channel,
739 SilcClientEntry client_entry)
743 if (silc_hash_table_find(channel->user_list, client_entry, NULL,
750 /* Adds client to channel. Returns TRUE if user was added or is already
751 added to the channel, FALSE on error. Must be called with both `channel'
752 and `client_entry' locked. */
754 SilcBool silc_client_add_to_channel(SilcClient client,
755 SilcClientConnection conn,
756 SilcChannelEntry channel,
757 SilcClientEntry client_entry,
762 if (silc_client_on_channel(channel, client_entry))
765 SILC_LOG_DEBUG(("Add client %s to channel", client_entry->nickname));
767 chu = silc_calloc(1, sizeof(*chu));
771 chu->client = client_entry;
772 chu->channel = channel;
775 silc_client_ref_client(client, conn, client_entry);
776 silc_client_ref_channel(client, conn, channel);
778 silc_hash_table_add(channel->user_list, client_entry, chu);
779 silc_hash_table_add(client_entry->channels, channel, chu);
784 /* Removes client from a channel. Returns FALSE if user is not on channel.
785 This handles entry locking internally. */
787 SilcBool silc_client_remove_from_channel(SilcClient client,
788 SilcClientConnection conn,
789 SilcChannelEntry channel,
790 SilcClientEntry client_entry)
794 chu = silc_client_on_channel(channel, client_entry);
798 SILC_LOG_DEBUG(("Remove client %s from channel", client_entry->nickname));
800 silc_rwlock_wrlock(client_entry->internal.lock);
801 silc_rwlock_wrlock(channel->internal.lock);
803 silc_hash_table_del(chu->client->channels, chu->channel);
804 silc_hash_table_del(chu->channel->user_list, chu->client);
807 /* If channel became empty, delete it */
808 if (!silc_hash_table_count(channel->user_list))
809 silc_client_del_channel(client, conn, channel);
811 silc_rwlock_unlock(client_entry->internal.lock);
812 silc_rwlock_unlock(channel->internal.lock);
814 silc_client_unref_client(client, conn, client_entry);
815 silc_client_unref_channel(client, conn, channel);
820 /* Removes a client entry from all channels it has joined. This handles
821 entry locking internally. */
823 void silc_client_remove_from_channels(SilcClient client,
824 SilcClientConnection conn,
825 SilcClientEntry client_entry)
827 SilcHashTableList htl;
830 if (!silc_hash_table_count(client_entry->channels))
833 SILC_LOG_DEBUG(("Remove client from all joined channels"));
835 silc_rwlock_wrlock(client_entry->internal.lock);
837 silc_hash_table_list(client_entry->channels, &htl);
838 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
839 silc_rwlock_wrlock(chu->channel->internal.lock);
841 silc_hash_table_del(chu->client->channels, chu->channel);
842 silc_hash_table_del(chu->channel->user_list, chu->client);
844 /* If channel became empty, delete it */
845 if (!silc_hash_table_count(chu->channel->user_list))
846 silc_client_del_channel(client, conn, chu->channel);
848 silc_rwlock_unlock(chu->channel->internal.lock);
850 silc_client_unref_client(client, conn, chu->client);
851 silc_client_unref_channel(client, conn, chu->channel);
855 silc_rwlock_unlock(client_entry->internal.lock);
857 silc_hash_table_list_reset(&htl);
860 /* Empties channel from users. This handles entry locking internally. */
862 void silc_client_empty_channel(SilcClient client,
863 SilcClientConnection conn,
864 SilcChannelEntry channel)
866 SilcHashTableList htl;
869 silc_rwlock_wrlock(channel->internal.lock);
871 silc_hash_table_list(channel->user_list, &htl);
872 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
873 silc_hash_table_del(chu->client->channels, chu->channel);
874 silc_hash_table_del(chu->channel->user_list, chu->client);
875 silc_client_unref_client(client, conn, chu->client);
876 silc_client_unref_channel(client, conn, chu->channel);
880 silc_rwlock_unlock(channel->internal.lock);
882 silc_hash_table_list_reset(&htl);
885 /* Save public keys to channel public key list. Removes keys that are
886 marked to be removed. Must be called with `channel' locked. */
888 SilcBool silc_client_channel_save_public_keys(SilcChannelEntry channel,
889 unsigned char *chpk_list,
890 SilcUInt32 chpk_list_len,
893 SilcArgumentDecodedList a, b;
898 /* Remove all channel public keys */
899 if (!channel->channel_pubkeys)
902 silc_dlist_start(channel->channel_pubkeys);
903 while ((b = silc_dlist_get(channel->channel_pubkeys)))
904 silc_dlist_del(channel->channel_pubkeys, b);
906 silc_dlist_uninit(channel->channel_pubkeys);
907 channel->channel_pubkeys = NULL;
912 /* Parse channel public key list and add or remove public keys */
913 chpks = silc_argument_list_parse_decoded(chpk_list, chpk_list_len,
914 SILC_ARGUMENT_PUBLIC_KEY);
918 if (!channel->channel_pubkeys) {
919 channel->channel_pubkeys = silc_dlist_init();
920 if (!channel->channel_pubkeys) {
921 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
926 silc_dlist_start(chpks);
927 while ((a = silc_dlist_get(chpks))) {
929 silc_dlist_start(channel->channel_pubkeys);
930 while ((b = silc_dlist_get(channel->channel_pubkeys))) {
931 if (silc_pkcs_public_key_compare(a->argument, b->argument)) {
937 if ((a->arg_type == 0x00 || a->arg_type == 0x03) && !found) {
938 silc_dlist_add(channel->channel_pubkeys, a);
939 silc_dlist_del(chpks, a);
940 } else if (a->arg_type == 0x01 && found) {
941 silc_dlist_del(channel->channel_pubkeys, b);
945 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);