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 ****************************/
29 SilcClientConnection conn;
30 SilcChannelEntry channel;
31 } *SilcClientChannelMessageContext;
33 /* Message payload encoding callback */
35 static void silc_client_send_channel_message_final(SilcBuffer message,
38 SilcClientChannelMessageContext c = context;
40 /* Send the channel message */
42 silc_packet_send_ext(c->conn->stream, SILC_PACKET_CHANNEL_MESSAGE, 0,
43 0, NULL, SILC_ID_CHANNEL, &c->channel->id,
44 silc_buffer_datalen(message), NULL, NULL);
46 silc_client_unref_channel(c->client, c->conn, c->channel);
50 /* Sends channel message to `channel'. */
52 SilcBool silc_client_send_channel_message(SilcClient client,
53 SilcClientConnection conn,
54 SilcChannelEntry channel,
55 SilcChannelPrivateKey key,
56 SilcMessageFlags flags,
61 SilcClientChannelMessageContext c;
67 SILC_LOG_DEBUG(("Sending channel message"));
69 if (silc_unlikely(!client || !conn || !channel))
71 if (silc_unlikely(flags & SILC_MESSAGE_FLAG_SIGNED && !hash)) {
72 SILC_LOG_ERROR(("Cannot send signed message without hash, missing "
76 if (silc_unlikely(conn->internal->disconnected))
79 chu = silc_client_on_channel(channel, conn->local_entry);
80 if (silc_unlikely(!chu)) {
81 client->internal->ops->say(conn->client, conn,
82 SILC_CLIENT_MESSAGE_AUDIT,
83 "Cannot talk to channel: not joined");
87 /* Check if it is allowed to send messages to this channel by us. */
88 if (silc_unlikely(channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS &&
91 if (silc_unlikely(channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS &&
92 chu->mode & SILC_CHANNEL_UMODE_CHANOP &&
93 !(chu->mode & SILC_CHANNEL_UMODE_CHANFO)))
95 if (silc_unlikely(chu->mode & SILC_CHANNEL_UMODE_QUIET))
98 /* Take the key to be used */
99 if (channel->internal.private_keys) {
101 /* Use key application specified */
102 cipher = key->send_key;
104 } else if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY &&
105 channel->internal.curr_key) {
106 /* Use current private key */
107 cipher = channel->internal.curr_key->send_key;
108 hmac = channel->internal.curr_key->hmac;
109 } else if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY &&
110 !channel->internal.curr_key &&
111 channel->internal.private_keys) {
112 /* Use just some private key since we don't know what to use
113 and private keys are set. */
114 silc_dlist_start(channel->internal.private_keys);
115 key = silc_dlist_get(channel->internal.private_keys);
116 cipher = key->send_key;
119 /* Use this key as current private key */
120 channel->internal.curr_key = key;
122 /* Use normal channel key generated by the server */
123 cipher = channel->internal.send_key;
124 hmac = channel->internal.hmac;
127 /* Use normal channel key generated by the server */
128 cipher = channel->internal.send_key;
129 hmac = channel->internal.hmac;
132 if (silc_unlikely(!cipher || !hmac)) {
133 SILC_LOG_ERROR(("No cipher and HMAC for channel"));
137 c = silc_calloc(1, sizeof(*c));
143 c->channel = silc_client_ref_channel(client, conn, channel);
145 sid.type = SILC_ID_CLIENT;
146 sid.u.client_id = chu->client->id;
147 rid.type = SILC_ID_CHANNEL;
148 rid.u.channel_id = chu->channel->id;
150 /* Encode the message payload. This also encrypts the message payload. */
151 silc_message_payload_encode(flags, data, data_len, TRUE, FALSE,
152 cipher, hmac, client->rng, NULL,
153 conn->private_key, hash, &sid, &rid, NULL,
154 silc_client_send_channel_message_final, c);
159 /************************* Channel Message Receive **************************/
161 /* Client resolving callback. Continues with the channel message processing */
163 static void silc_client_channel_message_resolved(SilcClient client,
164 SilcClientConnection conn,
169 /* If no client found, ignore the channel message, a silent error */
171 silc_fsm_next(context, silc_client_channel_message_error);
173 /* Continue processing the channel message packet */
174 SILC_FSM_CALL_CONTINUE(context);
177 /* Process received channel message */
179 SILC_FSM_STATE(silc_client_channel_message)
181 SilcClientConnection conn = fsm_context;
182 SilcClient client = conn->client;
183 SilcPacket packet = state_context;
184 SilcBuffer buffer = &packet->buffer;
185 SilcMessagePayload payload = NULL;
186 SilcChannelEntry channel;
187 SilcClientEntry client_entry;
188 SilcClientID remote_id;
189 SilcChannelID channel_id;
190 unsigned char *message;
191 SilcUInt32 message_len;
192 SilcChannelPrivateKey key = NULL;
194 SILC_LOG_DEBUG(("Received channel message"));
196 SILC_LOG_HEXDUMP(("Channel message"), silc_buffer_data(buffer),
197 silc_buffer_len(buffer));
199 if (silc_unlikely(packet->dst_id_type != SILC_ID_CHANNEL)) {
200 /** Invalid packet */
201 silc_fsm_next(fsm, silc_client_channel_message_error);
202 return SILC_FSM_CONTINUE;
205 if (silc_unlikely(!silc_id_str2id(packet->src_id,
206 packet->src_id_len, SILC_ID_CLIENT,
207 &remote_id, sizeof(remote_id)))) {
208 /** Invalid source ID */
209 silc_fsm_next(fsm, silc_client_channel_message_error);
210 return SILC_FSM_CONTINUE;
213 /* Get sender client entry */
214 client_entry = silc_client_get_client_by_id(client, conn, &remote_id);
215 if (!client_entry || !client_entry->internal.valid) {
216 /** Resolve client info */
217 silc_client_unref_client(client, conn, client_entry);
218 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
219 client, conn, &remote_id, NULL,
220 silc_client_channel_message_resolved,
225 if (silc_unlikely(!silc_id_str2id(packet->dst_id, packet->dst_id_len,
226 SILC_ID_CHANNEL, &channel_id,
227 sizeof(channel_id)))) {
228 /** Invalid destination ID */
229 silc_fsm_next(fsm, silc_client_channel_message_error);
230 return SILC_FSM_CONTINUE;
233 /* Find the channel */
234 channel = silc_client_get_channel_by_id(client, conn, &channel_id);
235 if (silc_unlikely(!channel)) {
236 /** Unknown channel */
237 silc_fsm_next(fsm, silc_client_channel_message_error);
238 return SILC_FSM_CONTINUE;
241 /* Check that user is on channel */
242 if (silc_unlikely(!silc_client_on_channel(channel, client_entry))) {
243 /** User not on channel */
244 SILC_LOG_WARNING(("Message from user not on channel, client or "
246 silc_fsm_next(fsm, silc_client_channel_message_error);
247 return SILC_FSM_CONTINUE;
250 /* If there is no channel private key then just decrypt the message
251 with the channel key. If private keys are set then just go through
252 all private keys and check what decrypts correctly. */
253 if (!channel->internal.private_keys) {
254 /* Parse the channel message payload. This also decrypts the payload */
255 payload = silc_message_payload_parse(silc_buffer_data(buffer),
256 silc_buffer_len(buffer), FALSE,
257 FALSE, channel->internal.receive_key,
258 channel->internal.hmac,
259 packet->src_id, packet->src_id_len,
260 packet->dst_id, packet->dst_id_len,
263 /* If decryption failed and we have just performed channel key rekey
264 we will use the old key in decryption. If that fails too then we
265 cannot do more and will drop the packet. */
266 if (silc_unlikely(!payload)) {
270 if (!channel->internal.old_channel_keys ||
271 !silc_dlist_count(channel->internal.old_channel_keys))
274 SILC_LOG_DEBUG(("Attempting to decrypt with old channel key(s)"));
276 silc_dlist_end(channel->internal.old_channel_keys);
277 silc_dlist_end(channel->internal.old_hmacs);
278 while ((cipher = silc_dlist_get(channel->internal.old_channel_keys))) {
279 hmac = silc_dlist_get(channel->internal.old_hmacs);
283 payload = silc_message_payload_parse(silc_buffer_data(buffer),
284 silc_buffer_len(buffer),
285 FALSE, FALSE, cipher, hmac,
298 /* If the private key mode is not set on the channel then try the actual
299 channel key first before trying private keys. */
300 if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
301 payload = silc_message_payload_parse(silc_buffer_data(buffer),
302 silc_buffer_len(buffer),
304 channel->internal.receive_key,
305 channel->internal.hmac,
313 silc_dlist_start(channel->internal.private_keys);
314 while ((key = silc_dlist_get(channel->internal.private_keys))) {
315 /* Parse the message payload. This also decrypts the payload */
316 payload = silc_message_payload_parse(silc_buffer_data(buffer),
317 silc_buffer_len(buffer),
318 FALSE, FALSE, key->receive_key,
319 key->hmac, packet->src_id,
327 if (key == SILC_LIST_END)
332 message = silc_message_get_data(payload, &message_len);
334 /* Pass the message to application */
335 client->internal->ops->channel_message(
336 client, conn, client_entry, channel, payload,
337 key, silc_message_get_flags(payload),
338 message, message_len);
341 silc_client_unref_client(client, conn, client_entry);
342 silc_client_unref_channel(client, conn, channel);
344 silc_message_payload_free(payload);
345 return SILC_FSM_FINISH;
348 /* Channel message error. */
350 SILC_FSM_STATE(silc_client_channel_message_error)
352 SilcPacket packet = state_context;
353 silc_packet_free(packet);
354 return SILC_FSM_FINISH;
357 /******************************* Channel Key ********************************/
359 /* Timeout callback that is called after a short period of time after the
360 new channel key has been created. This removes the first channel key
363 SILC_TASK_CALLBACK(silc_client_save_channel_key_rekey)
365 SilcChannelEntry channel = (SilcChannelEntry)context;
369 if (channel->internal.old_channel_keys) {
370 silc_dlist_start(channel->internal.old_channel_keys);
371 key = silc_dlist_get(channel->internal.old_channel_keys);
373 silc_dlist_del(channel->internal.old_channel_keys, key);
374 silc_cipher_free(key);
378 if (channel->internal.old_hmacs) {
379 silc_dlist_start(channel->internal.old_hmacs);
380 hmac = silc_dlist_get(channel->internal.old_hmacs);
382 silc_dlist_del(channel->internal.old_hmacs, hmac);
383 silc_hmac_free(hmac);
388 /* Saves channel key from encoded `key_payload'. This is used when we receive
389 Channel Key Payload and when we are processing JOIN command reply. */
391 SilcBool silc_client_save_channel_key(SilcClient client,
392 SilcClientConnection conn,
393 SilcBuffer key_payload,
394 SilcChannelEntry channel)
396 unsigned char *id_string, *key, *cipher, *hmac, hash[SILC_HASH_MAXLEN];
399 SilcChannelKeyPayload payload;
401 SILC_LOG_DEBUG(("New channel key"));
403 payload = silc_channel_key_payload_parse(silc_buffer_data(key_payload),
404 silc_buffer_len(key_payload));
408 id_string = silc_channel_key_get_id(payload, &tmp_len);
410 silc_channel_key_payload_free(payload);
414 if (!silc_id_str2id(id_string, tmp_len, SILC_ID_CHANNEL, &id, sizeof(id))) {
415 silc_channel_key_payload_free(payload);
421 channel = silc_client_get_channel_by_id(client, conn, &id);
423 SILC_LOG_DEBUG(("Key for unknown channel"));
424 silc_channel_key_payload_free(payload);
428 silc_client_ref_channel(client, conn, channel);
431 /* Save the old key for a short period of time so that we can decrypt
432 channel message even after the rekey if some client would be sending
433 messages with the old key after the rekey. */
434 if (!channel->internal.old_channel_keys)
435 channel->internal.old_channel_keys = silc_dlist_init();
436 if (!channel->internal.old_hmacs)
437 channel->internal.old_hmacs = silc_dlist_init();
438 if (channel->internal.old_channel_keys && channel->internal.old_hmacs) {
439 silc_dlist_add(channel->internal.old_channel_keys,
440 channel->internal.receive_key);
441 silc_dlist_add(channel->internal.old_hmacs, channel->internal.hmac);
442 silc_schedule_task_add_timeout(client->schedule,
443 silc_client_save_channel_key_rekey,
447 /* Get channel cipher */
448 cipher = silc_channel_key_get_cipher(payload, NULL);
449 if (!silc_cipher_alloc(cipher, &channel->internal.send_key)) {
450 client->internal->ops->say(
452 SILC_CLIENT_MESSAGE_AUDIT,
453 "Cannot talk to channel: unsupported cipher %s",
455 silc_client_unref_channel(client, conn, channel);
456 silc_channel_key_payload_free(payload);
459 if (!silc_cipher_alloc(cipher, &channel->internal.receive_key)) {
460 client->internal->ops->say(
462 SILC_CLIENT_MESSAGE_AUDIT,
463 "Cannot talk to channel: unsupported cipher %s",
465 silc_client_unref_channel(client, conn, channel);
466 silc_channel_key_payload_free(payload);
470 /* Set the cipher key. Both sending and receiving keys are same */
471 key = silc_channel_key_get_key(payload, &tmp_len);
472 silc_cipher_set_key(channel->internal.send_key, key, tmp_len * 8, TRUE);
473 silc_cipher_set_key(channel->internal.receive_key, key, tmp_len * 8, FALSE);
475 /* Get channel HMAC */
476 hmac = (channel->internal.hmac ?
477 (char *)silc_hmac_get_name(channel->internal.hmac) :
479 if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
480 client->internal->ops->say(
482 SILC_CLIENT_MESSAGE_AUDIT,
483 "Cannot talk to channel: unsupported HMAC %s",
485 silc_client_unref_channel(client, conn, channel);
486 silc_channel_key_payload_free(payload);
490 channel->cipher = silc_cipher_get_name(channel->internal.send_key);
491 channel->hmac = silc_hmac_get_name(channel->internal.hmac);
494 silc_hash_make(silc_hmac_get_hash(channel->internal.hmac), key,
496 silc_hmac_set_key(channel->internal.hmac, hash,
497 silc_hash_len(silc_hmac_get_hash(channel->internal.hmac)));
498 memset(hash, 0, sizeof(hash));
499 silc_channel_key_payload_free(payload);
501 silc_client_unref_channel(client, conn, channel);
506 /* Received channel key packet. The key will replace old channel key. */
508 SILC_FSM_STATE(silc_client_channel_key)
510 SilcClientConnection conn = fsm_context;
511 SilcClient client = conn->client;
512 SilcPacket packet = state_context;
514 SILC_LOG_DEBUG(("Received channel key"));
517 silc_client_save_channel_key(client, conn, &packet->buffer, NULL);
518 silc_packet_free(packet);
520 return SILC_FSM_FINISH;
523 /**************************** Channel Private Key ***************************/
525 /* Add new channel private key */
527 SilcBool silc_client_add_channel_private_key(SilcClient client,
528 SilcClientConnection conn,
529 SilcChannelEntry channel,
535 SilcChannelPrivateKey *ret_key)
537 SilcChannelPrivateKey entry;
538 unsigned char hash[SILC_HASH_MAXLEN];
539 SilcSKEKeyMaterial keymat;
541 if (!client || !conn || !channel)
545 cipher = SILC_DEFAULT_CIPHER;
547 hmac = SILC_DEFAULT_HMAC;
549 if (!silc_cipher_is_supported(cipher))
551 if (!silc_hmac_is_supported(hmac))
554 if (!channel->internal.private_keys) {
555 channel->internal.private_keys = silc_dlist_init();
556 if (!channel->internal.private_keys)
560 /* Produce the key material */
561 keymat = silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
562 conn->internal->sha1hash);
567 entry = silc_calloc(1, sizeof(*entry));
569 silc_ske_free_key_material(keymat);
572 entry->name = name ? strdup(name) : NULL;
574 /* Allocate the cipher and set the key */
575 if (!silc_cipher_alloc(cipher, &entry->send_key)) {
577 silc_free(entry->name);
578 silc_ske_free_key_material(keymat);
581 if (!silc_cipher_alloc(cipher, &entry->receive_key)) {
583 silc_free(entry->name);
584 silc_cipher_free(entry->send_key);
585 silc_ske_free_key_material(keymat);
588 silc_cipher_set_key(entry->send_key, keymat->send_enc_key,
589 keymat->enc_key_len, TRUE);
590 silc_cipher_set_key(entry->receive_key, keymat->send_enc_key,
591 keymat->enc_key_len, FALSE);
593 /* Generate HMAC key from the channel key data and set it */
594 if (!silc_hmac_alloc(hmac, NULL, &entry->hmac)) {
596 silc_free(entry->name);
597 silc_cipher_free(entry->send_key);
598 silc_cipher_free(entry->receive_key);
599 silc_ske_free_key_material(keymat);
602 silc_hash_make(silc_hmac_get_hash(entry->hmac), keymat->send_enc_key,
603 keymat->enc_key_len / 8, hash);
604 silc_hmac_set_key(entry->hmac, hash,
605 silc_hash_len(silc_hmac_get_hash(entry->hmac)));
606 memset(hash, 0, sizeof(hash));
608 /* Add to the private keys list */
609 silc_dlist_add(channel->internal.private_keys, entry);
611 if (!channel->internal.curr_key) {
612 channel->internal.curr_key = entry;
613 channel->cipher = silc_cipher_get_name(entry->send_key);
614 channel->hmac = silc_cipher_get_name(entry->send_key);
617 /* Free the key material */
618 silc_ske_free_key_material(keymat);
626 /* Removes all private keys from the `channel'. The old channel key is used
627 after calling this to protect the channel messages. Returns FALSE on
628 on error, TRUE otherwise. */
630 SilcBool silc_client_del_channel_private_keys(SilcClient client,
631 SilcClientConnection conn,
632 SilcChannelEntry channel)
634 SilcChannelPrivateKey entry;
636 if (!client || !conn || !channel)
639 if (!channel->internal.private_keys)
642 silc_dlist_start(channel->internal.private_keys);
643 while ((entry = silc_dlist_get(channel->internal.private_keys))) {
644 silc_dlist_del(channel->internal.private_keys, entry);
645 silc_free(entry->name);
646 silc_cipher_free(entry->send_key);
647 silc_cipher_free(entry->receive_key);
648 silc_hmac_free(entry->hmac);
652 channel->internal.curr_key = NULL;
653 channel->cipher = silc_cipher_get_name(channel->internal.send_key);
654 channel->hmac = silc_hmac_get_name(channel->internal.hmac);
656 silc_dlist_uninit(channel->internal.private_keys);
657 channel->internal.private_keys = NULL;
662 /* Removes and frees private key `key' from the channel `channel'. The `key'
663 is retrieved by calling the function silc_client_list_channel_private_keys.
664 The key is not used after this. If the key was last private key then the
665 old channel key is used hereafter to protect the channel messages. This
666 returns FALSE on error, TRUE otherwise. */
668 SilcBool silc_client_del_channel_private_key(SilcClient client,
669 SilcClientConnection conn,
670 SilcChannelEntry channel,
671 SilcChannelPrivateKey key)
673 SilcChannelPrivateKey entry;
675 if (!client || !conn || !channel)
678 if (!channel->internal.private_keys)
681 silc_dlist_start(channel->internal.private_keys);
682 while ((entry = silc_dlist_get(channel->internal.private_keys))) {
686 if (channel->internal.curr_key == entry) {
687 channel->internal.curr_key = NULL;
688 channel->cipher = silc_cipher_get_name(channel->internal.send_key);
689 channel->hmac = silc_hmac_get_name(channel->internal.hmac);
692 silc_dlist_del(channel->internal.private_keys, entry);
693 silc_free(entry->name);
694 silc_cipher_free(entry->send_key);
695 silc_cipher_free(entry->receive_key);
696 silc_hmac_free(entry->hmac);
699 if (silc_dlist_count(channel->internal.private_keys) == 0) {
700 silc_dlist_uninit(channel->internal.private_keys);
701 channel->internal.private_keys = NULL;
710 /* Returns array (pointers) of private keys associated to the `channel'.
711 The caller must free the array by calling the function
712 silc_client_free_channel_private_keys. The pointers in the array may be
713 used to delete the specific key by giving the pointer as argument to the
714 function silc_client_del_channel_private_key. */
716 SilcDList silc_client_list_channel_private_keys(SilcClient client,
717 SilcClientConnection conn,
718 SilcChannelEntry channel)
720 SilcChannelPrivateKey entry;
723 if (!client || !conn || !channel)
726 if (!channel->internal.private_keys)
729 list = silc_dlist_init();
733 silc_dlist_start(channel->internal.private_keys);
734 while ((entry = silc_dlist_get(channel->internal.private_keys)))
735 silc_dlist_add(list, entry);
740 /* Sets the `key' to be used as current channel private key on the
741 `channel'. Packet sent after calling this function will be secured
744 void silc_client_current_channel_private_key(SilcClient client,
745 SilcClientConnection conn,
746 SilcChannelEntry channel,
747 SilcChannelPrivateKey key)
751 channel->internal.curr_key = key;
752 channel->cipher = silc_cipher_get_name(key->send_key);
753 channel->hmac = silc_hmac_get_name(key->hmac);
756 /***************************** Utility routines *****************************/
758 /* Returns the SilcChannelUser entry if the `client_entry' is joined on the
759 channel indicated by the `channel'. NULL if client is not joined on
762 SilcChannelUser silc_client_on_channel(SilcChannelEntry channel,
763 SilcClientEntry client_entry)
767 if (silc_hash_table_find(channel->user_list, client_entry, NULL,
774 /* Adds client to channel. Returns TRUE if user was added or is already
775 added to the channel, FALSE on error. Must be called with both `channel'
776 and `client_entry' locked. */
778 SilcBool silc_client_add_to_channel(SilcClient client,
779 SilcClientConnection conn,
780 SilcChannelEntry channel,
781 SilcClientEntry client_entry,
786 if (silc_client_on_channel(channel, client_entry))
789 SILC_LOG_DEBUG(("Add client %s to channel", client_entry->nickname));
791 chu = silc_calloc(1, sizeof(*chu));
795 chu->client = client_entry;
796 chu->channel = channel;
799 silc_client_ref_client(client, conn, client_entry);
800 silc_client_ref_channel(client, conn, channel);
802 silc_hash_table_add(channel->user_list, client_entry, chu);
803 silc_hash_table_add(client_entry->channels, channel, chu);
808 /* Removes client from a channel. Returns FALSE if user is not on channel.
809 This handles entry locking internally. */
811 SilcBool silc_client_remove_from_channel(SilcClient client,
812 SilcClientConnection conn,
813 SilcChannelEntry channel,
814 SilcClientEntry client_entry)
818 chu = silc_client_on_channel(channel, client_entry);
822 SILC_LOG_DEBUG(("Remove client %s from channel", client_entry->nickname));
824 silc_rwlock_wrlock(client_entry->internal.lock);
825 silc_rwlock_wrlock(channel->internal.lock);
827 silc_hash_table_del(chu->client->channels, chu->channel);
828 silc_hash_table_del(chu->channel->user_list, chu->client);
831 /* If channel became empty, delete it */
832 if (!silc_hash_table_count(channel->user_list))
833 silc_client_del_channel(client, conn, channel);
835 silc_rwlock_unlock(client_entry->internal.lock);
836 silc_rwlock_unlock(channel->internal.lock);
838 silc_client_unref_client(client, conn, client_entry);
839 silc_client_unref_channel(client, conn, channel);
844 /* Removes a client entry from all channels it has joined. This handles
845 entry locking internally. */
847 void silc_client_remove_from_channels(SilcClient client,
848 SilcClientConnection conn,
849 SilcClientEntry client_entry)
851 SilcHashTableList htl;
854 if (!silc_hash_table_count(client_entry->channels))
857 SILC_LOG_DEBUG(("Remove client from all joined channels"));
859 silc_rwlock_wrlock(client_entry->internal.lock);
861 silc_hash_table_list(client_entry->channels, &htl);
862 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
863 silc_rwlock_wrlock(chu->channel->internal.lock);
865 silc_hash_table_del(chu->client->channels, chu->channel);
866 silc_hash_table_del(chu->channel->user_list, chu->client);
868 /* If channel became empty, delete it */
869 if (!silc_hash_table_count(chu->channel->user_list))
870 silc_client_del_channel(client, conn, chu->channel);
872 silc_rwlock_unlock(chu->channel->internal.lock);
874 silc_client_unref_client(client, conn, chu->client);
875 silc_client_unref_channel(client, conn, chu->channel);
879 silc_rwlock_unlock(client_entry->internal.lock);
881 silc_hash_table_list_reset(&htl);
884 /* Empties channel from users. This handles entry locking internally. */
886 void silc_client_empty_channel(SilcClient client,
887 SilcClientConnection conn,
888 SilcChannelEntry channel)
890 SilcHashTableList htl;
893 silc_rwlock_wrlock(channel->internal.lock);
895 silc_hash_table_list(channel->user_list, &htl);
896 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
897 silc_hash_table_del(chu->client->channels, chu->channel);
898 silc_hash_table_del(chu->channel->user_list, chu->client);
899 silc_client_unref_client(client, conn, chu->client);
900 silc_client_unref_channel(client, conn, chu->channel);
904 silc_rwlock_unlock(channel->internal.lock);
906 silc_hash_table_list_reset(&htl);
909 /* Save public keys to channel public key list. Removes keys that are
910 marked to be removed. Must be called with `channel' locked. */
912 SilcBool silc_client_channel_save_public_keys(SilcChannelEntry channel,
913 unsigned char *chpk_list,
914 SilcUInt32 chpk_list_len,
917 SilcArgumentDecodedList a, b;
922 /* Remove all channel public keys */
923 if (!channel->channel_pubkeys)
926 silc_dlist_start(channel->channel_pubkeys);
927 while ((b = silc_dlist_get(channel->channel_pubkeys)))
928 silc_dlist_del(channel->channel_pubkeys, b);
930 silc_dlist_uninit(channel->channel_pubkeys);
931 channel->channel_pubkeys = NULL;
936 /* Parse channel public key list and add or remove public keys */
937 chpks = silc_argument_list_parse_decoded(chpk_list, chpk_list_len,
938 SILC_ARGUMENT_PUBLIC_KEY);
942 if (!channel->channel_pubkeys) {
943 channel->channel_pubkeys = silc_dlist_init();
944 if (!channel->channel_pubkeys) {
945 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
950 silc_dlist_start(chpks);
951 while ((a = silc_dlist_get(chpks))) {
953 silc_dlist_start(channel->channel_pubkeys);
954 while ((b = silc_dlist_get(channel->channel_pubkeys))) {
955 if (silc_pkcs_public_key_compare(a->argument, b->argument)) {
961 if ((a->arg_type == 0x00 || a->arg_type == 0x03) && !found) {
962 silc_dlist_add(channel->channel_pubkeys, a);
963 silc_dlist_del(chpks, a);
964 } else if (a->arg_type == 0x01 && found) {
965 silc_dlist_del(channel->channel_pubkeys, b);
969 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);