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 if (channel->internal.send_key)
654 channel->cipher = silc_cipher_get_name(channel->internal.send_key);
656 channel->cipher = NULL;
657 if (channel->internal.hmac)
658 channel->hmac = silc_hmac_get_name(channel->internal.hmac);
660 channel->hmac = NULL;
662 silc_dlist_uninit(channel->internal.private_keys);
663 channel->internal.private_keys = NULL;
668 /* Removes and frees private key `key' from the channel `channel'. The `key'
669 is retrieved by calling the function silc_client_list_channel_private_keys.
670 The key is not used after this. If the key was last private key then the
671 old channel key is used hereafter to protect the channel messages. This
672 returns FALSE on error, TRUE otherwise. */
674 SilcBool silc_client_del_channel_private_key(SilcClient client,
675 SilcClientConnection conn,
676 SilcChannelEntry channel,
677 SilcChannelPrivateKey key)
679 SilcChannelPrivateKey entry;
681 if (!client || !conn || !channel)
684 if (!channel->internal.private_keys)
687 silc_dlist_start(channel->internal.private_keys);
688 while ((entry = silc_dlist_get(channel->internal.private_keys))) {
692 if (channel->internal.curr_key == entry) {
693 channel->internal.curr_key = NULL;
694 channel->cipher = silc_cipher_get_name(channel->internal.send_key);
695 channel->hmac = silc_hmac_get_name(channel->internal.hmac);
698 silc_dlist_del(channel->internal.private_keys, entry);
699 silc_free(entry->name);
700 silc_cipher_free(entry->send_key);
701 silc_cipher_free(entry->receive_key);
702 silc_hmac_free(entry->hmac);
705 if (silc_dlist_count(channel->internal.private_keys) == 0) {
706 silc_dlist_uninit(channel->internal.private_keys);
707 channel->internal.private_keys = NULL;
716 /* Returns array (pointers) of private keys associated to the `channel'.
717 The caller must free the array by calling the function
718 silc_client_free_channel_private_keys. The pointers in the array may be
719 used to delete the specific key by giving the pointer as argument to the
720 function silc_client_del_channel_private_key. */
722 SilcDList silc_client_list_channel_private_keys(SilcClient client,
723 SilcClientConnection conn,
724 SilcChannelEntry channel)
726 SilcChannelPrivateKey entry;
729 if (!client || !conn || !channel)
732 if (!channel->internal.private_keys)
735 list = silc_dlist_init();
739 silc_dlist_start(channel->internal.private_keys);
740 while ((entry = silc_dlist_get(channel->internal.private_keys)))
741 silc_dlist_add(list, entry);
746 /* Sets the `key' to be used as current channel private key on the
747 `channel'. Packet sent after calling this function will be secured
750 void silc_client_current_channel_private_key(SilcClient client,
751 SilcClientConnection conn,
752 SilcChannelEntry channel,
753 SilcChannelPrivateKey key)
757 channel->internal.curr_key = key;
758 channel->cipher = silc_cipher_get_name(key->send_key);
759 channel->hmac = silc_hmac_get_name(key->hmac);
762 /***************************** Utility routines *****************************/
764 /* Returns the SilcChannelUser entry if the `client_entry' is joined on the
765 channel indicated by the `channel'. NULL if client is not joined on
768 SilcChannelUser silc_client_on_channel(SilcChannelEntry channel,
769 SilcClientEntry client_entry)
773 if (silc_hash_table_find(channel->user_list, client_entry, NULL,
780 /* Adds client to channel. Returns TRUE if user was added or is already
781 added to the channel, FALSE on error. Must be called with both `channel'
782 and `client_entry' locked. */
784 SilcBool silc_client_add_to_channel(SilcClient client,
785 SilcClientConnection conn,
786 SilcChannelEntry channel,
787 SilcClientEntry client_entry,
792 if (silc_client_on_channel(channel, client_entry))
795 SILC_LOG_DEBUG(("Add client %s to channel", client_entry->nickname));
797 chu = silc_calloc(1, sizeof(*chu));
801 chu->client = client_entry;
802 chu->channel = channel;
805 silc_client_ref_client(client, conn, client_entry);
806 silc_client_ref_channel(client, conn, channel);
808 silc_hash_table_add(channel->user_list, client_entry, chu);
809 silc_hash_table_add(client_entry->channels, channel, chu);
814 /* Removes client from a channel. Returns FALSE if user is not on channel.
815 This handles entry locking internally. */
817 SilcBool silc_client_remove_from_channel(SilcClient client,
818 SilcClientConnection conn,
819 SilcChannelEntry channel,
820 SilcClientEntry client_entry)
824 chu = silc_client_on_channel(channel, client_entry);
828 SILC_LOG_DEBUG(("Remove client %s from channel", client_entry->nickname));
830 silc_rwlock_wrlock(client_entry->internal.lock);
831 silc_rwlock_wrlock(channel->internal.lock);
833 silc_hash_table_del(chu->client->channels, chu->channel);
834 silc_hash_table_del(chu->channel->user_list, chu->client);
837 /* If channel became empty, delete it */
838 if (!silc_hash_table_count(channel->user_list))
839 silc_client_del_channel(client, conn, channel);
841 silc_rwlock_unlock(client_entry->internal.lock);
842 silc_rwlock_unlock(channel->internal.lock);
844 silc_client_unref_client(client, conn, client_entry);
845 silc_client_unref_channel(client, conn, channel);
850 /* Removes a client entry from all channels it has joined. This handles
851 entry locking internally. */
853 void silc_client_remove_from_channels(SilcClient client,
854 SilcClientConnection conn,
855 SilcClientEntry client_entry)
857 SilcHashTableList htl;
860 if (!silc_hash_table_count(client_entry->channels))
863 SILC_LOG_DEBUG(("Remove client from all joined channels"));
865 silc_rwlock_wrlock(client_entry->internal.lock);
867 silc_hash_table_list(client_entry->channels, &htl);
868 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
869 silc_rwlock_wrlock(chu->channel->internal.lock);
871 silc_hash_table_del(chu->client->channels, chu->channel);
872 silc_hash_table_del(chu->channel->user_list, chu->client);
874 /* If channel became empty, delete it */
875 if (!silc_hash_table_count(chu->channel->user_list))
876 silc_client_del_channel(client, conn, chu->channel);
878 silc_rwlock_unlock(chu->channel->internal.lock);
880 silc_client_unref_client(client, conn, chu->client);
881 silc_client_unref_channel(client, conn, chu->channel);
885 silc_rwlock_unlock(client_entry->internal.lock);
887 silc_hash_table_list_reset(&htl);
890 /* Empties channel from users. This handles entry locking internally. */
892 void silc_client_empty_channel(SilcClient client,
893 SilcClientConnection conn,
894 SilcChannelEntry channel)
896 SilcHashTableList htl;
899 silc_rwlock_wrlock(channel->internal.lock);
901 silc_hash_table_list(channel->user_list, &htl);
902 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
903 silc_hash_table_del(chu->client->channels, chu->channel);
904 silc_hash_table_del(chu->channel->user_list, chu->client);
905 silc_client_unref_client(client, conn, chu->client);
906 silc_client_unref_channel(client, conn, chu->channel);
910 silc_rwlock_unlock(channel->internal.lock);
912 silc_hash_table_list_reset(&htl);
915 /* Save public keys to channel public key list. Removes keys that are
916 marked to be removed. Must be called with `channel' locked. */
918 SilcBool silc_client_channel_save_public_keys(SilcChannelEntry channel,
919 unsigned char *chpk_list,
920 SilcUInt32 chpk_list_len,
923 SilcArgumentDecodedList a, b;
928 /* Remove all channel public keys */
929 if (!channel->channel_pubkeys)
932 silc_dlist_start(channel->channel_pubkeys);
933 while ((b = silc_dlist_get(channel->channel_pubkeys)))
934 silc_dlist_del(channel->channel_pubkeys, b);
936 silc_dlist_uninit(channel->channel_pubkeys);
937 channel->channel_pubkeys = NULL;
942 /* Parse channel public key list and add or remove public keys */
943 chpks = silc_argument_list_parse_decoded(chpk_list, chpk_list_len,
944 SILC_ARGUMENT_PUBLIC_KEY);
948 if (!channel->channel_pubkeys) {
949 channel->channel_pubkeys = silc_dlist_init();
950 if (!channel->channel_pubkeys) {
951 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
956 silc_dlist_start(chpks);
957 while ((a = silc_dlist_get(chpks))) {
959 silc_dlist_start(channel->channel_pubkeys);
960 while ((b = silc_dlist_get(channel->channel_pubkeys))) {
961 if (silc_pkcs_public_key_compare(a->argument, b->argument)) {
967 if ((a->arg_type == 0x00 || a->arg_type == 0x03) && !found) {
968 silc_dlist_add(channel->channel_pubkeys, a);
969 silc_dlist_del(chpks, a);
970 } else if (a->arg_type == 0x01 && found) {
971 silc_dlist_del(channel->channel_pubkeys, b);
975 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);