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 if (channel->internal.send_key)
630 channel->cipher = silc_cipher_get_name(channel->internal.send_key);
632 channel->cipher = NULL;
634 channel->hmac = silc_hmac_get_name(channel->internal.hmac);
636 channel->hmac = NULL;
638 silc_dlist_uninit(channel->internal.private_keys);
639 channel->internal.private_keys = NULL;
644 /* Removes and frees private key `key' from the channel `channel'. The `key'
645 is retrieved by calling the function silc_client_list_channel_private_keys.
646 The key is not used after this. If the key was last private key then the
647 old channel key is used hereafter to protect the channel messages. This
648 returns FALSE on error, TRUE otherwise. */
650 SilcBool silc_client_del_channel_private_key(SilcClient client,
651 SilcClientConnection conn,
652 SilcChannelEntry channel,
653 SilcChannelPrivateKey key)
655 SilcChannelPrivateKey entry;
657 if (!client || !conn || !channel)
660 if (!channel->internal.private_keys)
663 silc_dlist_start(channel->internal.private_keys);
664 while ((entry = silc_dlist_get(channel->internal.private_keys))) {
668 if (channel->internal.curr_key == entry) {
669 channel->internal.curr_key = NULL;
670 channel->cipher = silc_cipher_get_name(channel->internal.send_key);
671 channel->hmac = silc_hmac_get_name(channel->internal.hmac);
674 silc_dlist_del(channel->internal.private_keys, entry);
675 silc_free(entry->name);
676 silc_cipher_free(entry->send_key);
677 silc_cipher_free(entry->receive_key);
678 silc_hmac_free(entry->hmac);
681 if (silc_dlist_count(channel->internal.private_keys) == 0) {
682 silc_dlist_uninit(channel->internal.private_keys);
683 channel->internal.private_keys = NULL;
692 /* Returns array (pointers) of private keys associated to the `channel'.
693 The caller must free the array by calling the function
694 silc_client_free_channel_private_keys. The pointers in the array may be
695 used to delete the specific key by giving the pointer as argument to the
696 function silc_client_del_channel_private_key. */
698 SilcDList silc_client_list_channel_private_keys(SilcClient client,
699 SilcClientConnection conn,
700 SilcChannelEntry channel)
702 SilcChannelPrivateKey entry;
705 if (!client || !conn || !channel)
708 if (!channel->internal.private_keys)
711 list = silc_dlist_init();
715 silc_dlist_start(channel->internal.private_keys);
716 while ((entry = silc_dlist_get(channel->internal.private_keys)))
717 silc_dlist_add(list, entry);
722 /* Sets the `key' to be used as current channel private key on the
723 `channel'. Packet sent after calling this function will be secured
726 void silc_client_current_channel_private_key(SilcClient client,
727 SilcClientConnection conn,
728 SilcChannelEntry channel,
729 SilcChannelPrivateKey key)
733 channel->internal.curr_key = key;
734 channel->cipher = silc_cipher_get_name(key->send_key);
735 channel->hmac = silc_hmac_get_name(key->hmac);
738 /***************************** Utility routines *****************************/
740 /* Returns the SilcChannelUser entry if the `client_entry' is joined on the
741 channel indicated by the `channel'. NULL if client is not joined on
744 SilcChannelUser silc_client_on_channel(SilcChannelEntry channel,
745 SilcClientEntry client_entry)
749 if (silc_hash_table_find(channel->user_list, client_entry, NULL,
756 /* Adds client to channel. Returns TRUE if user was added or is already
757 added to the channel, FALSE on error. Must be called with both `channel'
758 and `client_entry' locked. */
760 SilcBool silc_client_add_to_channel(SilcClient client,
761 SilcClientConnection conn,
762 SilcChannelEntry channel,
763 SilcClientEntry client_entry,
768 if (silc_client_on_channel(channel, client_entry))
771 SILC_LOG_DEBUG(("Add client %s to channel", client_entry->nickname));
773 chu = silc_calloc(1, sizeof(*chu));
777 chu->client = client_entry;
778 chu->channel = channel;
781 silc_client_ref_client(client, conn, client_entry);
782 silc_client_ref_channel(client, conn, channel);
784 silc_hash_table_add(channel->user_list, client_entry, chu);
785 silc_hash_table_add(client_entry->channels, channel, chu);
790 /* Removes client from a channel. Returns FALSE if user is not on channel.
791 This handles entry locking internally. */
793 SilcBool silc_client_remove_from_channel(SilcClient client,
794 SilcClientConnection conn,
795 SilcChannelEntry channel,
796 SilcClientEntry client_entry)
800 chu = silc_client_on_channel(channel, client_entry);
804 SILC_LOG_DEBUG(("Remove client %s from channel", client_entry->nickname));
806 silc_rwlock_wrlock(client_entry->internal.lock);
807 silc_rwlock_wrlock(channel->internal.lock);
809 silc_hash_table_del(chu->client->channels, chu->channel);
810 silc_hash_table_del(chu->channel->user_list, chu->client);
813 /* If channel became empty, delete it */
814 if (!silc_hash_table_count(channel->user_list))
815 silc_client_del_channel(client, conn, channel);
817 silc_rwlock_unlock(client_entry->internal.lock);
818 silc_rwlock_unlock(channel->internal.lock);
820 silc_client_unref_client(client, conn, client_entry);
821 silc_client_unref_channel(client, conn, channel);
826 /* Removes a client entry from all channels it has joined. This handles
827 entry locking internally. */
829 void silc_client_remove_from_channels(SilcClient client,
830 SilcClientConnection conn,
831 SilcClientEntry client_entry)
833 SilcHashTableList htl;
836 if (!silc_hash_table_count(client_entry->channels))
839 SILC_LOG_DEBUG(("Remove client from all joined channels"));
841 silc_rwlock_wrlock(client_entry->internal.lock);
843 silc_hash_table_list(client_entry->channels, &htl);
844 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
845 silc_rwlock_wrlock(chu->channel->internal.lock);
847 silc_hash_table_del(chu->client->channels, chu->channel);
848 silc_hash_table_del(chu->channel->user_list, chu->client);
850 /* If channel became empty, delete it */
851 if (!silc_hash_table_count(chu->channel->user_list))
852 silc_client_del_channel(client, conn, chu->channel);
854 silc_rwlock_unlock(chu->channel->internal.lock);
856 silc_client_unref_client(client, conn, chu->client);
857 silc_client_unref_channel(client, conn, chu->channel);
861 silc_rwlock_unlock(client_entry->internal.lock);
863 silc_hash_table_list_reset(&htl);
866 /* Empties channel from users. This handles entry locking internally. */
868 void silc_client_empty_channel(SilcClient client,
869 SilcClientConnection conn,
870 SilcChannelEntry channel)
872 SilcHashTableList htl;
875 silc_rwlock_wrlock(channel->internal.lock);
877 silc_hash_table_list(channel->user_list, &htl);
878 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
879 silc_hash_table_del(chu->client->channels, chu->channel);
880 silc_hash_table_del(chu->channel->user_list, chu->client);
881 silc_client_unref_client(client, conn, chu->client);
882 silc_client_unref_channel(client, conn, chu->channel);
886 silc_rwlock_unlock(channel->internal.lock);
888 silc_hash_table_list_reset(&htl);
891 /* Save public keys to channel public key list. Removes keys that are
892 marked to be removed. Must be called with `channel' locked. */
894 SilcBool silc_client_channel_save_public_keys(SilcChannelEntry channel,
895 unsigned char *chpk_list,
896 SilcUInt32 chpk_list_len,
899 SilcArgumentDecodedList a, b;
904 /* Remove all channel public keys */
905 if (!channel->channel_pubkeys)
908 silc_dlist_start(channel->channel_pubkeys);
909 while ((b = silc_dlist_get(channel->channel_pubkeys)))
910 silc_dlist_del(channel->channel_pubkeys, b);
912 silc_dlist_uninit(channel->channel_pubkeys);
913 channel->channel_pubkeys = NULL;
918 /* Parse channel public key list and add or remove public keys */
919 chpks = silc_argument_list_parse_decoded(chpk_list, chpk_list_len,
920 SILC_ARGUMENT_PUBLIC_KEY);
924 if (!channel->channel_pubkeys) {
925 channel->channel_pubkeys = silc_dlist_init();
926 if (!channel->channel_pubkeys) {
927 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
932 silc_dlist_start(chpks);
933 while ((a = silc_dlist_get(chpks))) {
935 silc_dlist_start(channel->channel_pubkeys);
936 while ((b = silc_dlist_get(channel->channel_pubkeys))) {
937 if (silc_pkcs_public_key_compare(a->argument, b->argument)) {
943 if ((a->arg_type == 0x00 || a->arg_type == 0x03) && !found) {
944 silc_dlist_add(channel->channel_pubkeys, a);
945 silc_dlist_del(chpks, a);
946 } else if (a->arg_type == 0x01 && found) {
947 silc_dlist_del(channel->channel_pubkeys, b);
951 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);