+Thu Jan 31 19:06:22 EET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * 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 <priikone@silcnet.org>
* Fixed founder regaining problem with JOIN command on normal
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
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)
void *context)
{
SilcChannelEntry channel = (SilcChannelEntry)context;
+ SilcHashTableList htl;
SilcChannelUser chu;
SILC_SERVER_REC *server = conn->context;
SILC_CHANNEL_REC *chanrec;
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);
case SILC_COMMAND_USERS:
{
+ SilcHashTableList htl;
SilcChannelEntry channel;
SilcChannelUser chu;
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;
if (mode)
silc_free(mode);
}
+ silc_hash_table_list_reset(&htl);
}
break;
} 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);
}
}
if (chl2) {
chl2->mode = mode;
silc_free(channel_id);
+ silc_hash_table_list_reset(&htl);
goto out;
}
}
chl2 = chl;
}
}
+ silc_hash_table_list_reset(&htl);
/* Send the same notify to the channel */
if (!notify_sent)
force_send);
}
+ silc_hash_table_list_reset(&htl);
silc_free(routed);
silc_free(packetdata.src_id);
silc_free(packetdata.dst_id);
force_send);
}
+ silc_hash_table_list_reset(&htl);
silc_free(routed);
silc_free(packetdata.src_id);
silc_free(packetdata.dst_id);
force_send);
}
}
+ silc_hash_table_list_reset(&htl);
}
/* Routine used to send (relay, route) private messages to some destination.
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);
silc_hash_table_del(channel->user_list, chl2->client);
silc_free(chl2);
}
+ silc_hash_table_list_reset(&htl2);
continue;
}
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. */
}
}
+ out:
+ silc_hash_table_list_reset(&htl);
silc_buffer_free(clidp);
}
silc_hash_table_del(channel->user_list, chl2->client);
silc_free(chl2);
}
+ silc_hash_table_list_reset(&htl2);
return FALSE;
}
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);
}
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);
}
silc_buffer_free(clidp);
}
+ silc_hash_table_list_reset(&htl);
silc_buffer_free(chidp);
}
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 =
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,
silc_buffer_pull(buffer, len);
silc_free(cid);
}
+ silc_hash_table_list_reset(&htl);
if (buffer)
silc_buffer_push(buffer, buffer->data - buffer->head);
silc_hash_table_del(channel->user_list, chl2->client);
silc_free(chl2);
}
+ silc_hash_table_list_reset(&htl2);
continue;
}
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);
}
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)
server->server_type == SILC_ROUTER ?
FALSE : !server->standalone);
}
+ silc_hash_table_list_reset(&htl);
silc_hash_table_free(channels);
return TRUE;
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;
}
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;
}
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);
}
}
-/* 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.
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
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 */
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"));
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. */
}
/* 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;
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);
}
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,
/* 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) :
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);
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",
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
{
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;
+}
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,
SilcChannelEntry channel;
SilcChannelUser chu;
SilcServerEntry server;
- SilcIDCacheEntry id_cache = NULL;
unsigned char *tmp;
uint32 tmp_len, mode;
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);
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
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
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. */
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;
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
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);
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)
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;
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,
{
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;
}
/* 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);
}
/* 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] == '-')
{
SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcClientConnection conn = cmd->conn;
- SilcIDCacheEntry id_cache = NULL;
SilcChannelEntry channel;
+ SilcChannelUser chu;
SilcBuffer buffer, idp;
char *name;
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,
{
SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
SilcClientID *client_id;
- SilcIDCacheEntry id_cache = NULL;
SilcClientEntry client_entry = NULL;
int argc;
uint32 len;
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);
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;
}
/* 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);
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);
}
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 */
SilcCommandStatus status;
SilcChannelEntry channel;
SilcChannelID *channel_id = NULL;
- SilcIDCacheEntry id_cache = NULL;
unsigned char *tmp;
char *topic;
uint32 argc, len;
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));
SilcCommandStatus status;
SilcChannelEntry channel;
SilcChannelID *channel_id;
- SilcIDCacheEntry id_cache;
unsigned char *tmp;
uint32 len;
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);
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;
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);
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;
}
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);
/* 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;
SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
"Cannot join channel: Unsupported HMAC `%s'", hmac);
COMMAND_REPLY_ERROR;
- silc_free(channel_name);
goto out;
}
}
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);
}
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,
SilcCommandStatus status;
unsigned char *tmp;
uint32 mode;
- SilcIDCacheEntry id_cache;
SilcChannelID *channel_id;
SilcChannelEntry channel;
uint32 len;
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) {
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;
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) {
}
/* 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));
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;
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);
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. */
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;
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. */
uint16 idp_len;
uint32 mode;
SilcClientID *client_id;
- SilcClientEntry client;
/* Client ID */
SILC_GET16_MSB(idp_len, client_id_list->data + 2);
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);
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);
}
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));
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) {
/*
- idlist.c
+ idlist.c
Author: Pekka Riikonen <priikone@silcnet.org>
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
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);
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;
}
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)
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);
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. */
(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,
/*
- idlist.h
+ idlist.h
Author: Pekka Riikonen <priikone@silcnet.org>
- 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
#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,
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. */
/* 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 */
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.
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);
*
* 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
*
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
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
* silc_hash_table_list(hash_table, &htl);
* while (silc_hash_table_get(&htl, (void *)&key, (void *)&context))
* ...
+ * silc_hash_table_list_reset(&htl);
*
* SOURCE
*/
SilcHashTable ht;
void *entry;
uint32 index;
+ bool auto_rehash;
};
/***/
* 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
silc_log_get_file @ 846 ;
silc_log_quick @ 847 ;
silc_log_flushdelay @ 848 ;
+ silc_hash_table_list_reset @ 849 ;
silc_client_command_call @ 148 ;
silc_client_command_reply_quit @ 149 ;
silc_client_run_one @ 150 ;
+ silc_client_on_channel @ 151 ;