From 9a85416f729ef965606a688fffb6baa9d22927a5 Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Thu, 31 Jan 2002 20:30:24 +0000 Subject: [PATCH] updates. --- CHANGES | 29 +++ TODO | 5 + apps/irssi/src/silc/core/client_ops.c | 27 ++- apps/irssi/src/silc/core/silc-channels.c | 11 +- apps/silcd/packet_receive.c | 2 + apps/silcd/packet_send.c | 5 + apps/silcd/server.c | 14 +- apps/silcd/server_util.c | 18 +- lib/silcclient/client.c | 105 ++-------- lib/silcclient/client_channel.c | 75 +++---- lib/silcclient/client_internal.h | 8 +- lib/silcclient/client_notify.c | 103 ++++----- lib/silcclient/client_prvmsg.c | 10 +- lib/silcclient/command.c | 39 ++-- lib/silcclient/command_reply.c | 256 ++++++++++------------- lib/silcclient/idlist.c | 121 +++++++---- lib/silcclient/idlist.h | 37 ++-- lib/silcclient/silcapi.h | 27 ++- lib/silcutil/silchashtable.c | 12 ++ lib/silcutil/silchashtable.h | 26 ++- win32/libsilc/libsilc.def | 1 + win32/libsilcclient/libsilcclient.def | 1 + 22 files changed, 475 insertions(+), 457 deletions(-) diff --git a/CHANGES b/CHANGES index 2b9eefd7..ef1aca76 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,32 @@ +Thu Jan 31 19:06:22 EET 2002 Pekka Riikonen + + * Added function silc_client_add_channel, + silc_client_replace_channel_id, and removed functions + silc_client_new_channel_id and silc_idlist_get_channel_by_id + from client library. + + * Added cross reference of the joined channels to the + SilcClientEntry, and changed the SilcChannelEntry's + users list to SilcHashTable. The affected files are + lib/silcclient/idlist.[ch]. + + * Fixed a bug in hash table tarversing. While the hash table + is traversed with SilcHashTableList the table must not be + rehashed. It is now guaranteed that auto rehashable tables + are not rehashed while tarversing the list. Also defined that + silc_hash_table_rehash must not be called while tarversing + the table. Added function silc_hash_table_list_reset that must + be called after the tarversing is over. The affected files are + lib/silcutil/silchashtable.[ch]. + + * Changed all hash table traversing to call the new + silc_hash_table_list_reset in server and in client library. + + * Added function silc_client_on_channel to return the + SilcChannelUser entry if the specified client entry is joined + on the specified channel. This is exported to application as + well. Affected files lib/silcclient/client_channel.c, silcapi.h. + Wed Jan 30 19:14:31 EET 2002 Pekka Riikonen * Fixed founder regaining problem with JOIN command on normal diff --git a/TODO b/TODO index a7b0f3af..a7f03538 100644 --- a/TODO +++ b/TODO @@ -51,6 +51,11 @@ TODO/bugs In SILC Client Library TODO/bugs In SILC Server ======================== + o If server send CUMODE_CHANGE notify (like setting founder) to router + and router does not have founder on channel (founder is left or there's + no founder on channel at all), the router will accept the server's + founder mode change, even though it perhaps should not do that. + o Make the normal server save user counts with LIST command reply. o The router should check for validity of received notify packets from diff --git a/apps/irssi/src/silc/core/client_ops.c b/apps/irssi/src/silc/core/client_ops.c index 448109cc..5ece9892 100644 --- a/apps/irssi/src/silc/core/client_ops.c +++ b/apps/irssi/src/silc/core/client_ops.c @@ -94,17 +94,10 @@ void silc_channel_message(SilcClient client, SilcClientConnection conn, nick = silc_nicklist_find(chanrec, sender); if (!nick) { - /* We didn't find client but it clearly exists, add it. It must be - found on the channel->clients list. */ - SilcChannelUser chu; - - silc_list_start(channel->clients); - while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) { - if (chu->client == sender) { - nick = silc_nicklist_insert(chanrec, chu, FALSE); - break; - } - } + /* We didn't find client but it clearly exists, add it. */ + SilcChannelUser chu = silc_client_on_channel(channel, sender); + if (chu) + nick = silc_nicklist_insert(chanrec, chu, FALSE); } if (flags & SILC_MESSAGE_FLAG_ACTION) @@ -295,6 +288,7 @@ static void silc_client_join_get_users(SilcClient client, void *context) { SilcChannelEntry channel = (SilcChannelEntry)context; + SilcHashTableList htl; SilcChannelUser chu; SILC_SERVER_REC *server = conn->context; SILC_CHANNEL_REC *chanrec; @@ -308,14 +302,15 @@ static void silc_client_join_get_users(SilcClient client, if (chanrec == NULL) return; - silc_list_start(channel->clients); - while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) { + silc_hash_table_list(channel->user_list, &htl); + while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { if (!chu->client->nickname) continue; if (chu->mode & SILC_CHANNEL_UMODE_CHANFO) founder = chu->client; silc_nicklist_insert(chanrec, chu, FALSE); } + silc_hash_table_list_reset(&htl); ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry)); nicklist_set_own(CHANNEL(chanrec), ownnick); @@ -753,6 +748,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, case SILC_COMMAND_USERS: { + SilcHashTableList htl; SilcChannelEntry channel; SilcChannelUser chu; @@ -765,8 +761,8 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, MSGLEVEL_CRAP, SILCTXT_USERS_HEADER, channel->channel_name); - silc_list_start(channel->clients); - while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) { + silc_hash_table_list(channel->user_list, &htl); + while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { SilcClientEntry e = chu->client; char stat[5], *mode; @@ -791,6 +787,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, if (mode) silc_free(mode); } + silc_hash_table_list_reset(&htl); } break; diff --git a/apps/irssi/src/silc/core/silc-channels.c b/apps/irssi/src/silc/core/silc-channels.c index 5e52a6bb..fa50947d 100644 --- a/apps/irssi/src/silc/core/silc-channels.c +++ b/apps/irssi/src/silc/core/silc-channels.c @@ -151,14 +151,9 @@ static void event_join(SILC_SERVER_REC *server, va_list va) } else { chanrec = silc_channel_find_entry(server, channel); if (chanrec != NULL) { - SilcChannelUser user; - - silc_list_start(chanrec->entry->clients); - while ((user = silc_list_get(chanrec->entry->clients)) != NULL) - if (user->client == client) { - nickrec = silc_nicklist_insert(chanrec, user, TRUE); - break; - } + SilcChannelUser chu = silc_client_on_channel(channel, client); + if (chu) + nickrec = silc_nicklist_insert(chanrec, chu, TRUE); } } diff --git a/apps/silcd/packet_receive.c b/apps/silcd/packet_receive.c index 442dd310..d1f6db8a 100644 --- a/apps/silcd/packet_receive.c +++ b/apps/silcd/packet_receive.c @@ -630,6 +630,7 @@ void silc_server_notify(SilcServer server, if (chl2) { chl2->mode = mode; silc_free(channel_id); + silc_hash_table_list_reset(&htl); goto out; } } @@ -650,6 +651,7 @@ void silc_server_notify(SilcServer server, chl2 = chl; } } + silc_hash_table_list_reset(&htl); /* Send the same notify to the channel */ if (!notify_sent) diff --git a/apps/silcd/packet_send.c b/apps/silcd/packet_send.c index 0860b68e..2c8786c3 100644 --- a/apps/silcd/packet_send.c +++ b/apps/silcd/packet_send.c @@ -661,6 +661,7 @@ void silc_server_packet_send_to_channel(SilcServer server, force_send); } + silc_hash_table_list_reset(&htl); silc_free(routed); silc_free(packetdata.src_id); silc_free(packetdata.dst_id); @@ -943,6 +944,7 @@ void silc_server_packet_relay_to_channel(SilcServer server, force_send); } + silc_hash_table_list_reset(&htl); silc_free(routed); silc_free(packetdata.src_id); silc_free(packetdata.dst_id); @@ -981,6 +983,7 @@ void silc_server_packet_send_local_channel(SilcServer server, force_send); } } + silc_hash_table_list_reset(&htl); } /* Routine used to send (relay, route) private messages to some destination. @@ -1613,8 +1616,10 @@ void silc_server_send_notify_on_channels(SilcServer server, sent_clients[sent_clients_count++] = c; } } + silc_hash_table_list_reset(&htl2); } + silc_hash_table_list_reset(&htl); silc_free(routed); silc_free(sent_clients); silc_free(packetdata.src_id); diff --git a/apps/silcd/server.c b/apps/silcd/server.c index 091a9436..d033284d 100644 --- a/apps/silcd/server.c +++ b/apps/silcd/server.c @@ -2604,6 +2604,7 @@ void silc_server_remove_from_channels(SilcServer server, silc_hash_table_del(channel->user_list, chl2->client); silc_free(chl2); } + silc_hash_table_list_reset(&htl2); continue; } @@ -2628,7 +2629,7 @@ void silc_server_remove_from_channels(SilcServer server, if (keygen && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) { /* Re-generate channel key */ if (!silc_server_create_channel_key(server, channel, 0)) - return; + goto out; /* Send the channel key to the channel. The key of course is not sent to the client who was removed from the channel. */ @@ -2638,6 +2639,8 @@ void silc_server_remove_from_channels(SilcServer server, } } + out: + silc_hash_table_list_reset(&htl); silc_buffer_free(clidp); } @@ -2724,6 +2727,7 @@ int silc_server_remove_from_one_channel(SilcServer server, silc_hash_table_del(channel->user_list, chl2->client); silc_free(chl2); } + silc_hash_table_list_reset(&htl2); return FALSE; } @@ -3005,7 +3009,7 @@ bool silc_server_create_channel_key(SilcServer server, channel->rekey->task = silc_schedule_task_add(server->schedule, 0, silc_server_channel_key_rekey, - (void *)channel->rekey, 36, 0, + (void *)channel->rekey, 3600, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); } @@ -3117,7 +3121,7 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server, channel->rekey->task = silc_schedule_task_add(server->schedule, 0, silc_server_channel_key_rekey, - (void *)channel->rekey, 36, 0, + (void *)channel->rekey, 3600, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); } @@ -3433,6 +3437,7 @@ void silc_server_announce_get_channel_users(SilcServer server, silc_buffer_free(clidp); } + silc_hash_table_list_reset(&htl); silc_buffer_free(chidp); } @@ -3676,6 +3681,7 @@ void silc_server_get_users_on_channel(SilcServer server, silc_hash_table_list(channel->user_list, &htl); while (silc_hash_table_get(&htl, NULL, (void *)&chl)) len += (silc_id_get_len(chl->client->id, SILC_ID_CLIENT) + 4); + silc_hash_table_list_reset(&htl); client_id_list = silc_buffer_alloc(len); client_mode_list = @@ -3697,6 +3703,7 @@ void silc_server_get_users_on_channel(SilcServer server, list_count++; } + silc_hash_table_list_reset(&htl); silc_buffer_push(client_id_list, client_id_list->data - client_id_list->head); silc_buffer_push(client_mode_list, @@ -3921,6 +3928,7 @@ SilcBuffer silc_server_get_client_channel_list(SilcServer server, silc_buffer_pull(buffer, len); silc_free(cid); } + silc_hash_table_list_reset(&htl); if (buffer) silc_buffer_push(buffer, buffer->data - buffer->head); diff --git a/apps/silcd/server_util.c b/apps/silcd/server_util.c index ad856b4a..5c06bcd1 100644 --- a/apps/silcd/server_util.c +++ b/apps/silcd/server_util.c @@ -105,6 +105,7 @@ static void silc_server_remove_clients_channels(SilcServer server, silc_hash_table_del(channel->user_list, chl2->client); silc_free(chl2); } + silc_hash_table_list_reset(&htl2); continue; } @@ -121,6 +122,7 @@ static void silc_server_remove_clients_channels(SilcServer server, if (!silc_hash_table_find(channels, channel, NULL, NULL)) silc_hash_table_add(channels, channel, channel); } + silc_hash_table_list_reset(&htl); silc_buffer_free(clidp); } @@ -340,8 +342,11 @@ bool silc_server_remove_clients_by_server(SilcServer server, must re-generate the channel key. */ silc_hash_table_list(channels, &htl); while (silc_hash_table_get(&htl, NULL, (void *)&channel)) { - if (!silc_server_create_channel_key(server, channel, 0)) + if (!silc_server_create_channel_key(server, channel, 0)) { + silc_hash_table_list_reset(&htl); + silc_hash_table_free(channels); return FALSE; + } /* Do not send the channel key if private channel key mode is set */ if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) @@ -351,6 +356,7 @@ bool silc_server_remove_clients_by_server(SilcServer server, server->server_type == SILC_ROUTER ? FALSE : !server->standalone); } + silc_hash_table_list_reset(&htl); silc_hash_table_free(channels); return TRUE; @@ -699,9 +705,12 @@ bool silc_server_channel_has_global(SilcChannelEntry channel) silc_hash_table_list(channel->user_list, &htl); while (silc_hash_table_get(&htl, NULL, (void *)&chl)) { - if (chl->client->router) + if (chl->client->router) { + silc_hash_table_list_reset(&htl); return TRUE; + } } + silc_hash_table_list_reset(&htl); return FALSE; } @@ -716,9 +725,12 @@ bool silc_server_channel_has_local(SilcChannelEntry channel) silc_hash_table_list(channel->user_list, &htl); while (silc_hash_table_get(&htl, NULL, (void *)&chl)) { - if (!chl->client->router) + if (!chl->client->router) { + silc_hash_table_list_reset(&htl); return TRUE; + } } + silc_hash_table_list_reset(&htl); return FALSE; } diff --git a/lib/silcclient/client.c b/lib/silcclient/client.c index d5867f13..ddd12852 100644 --- a/lib/silcclient/client.c +++ b/lib/silcclient/client.c @@ -1516,7 +1516,10 @@ void silc_client_receive_new_id(SilcClient client, conn->local_entry->server = strdup(conn->remote_host); conn->local_entry->id = conn->local_id; conn->local_entry->valid = TRUE; - + conn->local_entry->channels = silc_hash_table_alloc(1, silc_hash_ptr, + NULL, NULL, + NULL, NULL, NULL, TRUE); + /* Put it to the ID cache */ silc_idcache_add(conn->client_cache, strdup(conn->nickname), conn->local_id, (void *)conn->local_entry, 0, NULL); @@ -1545,73 +1548,22 @@ void silc_client_receive_new_id(SilcClient client, } } -/* Processed received Channel ID for a channel. This is called when client - joins to channel and server replies with channel ID. The ID is cached. - Returns the created channel entry. This is also called when received - channel ID in for example USERS command reply that we do not have. */ - -SilcChannelEntry silc_client_new_channel_id(SilcClient client, - SilcSocketConnection sock, - char *channel_name, - uint32 mode, - SilcIDPayload idp) -{ - SilcClientConnection conn = (SilcClientConnection)sock->user_data; - SilcChannelEntry channel; - - SILC_LOG_DEBUG(("New channel ID")); - - channel = silc_calloc(1, sizeof(*channel)); - channel->channel_name = channel_name; - channel->id = silc_id_payload_get_id(idp); - channel->mode = mode; - silc_list_init(channel->clients, struct SilcChannelUserStruct, next); - - /* Put it to the ID cache */ - silc_idcache_add(conn->channel_cache, channel->channel_name, - (void *)channel->id, (void *)channel, 0, NULL); - - return channel; -} - -/* Removes a client entry from all channel it has joined. This really is - a performance killer (client_entry should have pointers to channel - entry list). */ +/* Removes a client entry from all channels it has joined. */ void silc_client_remove_from_channels(SilcClient client, SilcClientConnection conn, SilcClientEntry client_entry) { - SilcIDCacheEntry id_cache; - SilcIDCacheList list; - SilcChannelEntry channel; + SilcHashTableList htl; SilcChannelUser chu; - if (!silc_idcache_get_all(conn->channel_cache, &list)) - return; - - silc_idcache_list_first(list, &id_cache); - channel = (SilcChannelEntry)id_cache->context; - - while (channel) { - - /* Remove client from channel */ - silc_list_start(channel->clients); - while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) { - if (chu->client == client_entry) { - silc_list_del(channel->clients, chu); - silc_free(chu); - break; - } - } - - if (!silc_idcache_list_next(list, &id_cache)) - break; - - channel = (SilcChannelEntry)id_cache->context; + silc_hash_table_list(client_entry->channels, &htl); + while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { + silc_hash_table_del(chu->client->channels, chu->channel); + silc_hash_table_del(chu->channel->user_list, chu->client); + silc_free(chu); } - - silc_idcache_list_free(list); + silc_hash_table_list_reset(&htl); } /* Replaces `old' client entries from all channels to `new' client entry. @@ -1624,35 +1576,20 @@ void silc_client_replace_from_channels(SilcClient client, SilcClientEntry old, SilcClientEntry new) { - SilcIDCacheEntry id_cache; - SilcIDCacheList list; - SilcChannelEntry channel; + SilcHashTableList htl; SilcChannelUser chu; - if (!silc_idcache_get_all(conn->channel_cache, &list)) - return; - - silc_idcache_list_first(list, &id_cache); - channel = (SilcChannelEntry)id_cache->context; - - while (channel) { - + silc_hash_table_list(old->channels, &htl); + while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { /* Replace client entry */ - silc_list_start(channel->clients); - while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) { - if (chu->client == old) { - chu->client = new; - break; - } - } - - if (!silc_idcache_list_next(list, &id_cache)) - break; + silc_hash_table_del(chu->client->channels, chu->channel); + silc_hash_table_del(chu->channel->user_list, chu->client); - channel = (SilcChannelEntry)id_cache->context; + chu->client = new; + silc_hash_table_add(chu->channel->user_list, chu->client, chu); + silc_hash_table_add(chu->client->channels, chu->channel, chu); } - - silc_idcache_list_free(list); + silc_hash_table_list_reset(&htl); } /* Registers failure timeout to process the received failure packet diff --git a/lib/silcclient/client_channel.c b/lib/silcclient/client_channel.c index 0f952373..814dea43 100644 --- a/lib/silcclient/client_channel.c +++ b/lib/silcclient/client_channel.c @@ -170,15 +170,13 @@ static void silc_client_channel_message_cb(SilcClient client, SilcChannelClientResolve res = (SilcChannelClientResolve)context; if (clients_count == 1) { - SilcIDCacheEntry id_cache = NULL; SilcChannelEntry channel; unsigned char *message; - if (!silc_idcache_find_by_id_one(conn->channel_cache, res->channel_id, - &id_cache)) + channel = silc_client_get_channel_by_id(client, conn, res->channel_id); + if (!channel) goto out; - channel = (SilcChannelEntry)id_cache->context; message = silc_channel_message_get_data(res->payload, NULL); /* Pass the message to application */ @@ -207,10 +205,8 @@ void silc_client_channel_message(SilcClient client, SilcChannelMessagePayload payload = NULL; SilcChannelID *id = NULL; SilcChannelEntry channel; - SilcChannelUser chu; - SilcIDCacheEntry id_cache = NULL; + SilcClientEntry client_entry; SilcClientID *client_id = NULL; - bool found = FALSE; unsigned char *message; SILC_LOG_DEBUG(("Start")); @@ -228,11 +224,10 @@ void silc_client_channel_message(SilcClient client, goto out; /* Find the channel entry from channels on this connection */ - if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)id, &id_cache)) + channel = silc_client_get_channel_by_id(client, conn, id); + if (!channel) goto out; - channel = (SilcChannelEntry)id_cache->context; - /* If there is no channel private key then just decrypt the message with the channel key. If private keys are set then just go through all private keys and check what decrypts correctly. */ @@ -274,16 +269,8 @@ void silc_client_channel_message(SilcClient client, } /* Find client entry */ - silc_list_start(channel->clients); - while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) { - if (SILC_ID_CLIENT_COMPARE(chu->client->id, client_id) && - chu->client->nickname) { - found = TRUE; - break; - } - } - - if (!found) { + client_entry = silc_client_get_client_by_id(client, conn, client_id); + if (!client_entry || !client_entry->nickname) { /* Resolve the client info */ SilcChannelClientResolve res = silc_calloc(1, sizeof(*res)); res->payload = payload; @@ -296,19 +283,22 @@ void silc_client_channel_message(SilcClient client, goto out; } + if (!silc_client_on_channel(channel, client_entry)) { + SILC_LOG_WARNING(("Received channel message from client not on channel")); + goto out; + } + message = silc_channel_message_get_data(payload, NULL); /* Pass the message to application */ client->internal->ops->channel_message( - client, conn, chu->client, channel, + client, conn, client_entry, channel, silc_channel_message_get_flags(payload), message); out: - if (id) - silc_free(id); - if (client_id) - silc_free(client_id); + silc_free(id); + silc_free(client_id); if (payload) silc_channel_message_payload_free(payload); } @@ -334,14 +324,14 @@ SILC_TASK_CALLBACK(silc_client_save_channel_key_rekey) receive Channel Key Payload and when we are processing JOIN command reply. */ -void silc_client_save_channel_key(SilcClientConnection conn, +void silc_client_save_channel_key(SilcClient client, + SilcClientConnection conn, SilcBuffer key_payload, SilcChannelEntry channel) { unsigned char *id_string, *key, *cipher, *hmac, hash[32]; uint32 tmp_len; SilcChannelID *id; - SilcIDCacheEntry id_cache = NULL; SilcChannelKeyPayload payload; payload = silc_channel_key_payload_parse(key_payload->data, @@ -363,12 +353,9 @@ void silc_client_save_channel_key(SilcClientConnection conn, /* Find channel. */ if (!channel) { - if (!silc_idcache_find_by_id_one(conn->channel_cache, - (void *)id, &id_cache)) + channel = silc_client_get_channel_by_id(client, conn, id); + if (!channel) goto out; - - /* Get channel entry */ - channel = (SilcChannelEntry)id_cache->context; } hmac = (channel->hmac ? (char *)silc_hmac_get_name(channel->hmac) : @@ -382,11 +369,11 @@ void silc_client_save_channel_key(SilcClientConnection conn, if (channel->old_hmac) silc_hmac_free(channel->old_hmac); if (channel->rekey_task) - silc_schedule_task_del(conn->client->schedule, channel->rekey_task); + silc_schedule_task_del(client->schedule, channel->rekey_task); channel->old_channel_key = channel->channel_key; channel->old_hmac = channel->hmac; channel->rekey_task = - silc_schedule_task_add(conn->client->schedule, 0, + silc_schedule_task_add(client->schedule, 0, silc_client_save_channel_key_rekey, channel, 10, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); @@ -401,7 +388,7 @@ void silc_client_save_channel_key(SilcClientConnection conn, memcpy(channel->key, key, tmp_len); if (!silc_cipher_alloc(cipher, &channel->channel_key)) { - conn->client->internal->ops->say( + client->internal->ops->say( conn->client, conn, SILC_CLIENT_MESSAGE_AUDIT, "Cannot talk to channel: unsupported cipher %s", @@ -437,7 +424,7 @@ void silc_client_receive_channel_key(SilcClient client, SILC_LOG_DEBUG(("Received key for channel")); /* Save the key */ - silc_client_save_channel_key(sock->user_data, packet, NULL); + silc_client_save_channel_key(client, sock->user_data, packet, NULL); } /* Adds private key for channel. This may be set only if the channel's mode @@ -659,3 +646,19 @@ void silc_client_free_channel_private_keys(SilcChannelPrivateKey *keys, { silc_free(keys); } + +/* Returns the SilcChannelUser entry if the `client_entry' is joined on the + channel indicated by the `channel'. NULL if client is not joined on + the channel. */ + +SilcChannelUser silc_client_on_channel(SilcChannelEntry channel, + SilcClientEntry client_entry) +{ + SilcChannelUser chu; + + if (silc_hash_table_find(channel->user_list, client_entry, NULL, + (void *)&chu)) + return chu; + + return NULL; +} diff --git a/lib/silcclient/client_internal.h b/lib/silcclient/client_internal.h index f796cb10..6471d8c0 100644 --- a/lib/silcclient/client_internal.h +++ b/lib/silcclient/client_internal.h @@ -164,12 +164,8 @@ void silc_client_error_by_server(SilcClient client, void silc_client_receive_new_id(SilcClient client, SilcSocketConnection sock, SilcIDPayload idp); -SilcChannelEntry silc_client_new_channel_id(SilcClient client, - SilcSocketConnection sock, - char *channel_name, - uint32 mode, - SilcIDPayload idp); -void silc_client_save_channel_key(SilcClientConnection conn, +void silc_client_save_channel_key(SilcClient client, + SilcClientConnection conn, SilcBuffer key_payload, SilcChannelEntry channel); void silc_client_receive_channel_key(SilcClient client, diff --git a/lib/silcclient/client_notify.c b/lib/silcclient/client_notify.c index d2895494..360da04a 100644 --- a/lib/silcclient/client_notify.c +++ b/lib/silcclient/client_notify.c @@ -103,7 +103,6 @@ void silc_client_notify_by_server(SilcClient client, SilcChannelEntry channel; SilcChannelUser chu; SilcServerEntry server; - SilcIDCacheEntry id_cache = NULL; unsigned char *tmp; uint32 tmp_len, mode; @@ -143,10 +142,7 @@ void silc_client_notify_by_server(SilcClient client, goto out; /* Get the channel entry */ - channel = NULL; - if (silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id, - &id_cache)) - channel = (SilcChannelEntry)id_cache->context; + channel = silc_client_get_channel_by_id(client, conn, channel_id); /* Get sender Client ID */ tmp = silc_argument_get_arg_type(args, 3, &tmp_len); @@ -222,17 +218,17 @@ void silc_client_notify_by_server(SilcClient client, goto out; /* Get channel entry */ - if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id, - &id_cache)) + channel = silc_client_get_channel_by_id(client, conn, channel_id); + if (!channel) break; - channel = (SilcChannelEntry)id_cache->context; - - /* Add client to channel */ - if (client_entry != conn->local_entry) { + /* Join the client to channel */ + if (!silc_client_on_channel(channel, client_entry)) { chu = silc_calloc(1, sizeof(*chu)); chu->client = client_entry; - silc_list_add(channel->clients, chu); + chu->channel = channel; + silc_hash_table_add(channel->user_list, client_entry, chu); + silc_hash_table_add(client_entry->channels, channel, chu); } /* Notify application. The channel entry is sent last as this notify @@ -269,20 +265,16 @@ void silc_client_notify_by_server(SilcClient client, SILC_ID_CHANNEL); if (!channel_id) goto out; - if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id, - &id_cache)) + channel = silc_client_get_channel_by_id(client, conn, channel_id); + if (!channel) break; - channel = (SilcChannelEntry)id_cache->context; - /* Remove client from channel */ - silc_list_start(channel->clients); - while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) { - if (chu->client == client_entry) { - silc_list_del(channel->clients, chu); - silc_free(chu); - break; - } + chu = silc_client_on_channel(channel, client_entry); + if (chu) { + silc_hash_table_del(client_entry->channels, channel); + silc_hash_table_del(channel->user_list, client_entry); + silc_free(chu); } /* Notify application. The channel entry is sent last as this notify @@ -406,12 +398,10 @@ void silc_client_notify_by_server(SilcClient client, SILC_ID_CHANNEL); if (!channel_id) goto out; - if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id, - &id_cache)) + channel = silc_client_get_channel_by_id(client, conn, channel_id); + if (!channel) break; - channel = (SilcChannelEntry)id_cache->context; - /* Notify application. The channel entry is sent last as this notify is for channel but application don't know it from the arguments sent by server. */ @@ -562,14 +552,12 @@ void silc_client_notify_by_server(SilcClient client, silc_id_payload_free(idp); goto out; } - if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id, - &id_cache)) { + channel = silc_client_get_channel_by_id(client, conn, channel_id); + if (!channel) { silc_id_payload_free(idp); goto out; } - channel = (SilcChannelEntry)id_cache->context; - /* Save the new mode */ channel->mode = mode; @@ -652,20 +640,14 @@ void silc_client_notify_by_server(SilcClient client, SILC_ID_CHANNEL); if (!channel_id) goto out; - if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id, - &id_cache)) + channel = silc_client_get_channel_by_id(client, conn, channel_id); + if (!channel) break; - channel = (SilcChannelEntry)id_cache->context; - /* Save the mode */ - silc_list_start(channel->clients); - while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) { - if (chu->client == client_entry) { - chu->mode = mode; - break; - } - } + chu = silc_client_on_channel(channel, client_entry); + if (chu) + chu->mode = mode; /* Notify application. The channel entry is sent last as this notify is for channel but application don't know it from the arguments @@ -706,37 +688,24 @@ void silc_client_notify_by_server(SilcClient client, channel_id = silc_id_payload_parse_id(tmp, tmp_len); if (!channel_id) goto out; - - /* Get the channel entry */ - if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id, - &id_cache)) - break; - - channel = (SilcChannelEntry)id_cache->context; - - SILC_LOG_DEBUG(("Old Channel ID id(%s)", - silc_id_render(channel->id, SILC_ID_CHANNEL))); - /* Remove the old channel entry */ - silc_idcache_del_by_context(conn->channel_cache, channel); + /* Get the channel entry */ + channel = silc_client_get_channel_by_id(client, conn, channel_id); + if (!channel) + goto out; - /* Free the old ID */ - silc_free(channel->id); + silc_free(channel_id); /* Get the new ID */ tmp = silc_argument_get_arg_type(args, 2, &tmp_len); if (!tmp) goto out; - channel->id = silc_id_payload_parse_id(tmp, tmp_len); - if (!channel->id) + channel_id = silc_id_payload_parse_id(tmp, tmp_len); + if (!channel_id) goto out; - SILC_LOG_DEBUG(("New Channel ID id(%s)", - silc_id_render(channel->id, SILC_ID_CHANNEL))); - - /* Add the channel entry again to ID cache */ - silc_idcache_add(conn->channel_cache, channel->channel_name, - channel->id, channel, 0, NULL); + /* Replace the Channel ID */ + silc_client_replace_channel_id(client, conn, channel, channel_id); /* Notify application */ client->internal->ops->notify(client, conn, type, channel, channel); @@ -768,12 +737,10 @@ void silc_client_notify_by_server(SilcClient client, SILC_ID_CHANNEL); if (!channel_id) goto out; - if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id, - &id_cache)) + channel = silc_client_get_channel_by_id(client, conn, channel_id); + if (!channel) break; - channel = (SilcChannelEntry)id_cache->context; - /* Get the kicker */ tmp = silc_argument_get_arg_type(args, 3, &tmp_len); if (!tmp) diff --git a/lib/silcclient/client_prvmsg.c b/lib/silcclient/client_prvmsg.c index 45b785e2..9dc86214 100644 --- a/lib/silcclient/client_prvmsg.c +++ b/lib/silcclient/client_prvmsg.c @@ -161,13 +161,11 @@ void silc_client_private_message(SilcClient client, goto out; /* Check whether we know this client already */ - if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)remote_id, - NULL, NULL, - silc_hash_client_id_compare, NULL, - &id_cache) || + remote_client = silc_client_get_client_by_id(client, conn, remote_id); + if (!remote_client || ((SilcClientEntry)id_cache->context)->nickname == NULL) { - if (id_cache && id_cache->context) { + if (remote_client) { remote_client = (SilcClientEntry)id_cache->context; if (remote_client->status & SILC_CLIENT_STATUS_RESOLVING) { remote_client->status &= ~SILC_CLIENT_STATUS_RESOLVING; @@ -183,8 +181,6 @@ void silc_client_private_message(SilcClient client, return; } - remote_client = (SilcClientEntry)id_cache->context; - /* Parse the payload and decrypt it also if private message key is set */ payload = silc_private_message_payload_parse(packet->buffer->data, packet->buffer->len, diff --git a/lib/silcclient/command.c b/lib/silcclient/command.c index f91beae0..7c948383 100644 --- a/lib/silcclient/command.c +++ b/lib/silcclient/command.c @@ -947,7 +947,7 @@ SILC_CLIENT_CMD_FUNC(join) { SilcClientCommandContext cmd = (SilcClientCommandContext)context; SilcClientConnection conn = cmd->conn; - SilcIDCacheEntry id_cache = NULL; + SilcChannelEntry channel; SilcBuffer buffer, idp, auth = NULL; char *name, *passphrase = NULL, *cipher = NULL, *hmac = NULL; int i; @@ -964,12 +964,9 @@ SILC_CLIENT_CMD_FUNC(join) } /* See if we have joined to the requested channel already */ - if (silc_idcache_find_by_name_one(conn->channel_cache, cmd->argv[1], - &id_cache)) { - SilcChannelEntry channel = (SilcChannelEntry)id_cache->context; - if (channel->on_channel) - goto out; - } + channel = silc_client_get_channel(cmd->client, conn, cmd->argv[1]); + if (channel && silc_client_on_channel(channel, conn->local_entry)) + goto out; idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT); @@ -1467,13 +1464,9 @@ SILC_CLIENT_CMD_FUNC(cumode) } /* Get the current mode */ - silc_list_start(channel->clients); - while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) { - if (chu->client == client_entry) { - mode = chu->mode; - break; - } - } + chu = silc_client_on_channel(channel, client_entry); + if (chu) + mode = chu->mode; /* Are we adding or removing mode */ if (cmd->argv[2][0] == '-') @@ -1995,8 +1988,8 @@ SILC_CLIENT_CMD_FUNC(leave) { SilcClientCommandContext cmd = (SilcClientCommandContext)context; SilcClientConnection conn = cmd->conn; - SilcIDCacheEntry id_cache = NULL; SilcChannelEntry channel; + SilcChannelUser chu; SilcBuffer buffer, idp; char *name; @@ -2025,19 +2018,25 @@ SILC_CLIENT_CMD_FUNC(leave) name = cmd->argv[1]; } - /* Get the Channel ID of the channel */ - if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) { + /* Get the channel entry */ + channel = silc_client_get_channel(cmd->client, conn, name); + if (!channel) { SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on that channel"); COMMAND_ERROR; goto out; } - channel = (SilcChannelEntry)id_cache->context; - channel->on_channel = FALSE; + /* Remove us from channel */ + chu = silc_client_on_channel(channel, conn->local_entry); + if (chu) { + silc_hash_table_del(chu->client->channels, chu->channel); + silc_hash_table_del(chu->channel->user_list, chu->client); + silc_free(chu); + } /* Send LEAVE command to the server */ - idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL); + idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL); buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1, 1, idp->data, idp->len); silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, diff --git a/lib/silcclient/command_reply.c b/lib/silcclient/command_reply.c index 248a51d4..f5658994 100644 --- a/lib/silcclient/command_reply.c +++ b/lib/silcclient/command_reply.c @@ -211,7 +211,6 @@ silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd, { SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data; SilcClientID *client_id; - SilcIDCacheEntry id_cache = NULL; SilcClientEntry client_entry = NULL; int argc; uint32 len; @@ -266,16 +265,13 @@ silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd, fingerprint = silc_argument_get_arg_type(cmd->args, 9, &fingerprint_len); /* Check if we have this client cached already. */ - if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id, - NULL, NULL, - silc_hash_client_id_compare, NULL, - &id_cache)) { + client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id); + if (!client_entry) { SILC_LOG_DEBUG(("Adding new client entry")); client_entry = silc_client_add_client(cmd->client, conn, nickname, username, realname, client_id, mode); } else { - client_entry = (SilcClientEntry)id_cache->context; silc_client_update_client(cmd->client, conn, client_entry, nickname, username, realname, mode); silc_free(client_id); @@ -356,7 +352,6 @@ SILC_CLIENT_CMD_REPLY_FUNC(whowas) SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data; SilcCommandStatus status; SilcClientID *client_id; - SilcIDCacheEntry id_cache = NULL; SilcClientEntry client_entry = NULL; uint32 len; unsigned char *id_data; @@ -378,11 +373,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(whowas) } /* Get the client entry, if exists */ - if (silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id, - NULL, NULL, - silc_hash_client_id_compare, NULL, - &id_cache)) - client_entry = (SilcClientEntry)id_cache->context; + client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id); silc_free(client_id); nickname = silc_argument_get_arg_type(cmd->args, 3, &len); @@ -458,17 +449,13 @@ silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd, SILC_LOG_DEBUG(("Received client information")); /* Check if we have this client cached already. */ - if (!silc_idcache_find_by_id_one_ext(conn->client_cache, - (void *)client_id, - NULL, NULL, - silc_hash_client_id_compare, NULL, - &id_cache)) { + client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id); + if (!client_entry) { SILC_LOG_DEBUG(("Adding new client entry")); client_entry = silc_client_add_client(cmd->client, conn, name, info, NULL, silc_id_dup(client_id, id_type), 0); } else { - client_entry = (SilcClientEntry)id_cache->context; silc_client_update_client(cmd->client, conn, client_entry, name, info, NULL, 0); } @@ -517,16 +504,15 @@ silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd, SILC_LOG_DEBUG(("Received channel information")); /* Check if we have this channel cached already. */ - if (!silc_idcache_find_by_id_one(conn->channel_cache, - (void *)channel_id, &id_cache)) { + channel_entry = silc_client_get_channel_by_id(client, conn, channel_id); + if (!channel_entry) { if (!name) break; - SILC_LOG_DEBUG(("Adding new channel entry")); - channel_entry = silc_client_new_channel_id(client, conn->sock, - strdup(name), 0, idp); - } else { - channel_entry = (SilcChannelEntry)id_cache->context; + /* Add new channel entry */ + channel_entry = silc_client_add_channel(client, conn, name, 0, + channel_id); + channel_id = NULL; } /* Notify application */ @@ -680,7 +666,6 @@ SILC_CLIENT_CMD_REPLY_FUNC(topic) SilcCommandStatus status; SilcChannelEntry channel; SilcChannelID *channel_id = NULL; - SilcIDCacheEntry id_cache = NULL; unsigned char *tmp; char *topic; uint32 argc, len; @@ -714,15 +699,13 @@ SILC_CLIENT_CMD_REPLY_FUNC(topic) goto out; /* Get the channel entry */ - if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id, - &id_cache)) { + channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id); + if (!channel) { silc_free(channel_id); COMMAND_REPLY_ERROR; goto out; } - channel = (SilcChannelEntry)id_cache->context; - /* Notify application */ COMMAND_REPLY((ARGS, channel, topic)); @@ -740,7 +723,6 @@ SILC_CLIENT_CMD_REPLY_FUNC(invite) SilcCommandStatus status; SilcChannelEntry channel; SilcChannelID *channel_id; - SilcIDCacheEntry id_cache; unsigned char *tmp; uint32 len; @@ -763,14 +745,12 @@ SILC_CLIENT_CMD_REPLY_FUNC(invite) goto out; /* Get the channel entry */ - if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id, - &id_cache)) { + channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id); + if (!channel) { silc_free(channel_id); COMMAND_REPLY_ERROR; goto out; } - - channel = (SilcChannelEntry)id_cache->context; /* Get the invite list */ tmp = silc_argument_get_arg_type(cmd->args, 3, &len); @@ -941,11 +921,10 @@ SILC_CLIENT_CMD_REPLY_FUNC(join) SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context; SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data; SilcCommandStatus status; - SilcIDPayload idp = NULL; SilcChannelEntry channel; - SilcIDCacheEntry id_cache = NULL; SilcChannelUser chu; - uint32 argc, mode, len, list_count; + SilcChannelID *channel_id; + uint32 argc, mode = 0, len, list_count; char *topic, *tmp, *channel_name = NULL, *hmac; SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL; int i; @@ -977,7 +956,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(join) COMMAND_REPLY_ERROR; goto out; } - channel_name = strdup(tmp); + channel_name = tmp; /* Get Channel ID */ tmp = silc_argument_get_arg_type(cmd->args, 3, &len); @@ -985,13 +964,11 @@ SILC_CLIENT_CMD_REPLY_FUNC(join) SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "Cannot join channel: Bad reply packet"); COMMAND_REPLY_ERROR; - silc_free(channel_name); goto out; } - idp = silc_id_payload_parse(tmp, len); - if (!idp) { + channel_id = silc_id_payload_parse_id(tmp, len); + if (!channel_id) { COMMAND_REPLY_ERROR; - silc_free(channel_name); goto out; } @@ -999,8 +976,6 @@ SILC_CLIENT_CMD_REPLY_FUNC(join) tmp = silc_argument_get_arg_type(cmd->args, 5, NULL); if (tmp) SILC_GET32_MSB(mode, tmp); - else - mode = 0; /* Get channel key */ tmp = silc_argument_get_arg_type(cmd->args, 7, &len); @@ -1013,15 +988,16 @@ SILC_CLIENT_CMD_REPLY_FUNC(join) /* Get topic */ topic = silc_argument_get_arg_type(cmd->args, 10, NULL); - /* If we have the channel entry, remove it and create a new one */ + /* Check whether we have this channel entry already. */ channel = silc_client_get_channel(cmd->client, conn, channel_name); - if (channel) - silc_client_del_channel(cmd->client, conn, channel); - - /* Save received Channel ID. This actually creates the channel */ - channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name, - mode, idp); - silc_id_payload_free(idp); + if (channel) { + if (!SILC_ID_CHANNEL_COMPARE(channel->id, channel_id)) + silc_client_replace_channel_id(cmd->client, conn, channel, channel_id); + } else { + /* Create new channel entry */ + channel = silc_client_add_channel(cmd->client, conn, channel_name, + mode, channel_id); + } conn->current_channel = channel; @@ -1032,7 +1008,6 @@ SILC_CLIENT_CMD_REPLY_FUNC(join) SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "Cannot join channel: Unsupported HMAC `%s'", hmac); COMMAND_REPLY_ERROR; - silc_free(channel_name); goto out; } } @@ -1079,27 +1054,23 @@ SILC_CLIENT_CMD_REPLY_FUNC(join) SILC_GET32_MSB(mode, client_mode_list->data); /* Check if we have this client cached already. */ - if (!silc_idcache_find_by_id_one_ext(conn->client_cache, - (void *)client_id, - NULL, NULL, - silc_hash_client_id_compare, NULL, - &id_cache)) { + client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id); + if (!client_entry) { /* No, we don't have it, add entry for it. */ client_entry = silc_client_add_client(cmd->client, conn, NULL, NULL, NULL, silc_id_dup(client_id, SILC_ID_CLIENT), 0); - } else { - /* Yes, we have it already */ - client_entry = (SilcClientEntry)id_cache->context; } - /* Join the client to the channel */ + /* Join client to the channel */ chu = silc_calloc(1, sizeof(*chu)); chu->client = client_entry; + chu->channel = channel; chu->mode = mode; - silc_list_add(channel->clients, chu); - silc_free(client_id); + silc_hash_table_add(channel->user_list, client_entry, chu); + silc_hash_table_add(client_entry->channels, channel, chu); + silc_free(client_id); silc_buffer_pull(client_id_list, idp_len); silc_buffer_pull(client_mode_list, 4); } @@ -1109,11 +1080,8 @@ SILC_CLIENT_CMD_REPLY_FUNC(join) client_mode_list->head); /* Save channel key */ - if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) - silc_client_save_channel_key(conn, keyp, channel); - - /* Client is now joined to the channel */ - channel->on_channel = TRUE; + if (keyp && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) + silc_client_save_channel_key(cmd->client, conn, keyp, channel); /* Notify application */ COMMAND_REPLY((ARGS, channel_name, channel, mode, 0, @@ -1239,7 +1207,6 @@ SILC_CLIENT_CMD_REPLY_FUNC(cmode) SilcCommandStatus status; unsigned char *tmp; uint32 mode; - SilcIDCacheEntry id_cache; SilcChannelID *channel_id; SilcChannelEntry channel; uint32 len; @@ -1261,15 +1228,13 @@ SILC_CLIENT_CMD_REPLY_FUNC(cmode) goto out; /* Get the channel entry */ - if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id, - &id_cache)) { + channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id); + if (!channel) { silc_free(channel_id); COMMAND_REPLY_ERROR; goto out; } - channel = (SilcChannelEntry)id_cache->context; - /* Get channel mode */ tmp = silc_argument_get_arg_type(cmd->args, 3, NULL); if (!tmp) { @@ -1299,7 +1264,6 @@ SILC_CLIENT_CMD_REPLY_FUNC(cumode) SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context; SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data; SilcCommandStatus status; - SilcIDCacheEntry id_cache = NULL; SilcClientID *client_id; SilcChannelID *channel_id; SilcClientEntry client_entry; @@ -1332,15 +1296,13 @@ SILC_CLIENT_CMD_REPLY_FUNC(cumode) goto out; /* Get the channel entry */ - if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id, - &id_cache)) { + channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id); + if (!channel) { silc_free(channel_id); COMMAND_REPLY_ERROR; goto out; } - channel = (SilcChannelEntry)id_cache->context; - /* Get Client ID */ id = silc_argument_get_arg_type(cmd->args, 4, &len); if (!id) { @@ -1356,27 +1318,19 @@ SILC_CLIENT_CMD_REPLY_FUNC(cumode) } /* Get client entry */ - if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id, - NULL, NULL, - silc_hash_client_id_compare, NULL, - &id_cache)) { + client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id); + if (!client_entry) { silc_free(channel_id); silc_free(client_id); COMMAND_REPLY_ERROR; goto out; } - client_entry = (SilcClientEntry)id_cache->context; - /* Save the mode */ SILC_GET32_MSB(mode, modev); - silc_list_start(channel->clients); - while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) { - if (chu->client == client_entry) { - chu->mode = mode; - break; - } - } + chu = silc_client_on_channel(channel, client_entry); + if (chu) + chu->mode = mode; /* Notify application */ COMMAND_REPLY((ARGS, mode, channel, client_entry)); @@ -1489,7 +1443,6 @@ SILC_CLIENT_CMD_REPLY_FUNC(ban) SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context; SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data; SilcCommandStatus status; - SilcIDCacheEntry id_cache = NULL; SilcChannelEntry channel; SilcChannelID *channel_id; unsigned char *tmp; @@ -1514,15 +1467,13 @@ SILC_CLIENT_CMD_REPLY_FUNC(ban) goto out; /* Get the channel entry */ - if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id, - &id_cache)) { + channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id); + if (!channel) { silc_free(channel_id); COMMAND_REPLY_ERROR; goto out; } - channel = (SilcChannelEntry)id_cache->context; - /* Get the ban list */ tmp = silc_argument_get_arg_type(cmd->args, 3, &len); @@ -1608,6 +1559,30 @@ SILC_CLIENT_CMD_REPLY_FUNC(leave) silc_client_command_reply_free(cmd); } +/* Channel resolving callback for USERS command reply. */ + +static void silc_client_command_reply_users_cb(SilcClient client, + SilcClientConnection conn, + SilcChannelEntry *channels, + uint32 channels_count, + void *context) +{ + if (!channels_count) { + SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context; + SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data; + SilcCommandStatus status = SILC_STATUS_ERR_NO_SUCH_CHANNEL; + + SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, + "%s", silc_client_command_status_message(status)); + COMMAND_REPLY_ERROR; + SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS); + silc_client_command_reply_free(cmd); + return; + } + + silc_client_command_reply_users(context, NULL); +} + /* Reply to USERS command. Received list of client ID's and theirs modes on the channel we requested. */ @@ -1616,8 +1591,8 @@ SILC_CLIENT_CMD_REPLY_FUNC(users) SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context; SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data; SilcCommandStatus status; - SilcIDCacheEntry id_cache = NULL; SilcChannelEntry channel; + SilcClientEntry client_entry; SilcChannelUser chu; SilcChannelID *channel_id = NULL; SilcBuffer client_id_list = NULL; @@ -1682,26 +1657,18 @@ SILC_CLIENT_CMD_REPLY_FUNC(users) silc_buffer_put(client_mode_list, tmp, tmp_len); /* Get channel entry */ - if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id, - &id_cache)) { + channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id); + if (!channel) { /* Resolve the channel from server */ - silc_idlist_get_channel_by_id(cmd->client, conn, channel_id, TRUE); - - /* Register pending command callback. After we've received the channel - information we will reprocess this command reply by re-calling this - USERS command reply callback. */ - silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident, - silc_client_command_reply_users, cmd); + silc_client_get_channel_by_id_resolve(cmd->client, conn, channel_id, + silc_client_command_reply_users_cb, + cmd); + silc_free(channel_id); + if (client_id_list) + silc_buffer_free(client_id_list); + if (client_mode_list) + silc_buffer_free(client_mode_list); return; - } else { - channel = (SilcChannelEntry)id_cache->context; - } - - /* Remove old client list from channel. */ - silc_list_start(channel->clients); - while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) { - silc_list_del(channel->clients, chu); - silc_free(chu); } /* Cache the received Client ID's and modes. */ @@ -1709,7 +1676,6 @@ SILC_CLIENT_CMD_REPLY_FUNC(users) uint16 idp_len; uint32 mode; SilcClientID *client_id; - SilcClientEntry client; /* Client ID */ SILC_GET16_MSB(idp_len, client_id_list->data + 2); @@ -1722,18 +1688,9 @@ SILC_CLIENT_CMD_REPLY_FUNC(users) SILC_GET32_MSB(mode, client_mode_list->data); /* Check if we have this client cached already. */ - id_cache = NULL; - silc_idcache_find_by_id_one_ext(conn->client_cache, - (void *)client_id, - NULL, NULL, - silc_hash_client_id_compare, NULL, - &id_cache); - - if (!id_cache || !((SilcClientEntry)id_cache->context)->username || - !((SilcClientEntry)id_cache->context)->realname) { - - if (id_cache && id_cache->context) { - SilcClientEntry client_entry = (SilcClientEntry)id_cache->context; + client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id); + if (!client_entry || !client_entry->username || !client_entry->realname) { + if (client_entry) { if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) { silc_buffer_pull(client_id_list, idp_len); silc_buffer_pull(client_mode_list, 4); @@ -1756,17 +1713,16 @@ SILC_CLIENT_CMD_REPLY_FUNC(users) res_argv_types[res_argc] = res_argc + 3; res_argc++; } else { - /* Found the client, join it to the channel */ - client = (SilcClientEntry)id_cache->context; - chu = silc_calloc(1, sizeof(*chu)); - chu->client = client; - chu->mode = mode; - silc_list_add(channel->clients, chu); - - silc_free(client_id); - id_cache = NULL; + if (!silc_client_on_channel(channel, client_entry)) { + chu = silc_calloc(1, sizeof(*chu)); + chu->client = client_entry; + chu->channel = channel; + silc_hash_table_add(channel->user_list, client_entry, chu); + silc_hash_table_add(client_entry->channels, channel, chu); + } } + silc_free(client_id); silc_buffer_pull(client_id_list, idp_len); silc_buffer_pull(client_mode_list, 4); } @@ -1794,14 +1750,21 @@ SILC_CLIENT_CMD_REPLY_FUNC(users) silc_client_command_reply_users, cmd); silc_buffer_free(res_cmd); - if (channel_id) - silc_free(channel_id); - + silc_free(channel_id); silc_free(res_argv); silc_free(res_argv_lens); silc_free(res_argv_types); + if (client_id_list) + silc_buffer_free(client_id_list); + if (client_mode_list) + silc_buffer_free(client_mode_list); return; } + + silc_buffer_push(client_id_list, (client_id_list->data - + client_id_list->head)); + silc_buffer_push(client_mode_list, (client_mode_list->data - + client_mode_list->head)); /* Notify application */ COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list)); @@ -1876,17 +1839,12 @@ SILC_CLIENT_CMD_REPLY_FUNC(getkey) if (id_type == SILC_ID_CLIENT) { /* Received client's public key */ client_id = silc_id_payload_get_id(idp); - if (!silc_idcache_find_by_id_one_ext(conn->client_cache, - (void *)client_id, - NULL, NULL, - silc_hash_client_id_compare, NULL, - &id_cache)) { + client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id); + if (!client_entry) { COMMAND_REPLY_ERROR; goto out; } - client_entry = (SilcClientEntry)id_cache->context; - /* Notify application */ COMMAND_REPLY((ARGS, id_type, client_entry, public_key)); } else if (id_type == SILC_ID_SERVER) { diff --git a/lib/silcclient/idlist.c b/lib/silcclient/idlist.c index 0dd94e4a..aa5ccc27 100644 --- a/lib/silcclient/idlist.c +++ b/lib/silcclient/idlist.c @@ -1,6 +1,6 @@ /* - idlist.c + idlist.c Author: Pekka Riikonen @@ -8,9 +8,8 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - + the Free Software Foundation; version 2 of the License. + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -586,6 +585,8 @@ silc_client_add_client(SilcClient client, SilcClientConnection conn, client_entry->mode = mode; if (nick) client_entry->nickname = strdup(nick); + client_entry->channels = silc_hash_table_alloc(1, silc_hash_ptr, NULL, NULL, + NULL, NULL, NULL, TRUE); /* Format the nickname */ silc_client_nickname_format(client, conn, client_entry); @@ -597,6 +598,7 @@ silc_client_add_client(SilcClient client, SilcClientConnection conn, silc_free(client_entry->username); silc_free(client_entry->hostname); silc_free(client_entry->server); + silc_hash_table_free(client_entry->channels); silc_free(client_entry); return NULL; } @@ -653,6 +655,7 @@ void silc_client_del_client_entry(SilcClient client, silc_free(client_entry->server); silc_free(client_entry->id); silc_free(client_entry->fingerprint); + silc_hash_table_free(client_entry->channels); if (client_entry->send_key) silc_cipher_free(client_entry->send_key); if (client_entry->receive_key) @@ -680,12 +683,65 @@ bool silc_client_del_client(SilcClient client, SilcClientConnection conn, return ret; } +/* Add new channel entry to the ID Cache */ + +SilcChannelEntry silc_client_add_channel(SilcClient client, + SilcClientConnection conn, + const char *channel_name, + uint32 mode, + SilcChannelID *channel_id) +{ + SilcChannelEntry channel; + + SILC_LOG_DEBUG(("Start")); + + channel = silc_calloc(1, sizeof(*channel)); + channel->channel_name = strdup(channel_name); + channel->id = channel_id; + channel->mode = mode; + channel->user_list = silc_hash_table_alloc(1, silc_hash_ptr, NULL, NULL, + NULL, NULL, NULL, TRUE); + + /* Put it to the ID cache */ + if (!silc_idcache_add(conn->channel_cache, channel->channel_name, + (void *)channel->id, (void *)channel, 0, NULL)) { + silc_free(channel->channel_name); + silc_hash_table_free(channel->user_list); + silc_free(channel); + return NULL; + } + + return channel; +} + +/* Foreach callbcak to free all users from the channel when deleting a + channel entry. */ + +static void silc_client_del_channel_foreach(void *key, void *context, + void *user_context) +{ + SilcChannelUser chu = (SilcChannelUser)context; + + /* Remove the context from the client's channel hash table as that + table and channel's user_list hash table share this same context. */ + silc_hash_table_del(chu->client->channels, chu->channel); + silc_free(chu); +} + /* Removes channel from the cache by the channel entry. */ bool silc_client_del_channel(SilcClient client, SilcClientConnection conn, SilcChannelEntry channel) { bool ret = silc_idcache_del_by_context(conn->channel_cache, channel); + + /* Free all client entrys from the users list. The silc_hash_table_free + will free all the entries so they are not freed at the foreach + callback. */ + silc_hash_table_foreach(channel->user_list, silc_client_del_channel_foreach, + NULL); + silc_hash_table_free(channel->user_list); + silc_free(channel->channel_name); silc_free(channel->id); silc_free(channel->key); @@ -704,6 +760,30 @@ bool silc_client_del_channel(SilcClient client, SilcClientConnection conn, return ret; } +/* Replaces the channel ID of the `channel' to `new_id'. Returns FALSE + if the ID could not be changed. */ + +bool silc_client_replace_channel_id(SilcClient client, + SilcClientConnection conn, + SilcChannelEntry channel, + SilcChannelID *new_id) +{ + if (!new_id) + return FALSE; + + SILC_LOG_DEBUG(("Old Channel ID id(%s)", + silc_id_render(channel->id, SILC_ID_CHANNEL))); + SILC_LOG_DEBUG(("New Channel ID id(%s)", + silc_id_render(new_id, SILC_ID_CHANNEL))); + + silc_idcache_del_by_id(conn->channel_cache, channel->id); + silc_free(channel->id); + channel->id = new_id; + return silc_idcache_add(conn->channel_cache, channel->channel_name, + (void *)channel->id, (void *)channel, 0, NULL); + +} + /* Finds entry for channel by the channel name. Returns the entry or NULL if the entry was not found. It is found only if the client is joined to the channel. */ @@ -816,39 +896,6 @@ void silc_client_get_channel_by_id_resolve(SilcClient client, (void *)i); } -/* Find channel entry by ID. This routine is used internally by the library. */ - -SilcChannelEntry silc_idlist_get_channel_by_id(SilcClient client, - SilcClientConnection conn, - SilcChannelID *channel_id, - int query) -{ - SilcBuffer idp; - SilcChannelEntry channel; - - SILC_LOG_DEBUG(("Start")); - - channel = silc_client_get_channel_by_id(client, conn, channel_id); - if (channel) - return channel; - - if (query) { - /* Register our own command reply for this command */ - silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL, - silc_client_command_reply_identify_i, 0, - ++conn->cmd_ident); - - /* Send the command */ - idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL); - silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY, - conn->cmd_ident, - 1, 5, idp->data, idp->len); - silc_buffer_free(idp); - } - - return NULL; -} - /* Finds entry for server by the server name. */ SilcServerEntry silc_client_get_server(SilcClient client, diff --git a/lib/silcclient/idlist.h b/lib/silcclient/idlist.h index 26b38e01..b515baa4 100644 --- a/lib/silcclient/idlist.h +++ b/lib/silcclient/idlist.h @@ -1,16 +1,15 @@ /* - idlist.h + idlist.h Author: Pekka Riikonen - Copyright (C) 1997 - 2001 Pekka Riikonen + Copyright (C) 2001 - 2002 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - + the Free Software Foundation; version 2 of the License. + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -21,6 +20,9 @@ #ifndef IDLIST_H #define IDLIST_H +typedef struct SilcChannelEntryStruct *SilcChannelEntry; + +/* Client entry status */ typedef enum { SILC_CLIENT_STATUS_NONE = 0x0000, SILC_CLIENT_STATUS_RESOLVING = 0x0001, @@ -51,13 +53,14 @@ typedef struct { bool generated; /* TRUE if library generated the key */ SilcClientKeyAgreement ke; /* Current key agreement context or NULL */ SilcClientStatus status; /* Status mask */ + SilcHashTable channels; /* All channels client has joined */ } *SilcClientEntry; /* Client and its mode on a channel */ typedef struct SilcChannelUserStruct { SilcClientEntry client; uint32 mode; - struct SilcChannelUserStruct *next; + SilcChannelEntry channel; } *SilcChannelUser; /* Structure to hold one channel private key. */ @@ -70,14 +73,13 @@ typedef struct { /* Channel entry context. This is allocate for every channel client has joined to. This includes for example the channel specific keys */ -typedef struct SilcChannelEntryStruct { +struct SilcChannelEntryStruct { char *channel_name; SilcChannelID *id; uint32 mode; - bool on_channel; - /* Joined clients */ - SilcList clients; + /* All clients that has joined this channel */ + SilcHashTable user_list; /* Channel keys */ SilcCipher channel_key; /* The channel key */ @@ -94,7 +96,7 @@ typedef struct SilcChannelEntryStruct { SilcCipher old_channel_key; SilcHmac old_hmac; SilcTask rekey_task; -} *SilcChannelEntry; +}; /* Server entry context. This represents one server. When server information is resolved with INFO command the server info is saved in this context. @@ -127,10 +129,15 @@ SilcClientEntry silc_idlist_get_client(SilcClient client, const char *nickname, const char *format, bool query); -SilcChannelEntry silc_idlist_get_channel_by_id(SilcClient client, - SilcClientConnection conn, - SilcChannelID *channel_id, - int query); +SilcChannelEntry silc_client_add_channel(SilcClient client, + SilcClientConnection conn, + const char *channel_name, + uint32 mode, + SilcChannelID *channel_id); +bool silc_client_replace_channel_id(SilcClient client, + SilcClientConnection conn, + SilcChannelEntry channel, + SilcChannelID *new_id); void silc_client_nickname_format(SilcClient client, SilcClientConnection conn, SilcClientEntry client_entry); diff --git a/lib/silcclient/silcapi.h b/lib/silcclient/silcapi.h index 5bcf556d..7bb91784 100644 --- a/lib/silcclient/silcapi.h +++ b/lib/silcclient/silcapi.h @@ -964,11 +964,11 @@ bool silc_client_del_client(SilcClient client, SilcClientConnection conn, * * SYNOPSIS * - * typedef void (*SilcGetClientCallback)(SilcClient client, - * SilcClientConnection conn, - * SilcClientEntry *clients, - * uint32 clients_count, - * void *context); + * typedef void (*SilcGetChannelCallback)(SilcClient client, + * SilcClientConnection conn, + * SilcChannelEntry *channels, + * uint32 channels_count, + * void *context); * * DESCRIPTION * @@ -1117,6 +1117,23 @@ SilcServerEntry silc_client_get_server_by_id(SilcClient client, bool silc_client_del_server(SilcClient client, SilcClientConnection conn, SilcServerEntry server); +/****f* silcclient/SilcClientAPI/silc_client_on_channel + * + * SYNOPSIS + * + * SilcChannelUser silc_client_on_channel(SilcChannelEntry channel, + * SilcClientEntry client_entry); + * + * DESCRIPTION + * + * Returns the ChannelUser entry if the `client_entry' is joined on the + * channel indicated by the `channel'. NULL if client is not joined on + * the channel. + * + ***/ +SilcChannelUser silc_client_on_channel(SilcChannelEntry channel, + SilcClientEntry client_entry); + /* Command management (command.c) */ /****f* silcclient/SilcClientAPI/silc_client_command_alloc diff --git a/lib/silcutil/silchashtable.c b/lib/silcutil/silchashtable.c index 130d9fa7..31f33308 100644 --- a/lib/silcutil/silchashtable.c +++ b/lib/silcutil/silchashtable.c @@ -834,6 +834,18 @@ void silc_hash_table_list(SilcHashTable ht, SilcHashTableList *htl) htl->ht = ht; htl->entry = NULL; htl->index = 0; + htl->auto_rehash = ht->auto_rehash; + + /* Disallow rehashing of the table while traversing the table */ + ht->auto_rehash = FALSE; +} + +/* Resets the `htl' SilcHashTableList. */ + +void silc_hash_table_list_reset(SilcHashTableList *htl) +{ + /* Set back the original auto rehash value to the table */ + htl->ht->auto_rehash = htl->auto_rehash; } /* Returns always the next entry in the hash table into the `key' and diff --git a/lib/silcutil/silchashtable.h b/lib/silcutil/silchashtable.h index bdee0e10..f05e99e0 100644 --- a/lib/silcutil/silchashtable.h +++ b/lib/silcutil/silchashtable.h @@ -80,6 +80,7 @@ typedef struct SilcHashTableStruct *SilcHashTable; * silc_hash_table_list(hash_table, &htl); * while (silc_hash_table_get(&htl, (void *)&key, (void *)&context)) * ... + * silc_hash_table_list_reset(&htl); * * SOURCE */ @@ -90,6 +91,7 @@ struct SilcHashTableListStruct { SilcHashTable ht; void *entry; uint32 index; + bool auto_rehash; }; /***/ @@ -383,11 +385,33 @@ void silc_hash_table_rehash(SilcHashTable ht, uint32 new_size); * DESCRIPTION * * Prepares the `htl' SilcHashTableList sent as argument to be used in the - * hash table traversing with the silc_hash_table_get. + * hash table traversing with the silc_hash_table_get. After the hash + * table traversing is completed the silc_hash_table_list_reset must be + * called. + * + * NOTES + * + * The hash table will not be rehashed during the traversing of the list, + * even if the table was marked as auto rehashable. The caller also must + * not call silc_hash_table_rehash while traversing the list. * ***/ void silc_hash_table_list(SilcHashTable ht, SilcHashTableList *htl); +/****f* silcutil/SilcHashTableAPI/silc_hash_table_list_reset + * + * SYNOPSIS + * + * void silc_hash_table_list_reset(SilcHashTableList *htl); + * + * DESCRIPTION + * + * Resets the `htl' SilcHashTableList. This must be called after the + * hash table traversing is completed. + * + ***/ +void silc_hash_table_list_reset(SilcHashTableList *htl); + /****f* silcutil/SilcHashTableAPI/silc_hash_table_get * * SYNOPSIS diff --git a/win32/libsilc/libsilc.def b/win32/libsilc/libsilc.def index 42d54f0d..18581ffb 100644 --- a/win32/libsilc/libsilc.def +++ b/win32/libsilc/libsilc.def @@ -555,3 +555,4 @@ EXPORTS silc_log_get_file @ 846 ; silc_log_quick @ 847 ; silc_log_flushdelay @ 848 ; + silc_hash_table_list_reset @ 849 ; diff --git a/win32/libsilcclient/libsilcclient.def b/win32/libsilcclient/libsilcclient.def index 7bec0254..655b2ce8 100644 --- a/win32/libsilcclient/libsilcclient.def +++ b/win32/libsilcclient/libsilcclient.def @@ -162,3 +162,4 @@ EXPORTS silc_client_command_call @ 148 ; silc_client_command_reply_quit @ 149 ; silc_client_run_one @ 150 ; + silc_client_on_channel @ 151 ; -- 2.24.0