X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=blobdiff_plain;f=apps%2Fsilcd%2Fidlist.c;h=f762787fe80af56f9e921192b0bb14947bafccce;hp=99b375e762eab456bd8569cae99a46e7af18e477;hb=e5d8d3db6caa344b3d419b884556c21b15e7d123;hpb=96bee64d3807c79aaa507596f1064fa3c6597267 diff --git a/apps/silcd/idlist.c b/apps/silcd/idlist.c index 99b375e7..f762787f 100644 --- a/apps/silcd/idlist.c +++ b/apps/silcd/idlist.c @@ -36,14 +36,16 @@ void silc_idlist_add_data(void *entry, SilcIDListData idata) SilcIDListData data = (SilcIDListData)entry; data->send_key = idata->send_key; data->receive_key = idata->receive_key; + data->rekey = idata->rekey; data->hash = idata->hash; - data->hmac = idata->hmac; - data->hmac_key = idata->hmac_key; - data->hmac_key_len = idata->hmac_key_len; + data->hmac_send = idata->hmac_send; + data->hmac_receive = idata->hmac_receive; data->public_key = idata->public_key; data->last_receive = idata->last_receive; data->last_sent = idata->last_sent; - data->registered = idata->registered; + data->status = idata->status; + + data->created = time(0); /* Update creation time */ } /* Free's all data in the common ID entry data structure. */ @@ -55,12 +57,15 @@ void silc_idlist_del_data(void *entry) silc_cipher_free(idata->send_key); if (idata->receive_key) silc_cipher_free(idata->receive_key); - if (idata->hmac) - silc_hmac_free(idata->hmac); - if (idata->hmac_key) { - memset(idata->hmac_key, 0, idata->hmac_key_len); - silc_free(idata->hmac_key); + if (idata->rekey) { + if (idata->rekey->send_enc_key) { + memset(idata->rekey->send_enc_key, 0, idata->rekey->enc_key_len); + silc_free(idata->rekey->send_enc_key); + } + silc_free(idata->rekey); } + if (idata->hmac_send) /* Same as idata->hmac_receive */ + silc_hmac_free(idata->hmac_send); if (idata->public_key) silc_pkcs_public_key_free(idata->public_key); } @@ -74,10 +79,10 @@ SILC_TASK_CALLBACK_GLOBAL(silc_idlist_purge) SILC_LOG_DEBUG(("Start")); silc_idcache_purge(i->cache); - silc_task_register(i->timeout_queue, 0, - silc_idlist_purge, - (void *)i, 600, 0, - SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW); + silc_schedule_task_add(i->schedule, 0, + silc_idlist_purge, + (void *)i, 600, 0, + SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW); } /****************************************************************************** @@ -109,9 +114,7 @@ silc_idlist_add_server(SilcIDList id_list, server->connection = connection; if (!silc_idcache_add(id_list->servers, server->server_name, - server->server_name ? strlen(server->server_name) : 0, - SILC_ID_SERVER, (void *)server->id, - (void *)server, TRUE, FALSE)) { + (void *)server->id, (void *)server, FALSE)) { silc_free(server); return NULL; } @@ -123,7 +126,7 @@ silc_idlist_add_server(SilcIDList id_list, SilcServerEntry silc_idlist_find_server_by_id(SilcIDList id_list, SilcServerID *id, - SilcIDCacheEntry *ret_entry) + bool registered, SilcIDCacheEntry *ret_entry) { SilcIDCacheEntry id_cache = NULL; SilcServerEntry server; @@ -135,7 +138,7 @@ silc_idlist_find_server_by_id(SilcIDList id_list, SilcServerID *id, silc_id_render(id, SILC_ID_SERVER))); if (!silc_idcache_find_by_id_one(id_list->servers, (void *)id, - SILC_ID_SERVER, &id_cache)) + &id_cache)) return NULL; server = (SilcServerEntry)id_cache->context; @@ -143,6 +146,12 @@ silc_idlist_find_server_by_id(SilcIDList id_list, SilcServerID *id, if (ret_entry) *ret_entry = id_cache; + if (server && registered && + !(server->data.status & SILC_IDLIST_STATUS_REGISTERED)) + return NULL; + + SILC_LOG_DEBUG(("Found")); + return server; } @@ -150,14 +159,14 @@ silc_idlist_find_server_by_id(SilcIDList id_list, SilcServerID *id, SilcServerEntry silc_idlist_find_server_by_name(SilcIDList id_list, char *name, - SilcIDCacheEntry *ret_entry) + bool registered, SilcIDCacheEntry *ret_entry) { SilcIDCacheEntry id_cache = NULL; SilcServerEntry server; SILC_LOG_DEBUG(("Server by name `%s'", name)); - if (!silc_idcache_find_by_data_one(id_list->servers, name, &id_cache)) + if (!silc_idcache_find_by_name_one(id_list->servers, name, &id_cache)) return NULL; server = (SilcServerEntry)id_cache->context; @@ -165,6 +174,10 @@ silc_idlist_find_server_by_name(SilcIDList id_list, char *name, if (ret_entry) *ret_entry = id_cache; + if (server && registered && + !(server->data.status & SILC_IDLIST_STATUS_REGISTERED)) + return NULL; + SILC_LOG_DEBUG(("Found")); return server; @@ -174,7 +187,8 @@ silc_idlist_find_server_by_name(SilcIDList id_list, char *name, SilcServerEntry silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname, - int port, SilcIDCacheEntry *ret_entry) + int port, bool registered, + SilcIDCacheEntry *ret_entry) { SilcIDCacheList list = NULL; SilcIDCacheEntry id_cache = NULL; @@ -183,8 +197,7 @@ silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname, SILC_LOG_DEBUG(("Server by hostname %s and port %d", hostname, port)); - if (!silc_idcache_find_by_id(id_list->servers, SILC_ID_CACHE_ANY, - SILC_ID_SERVER, &list)) + if (!silc_idcache_get_all(id_list->servers, &list)) return NULL; if (!silc_idcache_list_first(list, &id_cache)) { @@ -196,8 +209,8 @@ silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname, server = (SilcServerEntry)id_cache->context; sock = (SilcSocketConnection)server->connection; - if (sock && ((sock->hostname && !strcmp(sock->hostname, hostname)) || - (sock->ip && !strcmp(sock->ip, hostname))) + if (sock && ((sock->hostname && !strcasecmp(sock->hostname, hostname)) || + (sock->ip && !strcasecmp(sock->ip, hostname))) && sock->port == port) break; @@ -213,6 +226,10 @@ silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname, if (ret_entry) *ret_entry = id_cache; + if (server && registered && + !(server->data.status & SILC_IDLIST_STATUS_REGISTERED)) + return NULL; + SILC_LOG_DEBUG(("Found")); return server; @@ -233,13 +250,20 @@ silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id, SILC_LOG_DEBUG(("Replacing Server ID")); if (!silc_idcache_find_by_id_one(id_list->servers, (void *)old_id, - SILC_ID_SERVER, &id_cache)) + &id_cache)) return NULL; server = (SilcServerEntry)id_cache->context; + + /* Remove the old entry and add a new one */ + + silc_idcache_del_by_id(id_list->servers, (void *)server->id); + silc_free(server->id); server->id = new_id; - id_cache->id = (void *)new_id; + + silc_idcache_add(id_list->servers, server->server_name, server->id, + server, FALSE); SILC_LOG_DEBUG(("Found")); @@ -248,23 +272,26 @@ silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id, /* Removes and free's server entry from ID list */ -void silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry) +int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry) { + SILC_LOG_DEBUG(("Start")); + if (entry) { /* Remove from cache */ if (entry->id) - silc_idcache_del_by_id(id_list->servers, SILC_ID_SERVER, - (void *)entry->id); + if (!silc_idcache_del_by_id(id_list->servers, (void *)entry->id)) + return FALSE; /* Free data */ - if (entry->server_name) - silc_free(entry->server_name); - if (entry->id) - silc_free(entry->id); + silc_free(entry->server_name); + silc_free(entry->id); memset(entry, 'F', sizeof(*entry)); silc_free(entry); + return TRUE; } + + return FALSE; } /****************************************************************************** @@ -283,8 +310,7 @@ void silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry) to be directly connected local client and `router' must be NULL. */ SilcClientEntry -silc_idlist_add_client(SilcIDList id_list, unsigned char *nickname, - unsigned int nickname_len, char *username, +silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username, char *userinfo, SilcClientID *id, SilcServerEntry router, void *connection) { @@ -299,12 +325,12 @@ silc_idlist_add_client(SilcIDList id_list, unsigned char *nickname, client->id = id; client->router = router; client->connection = connection; - silc_list_init(client->channels, struct SilcChannelClientEntryStruct, - client_list); + client->channels = silc_hash_table_alloc(3, silc_hash_ptr, NULL, + NULL, NULL, NULL, NULL, TRUE); - if (!silc_idcache_add(id_list->clients, nickname, nickname_len, - SILC_ID_CLIENT, (void *)client->id, - (void *)client, TRUE, FALSE)) { + if (!silc_idcache_add(id_list->clients, nickname, (void *)client->id, + (void *)client, FALSE)) { + silc_hash_table_free(client->channels); silc_free(client); return NULL; } @@ -317,22 +343,19 @@ silc_idlist_add_client(SilcIDList id_list, unsigned char *nickname, int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry) { + SILC_LOG_DEBUG(("Start")); + if (entry) { /* Remove from cache */ if (entry->id) - if (!silc_idcache_del_by_id(id_list->clients, SILC_ID_CLIENT, - (void *)entry->id)) + if (!silc_idcache_del_by_context(id_list->clients, entry)) return FALSE; /* Free data */ - if (entry->nickname) - silc_free(entry->nickname); - if (entry->username) - silc_free(entry->username); - if (entry->userinfo) - silc_free(entry->userinfo); - if (entry->id) - silc_free(entry->id); + silc_free(entry->nickname); + silc_free(entry->username); + silc_free(entry->userinfo); + silc_free(entry->id); memset(entry, 'F', sizeof(*entry)); silc_free(entry); @@ -346,131 +369,84 @@ int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry) /* Returns all clients matching requested nickname. Number of clients is returned to `clients_count'. Caller must free the returned table. */ -SilcClientEntry * -silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname, - char *server, unsigned int *clients_count) +int silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname, + char *server, + SilcClientEntry **clients, + uint32 *clients_count) { SilcIDCacheList list = NULL; SilcIDCacheEntry id_cache = NULL; - SilcClientEntry *clients; - int i; SILC_LOG_DEBUG(("Start")); - if (!silc_idcache_find_by_data(id_list->clients, nickname, &list)) - return NULL; + if (!silc_idcache_find_by_name(id_list->clients, nickname, &list)) + return FALSE; - clients = silc_calloc(silc_idcache_list_count(list), sizeof(*clients)); + *clients = silc_realloc(*clients, + (silc_idcache_list_count(list) + *clients_count) * + sizeof(**clients)); - i = 0; silc_idcache_list_first(list, &id_cache); - clients[i++] = (SilcClientEntry)id_cache->context; + (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context; while (silc_idcache_list_next(list, &id_cache)) - clients[i++] = (SilcClientEntry)id_cache->context; + (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context; silc_idcache_list_free(list); - if (clients_count) - *clients_count = i; + SILC_LOG_DEBUG(("Found total %d clients", *clients_count)); - return clients; + return TRUE; } -/* Returns all clients matching requested nickname. Number of clients is - returned to `clients_count'. Caller must free the returned table. */ -/* XXX This actually checks the data, which can be hash of the nickname - but is not if the client is local client. Global client on global - list may have hash. Thus, this is not fully reliable function. - Instead this should probably check the hash from the list of client ID's. */ - -SilcClientEntry * -silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname, - SilcHash md5hash, - unsigned int *clients_count) +/* Returns all clients matching requested nickname hash. Number of clients + is returned to `clients_count'. Caller must free the returned table. */ + +int silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname, + SilcHash md5hash, + SilcClientEntry **clients, + uint32 *clients_count) { SilcIDCacheList list = NULL; SilcIDCacheEntry id_cache = NULL; - SilcClientEntry *clients; unsigned char hash[32]; - int i; + SilcClientID client_id; SILC_LOG_DEBUG(("Start")); silc_hash_make(md5hash, nickname, strlen(nickname), hash); - if (!silc_idcache_find_by_data(id_list->clients, hash, &list)) - return NULL; + /* As the Client ID is hashed in the ID cache by hashing only the hash + from the Client ID, we can do a lookup with only the hash not the + other parts of the ID and get all the clients with that hash, ie. + with that nickname, as the hash is from the nickname. */ + memset(&client_id, 0, sizeof(client_id)); + memcpy(&client_id.hash, hash, sizeof(client_id.hash)); + if (!silc_idcache_find_by_id(id_list->clients, &client_id, &list)) + return FALSE; - clients = silc_calloc(silc_idcache_list_count(list), sizeof(*clients)); + *clients = silc_realloc(*clients, + (silc_idcache_list_count(list) + *clients_count) * + sizeof(**clients)); - i = 0; silc_idcache_list_first(list, &id_cache); - clients[i++] = (SilcClientEntry)id_cache->context; + (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context; while (silc_idcache_list_next(list, &id_cache)) - clients[i++] = (SilcClientEntry)id_cache->context; + (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context; silc_idcache_list_free(list); - if (clients_count) - *clients_count = i; - - return clients; -} - -/* Finds client by nickname hash. */ - -SilcClientEntry -silc_idlist_find_client_by_hash(SilcIDList id_list, char *nickname, - SilcHash md5hash, SilcIDCacheEntry *ret_entry) -{ - SilcIDCacheList list = NULL; - SilcIDCacheEntry id_cache = NULL; - SilcClientEntry client = NULL; - unsigned char hash[32]; - - SILC_LOG_DEBUG(("Client by hash")); - - silc_hash_make(md5hash, nickname, strlen(nickname), hash); - - if (!silc_idcache_find_by_id(id_list->clients, SILC_ID_CACHE_ANY, - SILC_ID_CLIENT, &list)) - return NULL; - - if (!silc_idcache_list_first(list, &id_cache)) { - silc_idcache_list_free(list); - return NULL; - } - - while (id_cache) { - client = (SilcClientEntry)id_cache->context; - - if (client && !SILC_ID_COMPARE_HASH(client->id, hash)) - break; - - id_cache = NULL; - client = NULL; - - if (!silc_idcache_list_next(list, &id_cache)) - break; - } - - silc_idcache_list_free(list); - - if (ret_entry) - *ret_entry = id_cache; - - SILC_LOG_DEBUG(("Found")); + SILC_LOG_DEBUG(("Found total %d clients", *clients_count)); - return client; + return TRUE; } /* Finds client by Client ID */ SilcClientEntry silc_idlist_find_client_by_id(SilcIDList id_list, SilcClientID *id, - SilcIDCacheEntry *ret_entry) + bool registered, SilcIDCacheEntry *ret_entry) { SilcIDCacheEntry id_cache = NULL; SilcClientEntry client; @@ -481,8 +457,14 @@ silc_idlist_find_client_by_id(SilcIDList id_list, SilcClientID *id, SILC_LOG_DEBUG(("Client ID (%s)", silc_id_render(id, SILC_ID_CLIENT))); - if (!silc_idcache_find_by_id_one(id_list->clients, (void *)id, - SILC_ID_CLIENT, &id_cache)) + /* Do extended search since the normal ID comparison function for + Client ID's compares only the hash from the Client ID and not the + entire ID. The silc_hash_client_id_compare compares the entire + Client ID as we want to find one specific Client ID. */ + if (!silc_idcache_find_by_id_one_ext(id_list->clients, (void *)id, + NULL, NULL, + silc_hash_client_id_compare, NULL, + &id_cache)) return NULL; client = (SilcClientEntry)id_cache->context; @@ -490,6 +472,10 @@ silc_idlist_find_client_by_id(SilcIDList id_list, SilcClientID *id, if (ret_entry) *ret_entry = id_cache; + if (client && registered && + !(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) + return NULL; + SILC_LOG_DEBUG(("Found")); return client; @@ -509,23 +495,26 @@ silc_idlist_replace_client_id(SilcIDList id_list, SilcClientID *old_id, SILC_LOG_DEBUG(("Replacing Client ID")); - if (!silc_idcache_find_by_id_one(id_list->clients, (void *)old_id, - SILC_ID_CLIENT, &id_cache)) + /* Do extended search since the normal ID comparison function for + Client ID's compares only the hash from the Client ID and not the + entire ID. The silc_hash_client_id_compare compares the entire + Client ID as we want to find one specific Client ID. */ + if (!silc_idcache_find_by_id_one_ext(id_list->clients, (void *)old_id, + NULL, NULL, + silc_hash_client_id_compare, NULL, + &id_cache)) return NULL; client = (SilcClientEntry)id_cache->context; + + /* Remove the old entry and add a new one */ + + silc_idcache_del_by_context(id_list->clients, client); + silc_free(client->id); client->id = new_id; - id_cache->id = (void *)new_id; - - /* If the old ID Cache data was the hash value of the old Client ID - replace it with the hash of new Client ID */ - if (id_cache->data && !SILC_ID_COMPARE_HASH(old_id, id_cache->data)) { - silc_free(id_cache->data); - id_cache->data = silc_calloc(sizeof(new_id->hash), sizeof(unsigned char)); - memcpy(id_cache->data, new_id->hash, sizeof(new_id->hash)); - silc_idcache_sort_by_data(id_list->clients); - } + + silc_idcache_add(id_list->clients, NULL, client->id, client, FALSE); SILC_LOG_DEBUG(("Replaced")); @@ -573,6 +562,8 @@ silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode, { SilcChannelEntry channel; + SILC_LOG_DEBUG(("Adding new channel entry")); + channel = silc_calloc(1, sizeof(*channel)); channel->channel_name = channel_name; channel->mode = mode; @@ -580,19 +571,20 @@ silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode, channel->router = router; channel->channel_key = channel_key; channel->hmac = hmac; + channel->created = time(0); if (!channel->hmac) - if (!silc_hmac_alloc("hmac-sha1-96", NULL, &channel->hmac)) { + if (!silc_hmac_alloc(SILC_DEFAULT_HMAC, NULL, &channel->hmac)) { silc_free(channel); return NULL; } - silc_list_init(channel->user_list, struct SilcChannelClientEntryStruct, - channel_list); + channel->user_list = silc_hash_table_alloc(3, silc_hash_ptr, NULL, NULL, + NULL, NULL, NULL, TRUE); if (!silc_idcache_add(id_list->channels, channel->channel_name, - channel->channel_name ? strlen(channel->channel_name) : - 0, SILC_ID_CHANNEL, - (void *)channel->id, (void *)channel, TRUE, FALSE)) { + (void *)channel->id, (void *)channel, FALSE)) { + silc_hmac_free(channel->hmac); + silc_hash_table_free(channel->user_list); silc_free(channel); return NULL; } @@ -600,45 +592,52 @@ silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode, return channel; } +/* Foreach callbcak to free all users from the channel when deleting a + channel entry. */ + +static void silc_idlist_del_channel_foreach(void *key, void *context, + void *user_context) +{ + SilcChannelClientEntry chl = (SilcChannelClientEntry)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(chl->client->channels, chl->channel); + silc_free(chl); +} + /* Free channel entry. This free's everything. */ int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry) { - if (entry) { - SilcChannelClientEntry chl; + SILC_LOG_DEBUG(("Start")); + if (entry) { /* Remove from cache */ if (entry->id) - if (!silc_idcache_del_by_id(id_list->channels, SILC_ID_CHANNEL, - (void *)entry->id)) + if (!silc_idcache_del_by_id(id_list->channels, (void *)entry->id)) return FALSE; /* Free data */ - if (entry->channel_name) - silc_free(entry->channel_name); - if (entry->id) - silc_free(entry->id); - if (entry->topic) - silc_free(entry->topic); + silc_free(entry->channel_name); + silc_free(entry->id); + silc_free(entry->topic); if (entry->channel_key) silc_cipher_free(entry->channel_key); if (entry->key) { memset(entry->key, 0, entry->key_len / 8); silc_free(entry->key); } - if (entry->cipher) - silc_free(entry->cipher); - if (entry->hmac_name) - silc_free(entry->hmac_name); - - /* Free all data, free also any reference from the client's channel - list since they share the same memory. */ - silc_list_start(entry->user_list); - while ((chl = silc_list_get(entry->user_list)) != SILC_LIST_END) { - silc_list_del(chl->client->channels, chl); - silc_list_del(entry->user_list, chl); - silc_free(chl); - } + silc_free(entry->cipher); + silc_free(entry->hmac_name); + silc_free(entry->rekey); + + /* 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(entry->user_list, silc_idlist_del_channel_foreach, + NULL); + silc_hash_table_free(entry->user_list); memset(entry, 'F', sizeof(*entry)); silc_free(entry); @@ -655,30 +654,19 @@ SilcChannelEntry silc_idlist_find_channel_by_name(SilcIDList id_list, char *name, SilcIDCacheEntry *ret_entry) { - SilcIDCacheList list = NULL; SilcIDCacheEntry id_cache = NULL; - SilcChannelEntry channel; SILC_LOG_DEBUG(("Channel by name")); - if (!silc_idcache_find_by_data_loose(id_list->channels, name, &list)) + if (!silc_idcache_find_by_name_one(id_list->channels, name, &id_cache)) return NULL; - - if (!silc_idcache_list_first(list, &id_cache)) { - silc_idcache_list_free(list); - return NULL; - } - - channel = (SilcChannelEntry)id_cache->context; if (ret_entry) *ret_entry = id_cache; - silc_idcache_list_free(list); - SILC_LOG_DEBUG(("Found")); - return channel; + return id_cache->context; } /* Finds channel by Channel ID. */ @@ -696,8 +684,7 @@ silc_idlist_find_channel_by_id(SilcIDList id_list, SilcChannelID *id, SILC_LOG_DEBUG(("Channel ID (%s)", silc_id_render(id, SILC_ID_CHANNEL))); - if (!silc_idcache_find_by_id_one(id_list->channels, (void *)id, - SILC_ID_CHANNEL, &id_cache)) + if (!silc_idcache_find_by_id_one(id_list->channels, (void *)id, &id_cache)) return NULL; channel = (SilcChannelEntry)id_cache->context; @@ -726,13 +713,20 @@ silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id, SILC_LOG_DEBUG(("Replacing Channel ID")); if (!silc_idcache_find_by_id_one(id_list->channels, (void *)old_id, - SILC_ID_CHANNEL, &id_cache)) + &id_cache)) return NULL; channel = (SilcChannelEntry)id_cache->context; + + /* Remove the old entry and add a new one */ + + silc_idcache_del_by_id(id_list->channels, (void *)channel->id); + silc_free(channel->id); channel->id = new_id; - id_cache->id = (void *)new_id; + + silc_idcache_add(id_list->channels, channel->channel_name, channel->id, + channel, FALSE); SILC_LOG_DEBUG(("Replaced")); @@ -744,30 +738,38 @@ silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id, SilcChannelEntry * silc_idlist_get_channels(SilcIDList id_list, SilcChannelID *channel_id, - unsigned int *channels_count) + uint32 *channels_count) { SilcIDCacheList list = NULL; SilcIDCacheEntry id_cache = NULL; - SilcChannelEntry *channels; - int i; + SilcChannelEntry *channels = NULL; + int i = 0; SILC_LOG_DEBUG(("Start")); - if (!silc_idcache_find_by_id(id_list->channels, channel_id ? channel_id : - SILC_ID_CACHE_ANY, SILC_ID_CHANNEL, &list)) - return NULL; + if (!channel_id) { + if (!silc_idcache_get_all(id_list->channels, &list)) + return NULL; - channels = silc_calloc(silc_idcache_list_count(list), sizeof(*channels)); + channels = silc_calloc(silc_idcache_list_count(list), sizeof(*channels)); + + i = 0; + silc_idcache_list_first(list, &id_cache); + channels[i++] = (SilcChannelEntry)id_cache->context; + + while (silc_idcache_list_next(list, &id_cache)) + channels[i++] = (SilcChannelEntry)id_cache->context; + + silc_idcache_list_free(list); + } else { + if (!silc_idcache_find_by_id_one(id_list->channels, channel_id, &id_cache)) + return NULL; - i = 0; - silc_idcache_list_first(list, &id_cache); - channels[i++] = (SilcChannelEntry)id_cache->context; + i = 1; + channels = silc_calloc(1, sizeof(*channels)); + channels[0] = (SilcChannelEntry)id_cache->context; + } - while (silc_idcache_list_next(list, &id_cache)) - channels[i++] = (SilcChannelEntry)id_cache->context; - - silc_idcache_list_free(list); - if (channels_count) *channels_count = i;