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 conn->context_type = SILC_ID_CHANNEL;
57 conn->channel_entry = channel;
58 client->internal->ops->say(conn->client, conn,
59 SILC_CLIENT_MESSAGE_ERROR,
60 "Cannot talk to channel: not joined");
61 conn->context_type = SILC_ID_NONE;
65 /* Check if it is allowed to send messages to this channel by us. */
66 if (silc_unlikely(channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS &&
69 if (silc_unlikely(channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS &&
70 chu->mode & SILC_CHANNEL_UMODE_CHANOP &&
71 !(chu->mode & SILC_CHANNEL_UMODE_CHANFO)))
73 if (silc_unlikely(chu->mode & SILC_CHANNEL_UMODE_QUIET))
76 /* Take the key to be used */
77 if (channel->internal.private_keys) {
79 /* Use key application specified */
80 cipher = key->send_key;
82 } else if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY &&
83 channel->internal.curr_key) {
84 /* Use current private key */
85 cipher = channel->internal.curr_key->send_key;
86 hmac = channel->internal.curr_key->hmac;
87 } else if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY &&
88 !channel->internal.curr_key &&
89 channel->internal.private_keys) {
90 /* Use just some private key since we don't know what to use
91 and private keys are set. */
92 silc_dlist_start(channel->internal.private_keys);
93 key = silc_dlist_get(channel->internal.private_keys);
94 cipher = key->send_key;
97 /* Use this key as current private key */
98 channel->internal.curr_key = key;
100 /* Use normal channel key generated by the server */
101 cipher = channel->internal.send_key;
102 hmac = channel->internal.hmac;
105 /* Use normal channel key generated by the server */
106 cipher = channel->internal.send_key;
107 hmac = channel->internal.hmac;
110 if (silc_unlikely(!cipher || !hmac)) {
111 SILC_LOG_ERROR(("No cipher and HMAC for channel"));
115 /* Encode the message payload. This also encrypts the message payload. */
116 sid.type = SILC_ID_CLIENT;
117 sid.u.client_id = chu->client->id;
118 rid.type = SILC_ID_CHANNEL;
119 rid.u.channel_id = chu->channel->id;
120 buffer = silc_message_payload_encode(flags, data, data_len, TRUE, FALSE,
121 cipher, hmac, client->rng, NULL,
122 conn->private_key, hash, &sid, &rid,
124 if (silc_unlikely(!buffer)) {
125 SILC_LOG_ERROR(("Error encoding channel message"));
129 /* Send the channel message */
130 ret = silc_packet_send_ext(conn->stream, SILC_PACKET_CHANNEL_MESSAGE, 0,
131 0, NULL, SILC_ID_CHANNEL, &channel->id,
132 silc_buffer_datalen(buffer), NULL, NULL);
134 silc_buffer_free(buffer);
138 /************************* Channel Message Receive **************************/
140 /* Client resolving callback. Continues with the channel message processing */
142 static void silc_client_channel_message_resolved(SilcClient client,
143 SilcClientConnection conn,
148 /* If no client found, ignore the channel message, a silent error */
150 silc_fsm_next(context, silc_client_channel_message_error);
152 /* Continue processing the channel message packet */
153 SILC_FSM_CALL_CONTINUE(context);
156 /* Process received channel message */
158 SILC_FSM_STATE(silc_client_channel_message)
160 SilcClientConnection conn = fsm_context;
161 SilcClient client = conn->client;
162 SilcPacket packet = state_context;
163 SilcBuffer buffer = &packet->buffer;
164 SilcMessagePayload payload = NULL;
165 SilcChannelEntry channel;
166 SilcClientEntry client_entry;
167 SilcClientID remote_id;
168 SilcChannelID channel_id;
169 unsigned char *message;
170 SilcUInt32 message_len;
171 SilcChannelPrivateKey key = NULL;
173 SILC_LOG_DEBUG(("Received channel message"));
175 SILC_LOG_HEXDUMP(("Channel message"), silc_buffer_data(buffer),
176 silc_buffer_len(buffer));
178 if (silc_unlikely(packet->dst_id_type != SILC_ID_CHANNEL)) {
179 /** Invalid packet */
180 silc_fsm_next(fsm, silc_client_channel_message_error);
181 return SILC_FSM_CONTINUE;
184 if (silc_unlikely(!silc_id_str2id(packet->src_id,
185 packet->src_id_len, SILC_ID_CLIENT,
186 &remote_id, sizeof(remote_id)))) {
187 /** Invalid source ID */
188 silc_fsm_next(fsm, silc_client_channel_message_error);
189 return SILC_FSM_CONTINUE;
192 /* Get sender client entry */
193 client_entry = silc_client_get_client_by_id(client, conn, &remote_id);
194 if (!client_entry || !client_entry->internal.valid) {
195 /** Resolve client info */
196 silc_client_unref_client(client, conn, client_entry);
197 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
198 client, conn, &remote_id, NULL,
199 silc_client_channel_message_resolved,
204 if (silc_unlikely(!silc_id_str2id(packet->dst_id, packet->dst_id_len,
205 SILC_ID_CHANNEL, &channel_id,
206 sizeof(channel_id)))) {
207 /** Invalid destination ID */
208 silc_fsm_next(fsm, silc_client_channel_message_error);
209 return SILC_FSM_CONTINUE;
212 /* Find the channel */
213 channel = silc_client_get_channel_by_id(client, conn, &channel_id);
214 if (silc_unlikely(!channel)) {
215 /** Unknown channel */
216 silc_fsm_next(fsm, silc_client_channel_message_error);
217 return SILC_FSM_CONTINUE;
220 /* Check that user is on channel */
221 if (silc_unlikely(!silc_client_on_channel(channel, client_entry))) {
222 /** User not on channel */
223 SILC_LOG_WARNING(("Message from user not on channel, client or "
225 silc_fsm_next(fsm, silc_client_channel_message_error);
226 return SILC_FSM_CONTINUE;
229 /* If there is no channel private key then just decrypt the message
230 with the channel key. If private keys are set then just go through
231 all private keys and check what decrypts correctly. */
232 if (!channel->internal.private_keys) {
233 /* Parse the channel message payload. This also decrypts the payload */
234 payload = silc_message_payload_parse(silc_buffer_data(buffer),
235 silc_buffer_len(buffer), FALSE,
236 FALSE, channel->internal.receive_key,
237 channel->internal.hmac,
238 packet->src_id, packet->src_id_len,
239 packet->dst_id, packet->dst_id_len,
242 /* If decryption failed and we have just performed channel key rekey
243 we will use the old key in decryption. If that fails too then we
244 cannot do more and will drop the packet. */
245 if (silc_unlikely(!payload)) {
249 if (!channel->internal.old_channel_keys ||
250 !silc_dlist_count(channel->internal.old_channel_keys))
253 SILC_LOG_DEBUG(("Attempting to decrypt with old channel key(s)"));
255 silc_dlist_end(channel->internal.old_channel_keys);
256 silc_dlist_end(channel->internal.old_hmacs);
257 while ((cipher = silc_dlist_get(channel->internal.old_channel_keys))) {
258 hmac = silc_dlist_get(channel->internal.old_hmacs);
262 payload = silc_message_payload_parse(silc_buffer_data(buffer),
263 silc_buffer_len(buffer),
264 FALSE, FALSE, cipher, hmac,
277 /* If the private key mode is not set on the channel then try the actual
278 channel key first before trying private keys. */
279 if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
280 payload = silc_message_payload_parse(silc_buffer_data(buffer),
281 silc_buffer_len(buffer),
283 channel->internal.receive_key,
284 channel->internal.hmac,
292 silc_dlist_start(channel->internal.private_keys);
293 while ((key = silc_dlist_get(channel->internal.private_keys))) {
294 /* Parse the message payload. This also decrypts the payload */
295 payload = silc_message_payload_parse(silc_buffer_data(buffer),
296 silc_buffer_len(buffer),
297 FALSE, FALSE, key->receive_key,
298 key->hmac, packet->src_id,
306 if (key == SILC_LIST_END)
311 message = silc_message_get_data(payload, &message_len);
313 /* Pass the message to application */
314 client->internal->ops->channel_message(
315 client, conn, client_entry, channel, payload,
316 key, silc_message_get_flags(payload),
317 message, message_len);
320 silc_client_unref_client(client, conn, client_entry);
321 silc_client_unref_channel(client, conn, channel);
323 silc_message_payload_free(payload);
324 return SILC_FSM_FINISH;
327 /* Channel message error. */
329 SILC_FSM_STATE(silc_client_channel_message_error)
331 SilcPacket packet = state_context;
332 silc_packet_free(packet);
333 return SILC_FSM_FINISH;
336 /******************************* Channel Key ********************************/
338 /* Timeout callback that is called after a short period of time after the
339 new channel key has been created. This removes the first channel key
342 SILC_TASK_CALLBACK(silc_client_save_channel_key_rekey)
344 SilcChannelEntry channel = (SilcChannelEntry)context;
348 if (channel->internal.old_channel_keys) {
349 silc_dlist_start(channel->internal.old_channel_keys);
350 key = silc_dlist_get(channel->internal.old_channel_keys);
352 silc_dlist_del(channel->internal.old_channel_keys, key);
353 silc_cipher_free(key);
357 if (channel->internal.old_hmacs) {
358 silc_dlist_start(channel->internal.old_hmacs);
359 hmac = silc_dlist_get(channel->internal.old_hmacs);
361 silc_dlist_del(channel->internal.old_hmacs, hmac);
362 silc_hmac_free(hmac);
367 /* Saves channel key from encoded `key_payload'. This is used when we receive
368 Channel Key Payload and when we are processing JOIN command reply. */
370 SilcBool silc_client_save_channel_key(SilcClient client,
371 SilcClientConnection conn,
372 SilcBuffer key_payload,
373 SilcChannelEntry channel)
375 unsigned char *id_string, *key, *cipher, *hmac, hash[SILC_HASH_MAXLEN];
378 SilcChannelKeyPayload payload;
380 SILC_LOG_DEBUG(("New channel key"));
382 payload = silc_channel_key_payload_parse(silc_buffer_data(key_payload),
383 silc_buffer_len(key_payload));
387 id_string = silc_channel_key_get_id(payload, &tmp_len);
389 silc_channel_key_payload_free(payload);
393 if (!silc_id_str2id(id_string, tmp_len, SILC_ID_CHANNEL, &id, sizeof(id))) {
394 silc_channel_key_payload_free(payload);
400 channel = silc_client_get_channel_by_id(client, conn, &id);
402 SILC_LOG_DEBUG(("Key for unknown channel"));
403 silc_channel_key_payload_free(payload);
407 silc_client_ref_channel(client, conn, channel);
410 /* Save the old key for a short period of time so that we can decrypt
411 channel message even after the rekey if some client would be sending
412 messages with the old key after the rekey. */
413 if (!channel->internal.old_channel_keys)
414 channel->internal.old_channel_keys = silc_dlist_init();
415 if (!channel->internal.old_hmacs)
416 channel->internal.old_hmacs = silc_dlist_init();
417 if (channel->internal.old_channel_keys && channel->internal.old_hmacs) {
418 silc_dlist_add(channel->internal.old_channel_keys,
419 channel->internal.receive_key);
420 silc_dlist_add(channel->internal.old_hmacs, channel->internal.hmac);
421 silc_schedule_task_add_timeout(client->schedule,
422 silc_client_save_channel_key_rekey,
426 /* Get channel cipher */
427 cipher = silc_channel_key_get_cipher(payload, NULL);
428 if (!silc_cipher_alloc(cipher, &channel->internal.send_key)) {
429 conn->context_type = SILC_ID_CHANNEL;
430 conn->channel_entry = channel;
431 client->internal->ops->say(
433 SILC_CLIENT_MESSAGE_ERROR,
434 "Cannot talk to channel: unsupported cipher %s",
436 conn->context_type = SILC_ID_NONE;
437 silc_client_unref_channel(client, conn, channel);
438 silc_channel_key_payload_free(payload);
441 if (!silc_cipher_alloc(cipher, &channel->internal.receive_key)) {
442 conn->context_type = SILC_ID_CHANNEL;
443 conn->channel_entry = channel;
444 client->internal->ops->say(
446 SILC_CLIENT_MESSAGE_ERROR,
447 "Cannot talk to channel: unsupported cipher %s",
449 conn->context_type = SILC_ID_NONE;
450 silc_client_unref_channel(client, conn, channel);
451 silc_channel_key_payload_free(payload);
455 /* Set the cipher key. Both sending and receiving keys are same */
456 key = silc_channel_key_get_key(payload, &tmp_len);
457 silc_cipher_set_key(channel->internal.send_key, key, tmp_len * 8, TRUE);
458 silc_cipher_set_key(channel->internal.receive_key, key, tmp_len * 8, FALSE);
460 /* Get channel HMAC */
461 hmac = (channel->internal.hmac ?
462 (char *)silc_hmac_get_name(channel->internal.hmac) :
464 if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
465 conn->context_type = SILC_ID_CHANNEL;
466 conn->channel_entry = channel;
467 client->internal->ops->say(
469 SILC_CLIENT_MESSAGE_ERROR,
470 "Cannot talk to channel: unsupported HMAC %s",
472 conn->context_type = SILC_ID_NONE;
473 silc_client_unref_channel(client, conn, channel);
474 silc_channel_key_payload_free(payload);
478 channel->cipher = silc_cipher_get_name(channel->internal.send_key);
479 channel->hmac = silc_hmac_get_name(channel->internal.hmac);
482 silc_hash_make(silc_hmac_get_hash(channel->internal.hmac), key,
484 silc_hmac_set_key(channel->internal.hmac, hash,
485 silc_hash_len(silc_hmac_get_hash(channel->internal.hmac)));
486 memset(hash, 0, sizeof(hash));
487 silc_channel_key_payload_free(payload);
489 silc_client_unref_channel(client, conn, channel);
494 /* Received channel key packet. The key will replace old channel key. */
496 SILC_FSM_STATE(silc_client_channel_key)
498 SilcClientConnection conn = fsm_context;
499 SilcClient client = conn->client;
500 SilcPacket packet = state_context;
502 SILC_LOG_DEBUG(("Received channel key"));
505 silc_client_save_channel_key(client, conn, &packet->buffer, NULL);
506 silc_packet_free(packet);
508 return SILC_FSM_FINISH;
511 /**************************** Channel Private Key ***************************/
513 /* Add new channel private key */
515 SilcBool silc_client_add_channel_private_key(SilcClient client,
516 SilcClientConnection conn,
517 SilcChannelEntry channel,
523 SilcChannelPrivateKey *ret_key)
525 SilcChannelPrivateKey entry;
526 unsigned char hash[SILC_HASH_MAXLEN];
527 SilcSKEKeyMaterial keymat;
529 if (!client || !conn || !channel)
533 cipher = SILC_DEFAULT_CIPHER;
535 hmac = SILC_DEFAULT_HMAC;
537 if (!silc_cipher_is_supported(cipher))
539 if (!silc_hmac_is_supported(hmac))
542 if (!channel->internal.private_keys) {
543 channel->internal.private_keys = silc_dlist_init();
544 if (!channel->internal.private_keys)
548 /* Produce the key material */
549 keymat = silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
550 conn->internal->sha1hash);
555 entry = silc_calloc(1, sizeof(*entry));
557 silc_ske_free_key_material(keymat);
560 entry->name = name ? strdup(name) : NULL;
562 /* Allocate the cipher and set the key */
563 if (!silc_cipher_alloc(cipher, &entry->send_key)) {
565 silc_free(entry->name);
566 silc_ske_free_key_material(keymat);
569 if (!silc_cipher_alloc(cipher, &entry->receive_key)) {
571 silc_free(entry->name);
572 silc_cipher_free(entry->send_key);
573 silc_ske_free_key_material(keymat);
576 silc_cipher_set_key(entry->send_key, keymat->send_enc_key,
577 keymat->enc_key_len, TRUE);
578 silc_cipher_set_key(entry->receive_key, keymat->send_enc_key,
579 keymat->enc_key_len, FALSE);
581 /* Generate HMAC key from the channel key data and set it */
582 if (!silc_hmac_alloc(hmac, NULL, &entry->hmac)) {
584 silc_free(entry->name);
585 silc_cipher_free(entry->send_key);
586 silc_cipher_free(entry->receive_key);
587 silc_ske_free_key_material(keymat);
590 silc_hash_make(silc_hmac_get_hash(entry->hmac), keymat->send_enc_key,
591 keymat->enc_key_len / 8, hash);
592 silc_hmac_set_key(entry->hmac, hash,
593 silc_hash_len(silc_hmac_get_hash(entry->hmac)));
594 memset(hash, 0, sizeof(hash));
596 /* Add to the private keys list */
597 silc_dlist_add(channel->internal.private_keys, entry);
599 if (!channel->internal.curr_key) {
600 channel->internal.curr_key = entry;
601 channel->cipher = silc_cipher_get_name(entry->send_key);
602 channel->hmac = silc_cipher_get_name(entry->send_key);
605 /* Free the key material */
606 silc_ske_free_key_material(keymat);
614 /* Removes all private keys from the `channel'. The old channel key is used
615 after calling this to protect the channel messages. Returns FALSE on
616 on error, TRUE otherwise. */
618 SilcBool silc_client_del_channel_private_keys(SilcClient client,
619 SilcClientConnection conn,
620 SilcChannelEntry channel)
622 SilcChannelPrivateKey entry;
624 if (!client || !conn || !channel)
627 if (!channel->internal.private_keys)
630 silc_dlist_start(channel->internal.private_keys);
631 while ((entry = silc_dlist_get(channel->internal.private_keys))) {
632 silc_dlist_del(channel->internal.private_keys, entry);
633 silc_free(entry->name);
634 silc_cipher_free(entry->send_key);
635 silc_cipher_free(entry->receive_key);
636 silc_hmac_free(entry->hmac);
640 channel->internal.curr_key = NULL;
641 if (channel->internal.send_key)
642 channel->cipher = silc_cipher_get_name(channel->internal.send_key);
644 channel->cipher = NULL;
645 if (channel->internal.hmac)
646 channel->hmac = silc_hmac_get_name(channel->internal.hmac);
648 channel->hmac = NULL;
650 silc_dlist_uninit(channel->internal.private_keys);
651 channel->internal.private_keys = NULL;
656 /* Removes and frees private key `key' from the channel `channel'. The `key'
657 is retrieved by calling the function silc_client_list_channel_private_keys.
658 The key is not used after this. If the key was last private key then the
659 old channel key is used hereafter to protect the channel messages. This
660 returns FALSE on error, TRUE otherwise. */
662 SilcBool silc_client_del_channel_private_key(SilcClient client,
663 SilcClientConnection conn,
664 SilcChannelEntry channel,
665 SilcChannelPrivateKey key)
667 SilcChannelPrivateKey entry;
669 if (!client || !conn || !channel)
672 if (!channel->internal.private_keys)
675 silc_dlist_start(channel->internal.private_keys);
676 while ((entry = silc_dlist_get(channel->internal.private_keys))) {
680 if (channel->internal.curr_key == entry) {
681 channel->internal.curr_key = NULL;
682 channel->cipher = silc_cipher_get_name(channel->internal.send_key);
683 channel->hmac = silc_hmac_get_name(channel->internal.hmac);
686 silc_dlist_del(channel->internal.private_keys, entry);
687 silc_free(entry->name);
688 silc_cipher_free(entry->send_key);
689 silc_cipher_free(entry->receive_key);
690 silc_hmac_free(entry->hmac);
693 if (silc_dlist_count(channel->internal.private_keys) == 0) {
694 silc_dlist_uninit(channel->internal.private_keys);
695 channel->internal.private_keys = NULL;
704 /* Returns array (pointers) of private keys associated to the `channel'.
705 The caller must free the array by calling the function
706 silc_client_free_channel_private_keys. The pointers in the array may be
707 used to delete the specific key by giving the pointer as argument to the
708 function silc_client_del_channel_private_key. */
710 SilcDList silc_client_list_channel_private_keys(SilcClient client,
711 SilcClientConnection conn,
712 SilcChannelEntry channel)
714 SilcChannelPrivateKey entry;
717 if (!client || !conn || !channel)
720 if (!channel->internal.private_keys)
723 list = silc_dlist_init();
727 silc_dlist_start(channel->internal.private_keys);
728 while ((entry = silc_dlist_get(channel->internal.private_keys)))
729 silc_dlist_add(list, entry);
734 /* Sets the `key' to be used as current channel private key on the
735 `channel'. Packet sent after calling this function will be secured
738 void silc_client_current_channel_private_key(SilcClient client,
739 SilcClientConnection conn,
740 SilcChannelEntry channel,
741 SilcChannelPrivateKey key)
745 channel->internal.curr_key = key;
746 channel->cipher = silc_cipher_get_name(key->send_key);
747 channel->hmac = silc_hmac_get_name(key->hmac);
750 /***************************** Utility routines *****************************/
752 /* Returns the SilcChannelUser entry if the `client_entry' is joined on the
753 channel indicated by the `channel'. NULL if client is not joined on
756 SilcChannelUser silc_client_on_channel(SilcChannelEntry channel,
757 SilcClientEntry client_entry)
761 if (silc_hash_table_find(channel->user_list, client_entry, NULL,
768 /* Adds client to channel. Returns TRUE if user was added or is already
769 added to the channel, FALSE on error. Must be called with both `channel'
770 and `client_entry' locked. */
772 SilcBool silc_client_add_to_channel(SilcClient client,
773 SilcClientConnection conn,
774 SilcChannelEntry channel,
775 SilcClientEntry client_entry,
780 if (silc_client_on_channel(channel, client_entry))
783 SILC_LOG_DEBUG(("Add client %s to channel", client_entry->nickname));
785 chu = silc_calloc(1, sizeof(*chu));
789 chu->client = client_entry;
790 chu->channel = channel;
793 silc_client_ref_client(client, conn, client_entry);
794 silc_client_ref_channel(client, conn, channel);
796 silc_hash_table_add(channel->user_list, client_entry, chu);
797 silc_hash_table_add(client_entry->channels, channel, chu);
802 /* Removes client from a channel. Returns FALSE if user is not on channel.
803 This handles entry locking internally. */
805 SilcBool silc_client_remove_from_channel(SilcClient client,
806 SilcClientConnection conn,
807 SilcChannelEntry channel,
808 SilcClientEntry client_entry)
812 chu = silc_client_on_channel(channel, client_entry);
816 SILC_LOG_DEBUG(("Remove client %s from channel", client_entry->nickname));
818 silc_rwlock_wrlock(client_entry->internal.lock);
819 silc_rwlock_wrlock(channel->internal.lock);
821 silc_hash_table_del(chu->client->channels, chu->channel);
822 silc_hash_table_del(chu->channel->user_list, chu->client);
825 /* If channel became empty, delete it */
826 if (!silc_hash_table_count(channel->user_list))
827 silc_client_del_channel(client, conn, channel);
829 silc_rwlock_unlock(client_entry->internal.lock);
830 silc_rwlock_unlock(channel->internal.lock);
832 silc_client_unref_client(client, conn, client_entry);
833 silc_client_unref_channel(client, conn, channel);
838 /* Removes a client entry from all channels it has joined. This handles
839 entry locking internally. */
841 void silc_client_remove_from_channels(SilcClient client,
842 SilcClientConnection conn,
843 SilcClientEntry client_entry)
845 SilcHashTableList htl;
848 if (!silc_hash_table_count(client_entry->channels))
851 SILC_LOG_DEBUG(("Remove client from all joined channels"));
853 silc_rwlock_wrlock(client_entry->internal.lock);
855 silc_hash_table_list(client_entry->channels, &htl);
856 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
857 silc_rwlock_wrlock(chu->channel->internal.lock);
859 silc_hash_table_del(chu->client->channels, chu->channel);
860 silc_hash_table_del(chu->channel->user_list, chu->client);
862 /* If channel became empty, delete it */
863 if (!silc_hash_table_count(chu->channel->user_list))
864 silc_client_del_channel(client, conn, chu->channel);
866 silc_rwlock_unlock(chu->channel->internal.lock);
868 silc_client_unref_client(client, conn, chu->client);
869 silc_client_unref_channel(client, conn, chu->channel);
873 silc_rwlock_unlock(client_entry->internal.lock);
875 silc_hash_table_list_reset(&htl);
878 /* Empties channel from users. This handles entry locking internally. */
880 void silc_client_empty_channel(SilcClient client,
881 SilcClientConnection conn,
882 SilcChannelEntry channel)
884 SilcHashTableList htl;
887 silc_rwlock_wrlock(channel->internal.lock);
889 silc_hash_table_list(channel->user_list, &htl);
890 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
891 silc_hash_table_del(chu->client->channels, chu->channel);
892 silc_hash_table_del(chu->channel->user_list, chu->client);
893 silc_client_unref_client(client, conn, chu->client);
894 silc_client_unref_channel(client, conn, chu->channel);
898 silc_rwlock_unlock(channel->internal.lock);
900 silc_hash_table_list_reset(&htl);
903 /* Save public keys to channel public key list. Removes keys that are
904 marked to be removed. Must be called with `channel' locked. */
906 SilcBool silc_client_channel_save_public_keys(SilcChannelEntry channel,
907 unsigned char *chpk_list,
908 SilcUInt32 chpk_list_len,
911 SilcArgumentDecodedList a, b;
916 /* Remove all channel public keys */
917 if (!channel->channel_pubkeys)
920 silc_dlist_start(channel->channel_pubkeys);
921 while ((b = silc_dlist_get(channel->channel_pubkeys)))
922 silc_dlist_del(channel->channel_pubkeys, b);
924 silc_dlist_uninit(channel->channel_pubkeys);
925 channel->channel_pubkeys = NULL;
930 /* Parse channel public key list and add or remove public keys */
931 chpks = silc_argument_list_parse_decoded(chpk_list, chpk_list_len,
932 SILC_ARGUMENT_PUBLIC_KEY);
936 if (!channel->channel_pubkeys) {
937 channel->channel_pubkeys = silc_dlist_init();
938 if (!channel->channel_pubkeys) {
939 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
944 silc_dlist_start(chpks);
945 while ((a = silc_dlist_get(chpks))) {
947 silc_dlist_start(channel->channel_pubkeys);
948 while ((b = silc_dlist_get(channel->channel_pubkeys))) {
949 if (silc_pkcs_public_key_compare(a->argument, b->argument)) {
955 if ((a->arg_type == 0x00 || a->arg_type == 0x03) && !found) {
956 silc_dlist_add(channel->channel_pubkeys, a);
957 silc_dlist_del(chpks, a);
958 } else if (a->arg_type == 0x01 && found) {
959 silc_dlist_del(channel->channel_pubkeys, b);
963 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);