X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=blobdiff_plain;f=lib%2Fsilcclient%2Fidlist.c;h=dfdfc6f3e5d4420367acfcd94dd0e74d5939cea7;hp=6c015ef527f0758c594d0b751a40403cd3e0097d;hb=413da0f8686910f5e627393157566ae729ca99c4;hpb=050bd9d9e5d843220f3f393a18ab5011622237b9 diff --git a/lib/silcclient/idlist.c b/lib/silcclient/idlist.c index 6c015ef5..dfdfc6f3 100644 --- a/lib/silcclient/idlist.c +++ b/lib/silcclient/idlist.c @@ -1,10 +1,10 @@ /* - idlist.c + idlist.c Author: Pekka Riikonen - Copyright (C) 2001 - 2002 Pekka Riikonen + Copyright (C) 2001 - 2003 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 @@ -87,7 +87,7 @@ SilcClientEntry *silc_client_get_clients_local(SilcClient client, continue; } } - + clients[i++] = id_cache->context; found = TRUE; if (!silc_idcache_list_next(list, &id_cache)) @@ -146,7 +146,7 @@ SILC_CLIENT_CMD_FUNC(get_client_callback) silc_free(i); } -/* Finds client entry or entries by the `nickname' and `server'. The +/* Finds client entry or entries by the `nickname' and `server'. The completion callback will be called when the client entries has been found. Note: this function is always asynchronous and resolves the client @@ -195,13 +195,13 @@ void silc_client_get_clients(SilcClient client, ++conn->cmd_ident); /* Send the command */ - silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY, - conn->cmd_ident, 1, 1, userhost, + silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY, + conn->cmd_ident, 1, 1, userhost, strlen(userhost)); /* Add pending callback */ silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident, - silc_client_command_get_client_callback, + silc_client_command_get_client_callback, (void *)i); silc_free(userhost); @@ -232,14 +232,14 @@ SilcClientEntry silc_idlist_get_client(SilcClient client, if (query) { SILC_LOG_DEBUG(("Requesting Client ID from server")); - + /* 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 */ - silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY, + silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident, 1, 1, nickname, strlen(nickname)); @@ -287,7 +287,6 @@ SilcClientEntry silc_idlist_get_client(SilcClient client, return entry; } - typedef struct { SilcClient client; SilcClientConnection conn; @@ -318,6 +317,8 @@ SILC_CLIENT_CMD_FUNC(get_clients_list_callback) SILC_LOG_DEBUG(("Resolved all clients")); + clients = silc_calloc(i->list_count, sizeof(*clients)); + for (c = 0; c < i->list_count; c++) { SilcUInt16 idp_len; SilcClientID *client_id; @@ -332,13 +333,11 @@ SILC_CLIENT_CMD_FUNC(get_clients_list_callback) } /* Get the client entry */ - if (silc_idcache_find_by_id_one_ext(i->conn->internal->client_cache, - (void *)client_id, - NULL, NULL, + if (silc_idcache_find_by_id_one_ext(i->conn->internal->client_cache, + (void *)client_id, + NULL, NULL, silc_hash_client_id_compare, NULL, &id_cache)) { - clients = silc_realloc(clients, sizeof(*clients) * - (clients_count + 1)); clients[clients_count] = (SilcClientEntry)id_cache->context; clients_count++; found = TRUE; @@ -411,7 +410,7 @@ void silc_client_get_clients_by_list(SilcClient client, /* Check if we have this client cached already. */ ret = silc_idcache_find_by_id_one_ext(conn->internal->client_cache, - (void *)client_id, NULL, NULL, + (void *)client_id, NULL, NULL, silc_hash_client_id_compare, NULL, &id_cache); @@ -424,9 +423,9 @@ void silc_client_get_clients_by_list(SilcClient client, if (entry->status & SILC_CLIENT_STATUS_RESOLVING) { /* Attach to this resolving and wait until it finishes */ silc_client_command_pending( - conn, SILC_COMMAND_NONE, + conn, SILC_COMMAND_NONE, entry->resolve_cmd_ident, - silc_client_command_get_clients_list_callback, + silc_client_command_get_clients_list_callback, (void *)in); wait_res = TRUE; in->res_count++; @@ -458,7 +457,7 @@ void silc_client_get_clients_by_list(SilcClient client, silc_buffer_pull(client_id_list, idp_len); } - silc_buffer_push(client_id_list, client_id_list->data - + silc_buffer_push(client_id_list, client_id_list->data - client_id_list->head); /* Query the client information from server if the list included clients @@ -470,7 +469,7 @@ void silc_client_get_clients_by_list(SilcClient client, res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY, res_argc, res_argv, res_argv_lens, res_argv_types, ++conn->cmd_ident); - silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND, + silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND, NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len, TRUE); @@ -481,7 +480,7 @@ void silc_client_get_clients_by_list(SilcClient client, /* Process the applications request after reply has been received */ silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident, - silc_client_command_get_clients_list_callback, + silc_client_command_get_clients_list_callback, (void *)in); in->res_count++; @@ -499,6 +498,169 @@ void silc_client_get_clients_by_list(SilcClient client, silc_client_command_get_clients_list_callback((void *)in, NULL); } +typedef struct { + SilcClient client; + SilcClientConnection conn; + SilcChannelID channel_id; + SilcGetClientCallback completion; + void *context; + int res_count; +} *GetClientsByChannelInternal; + +SILC_CLIENT_CMD_FUNC(get_clients_by_channel_cb) +{ + GetClientsByChannelInternal i = context; + SilcClientEntry *clients = NULL; + SilcUInt32 clients_count = 0; + bool found = FALSE; + SilcChannelEntry channel; + SilcHashTableList htl; + SilcChannelUser chu; + + channel = silc_client_get_channel_by_id(i->client, i->conn, &i->channel_id); + if (channel && !silc_hash_table_count(channel->user_list)) { + clients = silc_calloc(silc_hash_table_count(channel->user_list), + sizeof(*clients)); + silc_hash_table_list(channel->user_list, &htl); + while (silc_hash_table_get(&htl, NULL, (void **)&chu)) + clients[clients_count++] = chu->client; + silc_hash_table_list_reset(&htl); + found = TRUE; + } + + if (found) { + i->completion(i->client, i->conn, clients, clients_count, i->context); + silc_free(clients); + } else { + i->completion(i->client, i->conn, NULL, 0, i->context); + } + + silc_free(i); +} + +/* Gets client entries by the channel entry indicated by `channel'. Thus, + it resolves the clients currently on that channel. */ + +void silc_client_get_clients_by_channel(SilcClient client, + SilcClientConnection conn, + SilcChannelEntry channel, + SilcGetClientCallback completion, + void *context) +{ + GetClientsByChannelInternal in; + SilcHashTableList htl; + SilcChannelUser chu; + SilcClientEntry entry; + unsigned char **res_argv = NULL; + SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0; + SilcBuffer idp; + bool wait_res = FALSE; + + assert(client && conn && channel); + + SILC_LOG_DEBUG(("Start")); + + in = silc_calloc(1, sizeof(*in)); + in->client = client; + in->conn = conn; + in->channel_id = *channel->id; + in->completion = completion; + in->context = context; + + /* If user list does not exist, send USERS command. */ + if (!channel->user_list || !silc_hash_table_count(channel->user_list)) { + SILC_LOG_DEBUG(("Sending USERS")); + silc_client_command_register(client, SILC_COMMAND_USERS, NULL, NULL, + silc_client_command_reply_users_i, 0, + ++conn->cmd_ident); + silc_client_command_send(client, conn, SILC_COMMAND_USERS, + conn->cmd_ident, 1, 2, channel->channel_name, + strlen(channel->channel_name)); + silc_client_command_pending(conn, SILC_COMMAND_USERS, conn->cmd_ident, + silc_client_command_get_clients_by_channel_cb, + in); + return; + } + + silc_hash_table_list(channel->user_list, &htl); + while (silc_hash_table_get(&htl, NULL, (void **)&chu)) { + entry = chu->client; + + /* If the entry has incomplete info, then resolve it from the server. */ + if (!entry->nickname || !entry->realname) { + if (entry->status & SILC_CLIENT_STATUS_RESOLVING) { + /* Attach to this resolving and wait until it finishes */ + silc_client_command_pending( + conn, SILC_COMMAND_NONE, + entry->resolve_cmd_ident, + silc_client_command_get_clients_by_channel_cb, + (void *)in); + wait_res = TRUE; + in->res_count++; + continue; + } + entry->status |= SILC_CLIENT_STATUS_RESOLVING; + entry->resolve_cmd_ident = conn->cmd_ident + 1; + + idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT); + + /* No we don't have it, query it from the server. Assemble argument + table that will be sent for the WHOIS command later. */ + res_argv = silc_realloc(res_argv, sizeof(*res_argv) * + (res_argc + 1)); + res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) * + (res_argc + 1)); + res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) * + (res_argc + 1)); + res_argv[res_argc] = silc_memdup(idp->data, idp->len); + res_argv_lens[res_argc] = idp->len; + res_argv_types[res_argc] = res_argc + 4; + res_argc++; + + silc_buffer_free(idp); + } + } + silc_hash_table_list_reset(&htl); + + /* Query the client information from server if the list included clients + that we don't know about. */ + if (res_argc) { + SilcBuffer res_cmd; + + /* Send the WHOIS command to server */ + res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS, + res_argc, res_argv, res_argv_lens, + res_argv_types, ++conn->cmd_ident); + silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND, + NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len, + TRUE); + + /* Register our own command reply for this command */ + silc_client_command_register(client, SILC_COMMAND_WHOIS, NULL, NULL, + silc_client_command_reply_whois_i, 0, + conn->cmd_ident); + + /* Process the applications request after reply has been received */ + silc_client_command_pending( + conn, SILC_COMMAND_WHOIS, conn->cmd_ident, + silc_client_command_get_clients_by_channel_cb, + (void *)in); + in->res_count++; + + silc_buffer_free(res_cmd); + silc_free(res_argv); + silc_free(res_argv_lens); + silc_free(res_argv_types); + return; + } + + if (wait_res) + return; + + /* We have the clients in cache, get them and call the completion */ + silc_client_command_get_clients_by_channel_cb((void *)in, NULL); +} + /* Finds entry for client by the client's ID. Returns the entry or NULL if the entry was not found. */ @@ -512,12 +674,12 @@ SilcClientEntry silc_client_get_client_by_id(SilcClient client, if (!client_id) return NULL; - SILC_LOG_DEBUG(("Finding client by ID (%s)", + SILC_LOG_DEBUG(("Finding client by ID (%s)", silc_id_render(client_id, SILC_ID_CLIENT))); /* Find ID from cache */ if (!silc_idcache_find_by_id_one_ext(conn->internal->client_cache, - (void *)client_id, NULL, NULL, + (void *)client_id, NULL, NULL, silc_hash_client_id_compare, NULL, &id_cache)) return NULL; @@ -577,7 +739,7 @@ void silc_client_get_client_by_id_resolve(SilcClient client, i->client_id = silc_id_dup(client_id, SILC_ID_CLIENT); i->completion = completion; i->context = context; - + /* Register our own command reply for this command */ silc_client_command_register(client, SILC_COMMAND_WHOIS, NULL, NULL, silc_client_command_reply_whois_i, 0, @@ -593,7 +755,7 @@ void silc_client_get_client_by_id_resolve(SilcClient client, /* Add pending callback */ silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident, - silc_client_command_get_client_by_id_callback, + silc_client_command_get_client_by_id_callback, (void *)i); } @@ -610,7 +772,7 @@ void silc_client_get_client_by_id_resolve(SilcClient client, SilcClientEntry silc_client_add_client(SilcClient client, SilcClientConnection conn, - char *nickname, char *username, + char *nickname, char *username, char *userinfo, SilcClientID *id, SilcUInt32 mode) { SilcClientEntry client_entry; @@ -623,7 +785,7 @@ silc_client_add_client(SilcClient client, SilcClientConnection conn, client_entry->id = id; client_entry->valid = TRUE; silc_parse_userfqdn(nickname, &nick, &client_entry->server); - silc_parse_userfqdn(username, &client_entry->username, + silc_parse_userfqdn(username, &client_entry->username, &client_entry->hostname); if (userinfo) client_entry->realname = strdup(userinfo); @@ -635,9 +797,9 @@ silc_client_add_client(SilcClient client, SilcClientConnection conn, /* Format the nickname */ silc_client_nickname_format(client, conn, client_entry); - + /* Add client to cache, the non-formatted nickname is saved to cache */ - if (!silc_idcache_add(conn->internal->client_cache, nick, client_entry->id, + if (!silc_idcache_add(conn->internal->client_cache, nick, client_entry->id, (void *)client_entry, 0, NULL)) { silc_free(client_entry->nickname); silc_free(client_entry->username); @@ -685,14 +847,14 @@ void silc_client_update_client(SilcClient client, if (nick) { /* Remove the old cache entry and create a new one */ silc_idcache_del_by_context(conn->internal->client_cache, client_entry); - silc_idcache_add(conn->internal->client_cache, nick, client_entry->id, + silc_idcache_add(conn->internal->client_cache, nick, client_entry->id, client_entry, 0, NULL); } } /* Deletes the client entry and frees all memory. */ -void silc_client_del_client_entry(SilcClient client, +void silc_client_del_client_entry(SilcClient client, SilcClientConnection conn, SilcClientEntry client_entry) { @@ -725,11 +887,13 @@ bool silc_client_del_client(SilcClient client, SilcClientConnection conn, bool ret = silc_idcache_del_by_context(conn->internal->client_cache, client_entry); - /* Remove from channels */ - silc_client_remove_from_channels(client, conn, client_entry); + if (ret) { + /* Remove from channels */ + silc_client_remove_from_channels(client, conn, client_entry); - /* Free the client entry data */ - silc_client_del_client_entry(client, conn, client_entry); + /* Free the client entry data */ + silc_client_del_client_entry(client, conn, client_entry); + } return ret; } @@ -739,7 +903,7 @@ bool silc_client_del_client(SilcClient client, SilcClientConnection conn, SilcChannelEntry silc_client_add_channel(SilcClient client, SilcClientConnection conn, const char *channel_name, - SilcUInt32 mode, + SilcUInt32 mode, SilcChannelID *channel_id) { SilcChannelEntry channel; @@ -754,7 +918,7 @@ SilcChannelEntry silc_client_add_channel(SilcClient client, NULL, NULL, NULL, TRUE); /* Put it to the ID cache */ - if (!silc_idcache_add(conn->internal->channel_cache, channel->channel_name, + if (!silc_idcache_add(conn->internal->channel_cache, channel->channel_name, (void *)channel->id, (void *)channel, 0, NULL)) { silc_free(channel->channel_name); silc_hash_table_free(channel->user_list); @@ -792,7 +956,7 @@ bool silc_client_del_channel(SilcClient client, SilcClientConnection conn, SILC_LOG_DEBUG(("Start")); /* 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 + 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); @@ -805,12 +969,20 @@ bool silc_client_del_channel(SilcClient client, SilcClientConnection conn, silc_cipher_free(channel->channel_key); if (channel->hmac) silc_hmac_free(channel->hmac); - if (channel->old_channel_key) - silc_cipher_free(channel->old_channel_key); - if (channel->old_hmac) - silc_hmac_free(channel->old_hmac); - if (channel->rekey_task) - silc_schedule_task_del(conn->client->schedule, channel->rekey_task); + if (channel->old_channel_keys) { + SilcCipher key; + silc_dlist_start(channel->old_channel_keys); + while ((key = silc_dlist_get(channel->old_channel_keys)) != SILC_LIST_END) + silc_cipher_free(key); + silc_dlist_uninit(channel->old_channel_keys); + } + if (channel->old_hmacs) { + SilcHmac hmac; + silc_dlist_start(channel->old_hmacs); + while ((hmac = silc_dlist_get(channel->old_hmacs)) != SILC_LIST_END) + silc_hmac_free(hmac); + silc_dlist_uninit(channel->old_hmacs); + } silc_client_del_channel_private_keys(client, conn, channel); silc_free(channel); return ret; @@ -827,16 +999,16 @@ bool silc_client_replace_channel_id(SilcClient client, if (!new_id) return FALSE; - SILC_LOG_DEBUG(("Old Channel ID id(%s)", + 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_LOG_DEBUG(("New Channel ID id(%s)", silc_id_render(new_id, SILC_ID_CHANNEL))); silc_idcache_del_by_id(conn->internal->channel_cache, channel->id); silc_free(channel->id); channel->id = new_id; return silc_idcache_add(conn->internal->channel_cache, - channel->channel_name, + channel->channel_name, (void *)channel->id, (void *)channel, 0, NULL); } @@ -858,7 +1030,7 @@ SilcChannelEntry silc_client_get_channel(SilcClient client, SILC_LOG_DEBUG(("Start")); - if (!silc_idcache_find_by_name_one(conn->internal->channel_cache, channel, + if (!silc_idcache_find_by_name_one(conn->internal->channel_cache, channel, &id_cache)) return NULL; @@ -886,7 +1058,7 @@ SilcChannelEntry silc_client_get_channel_by_id(SilcClient client, SILC_LOG_DEBUG(("Start")); - if (!silc_idcache_find_by_id_one(conn->internal->channel_cache, channel_id, + if (!silc_idcache_find_by_id_one(conn->internal->channel_cache, channel_id, &id_cache)) return NULL; @@ -900,27 +1072,85 @@ SilcChannelEntry silc_client_get_channel_by_id(SilcClient client, typedef struct { SilcClient client; SilcClientConnection conn; - SilcChannelID *channel_id; + union { + SilcChannelID *channel_id; + char *channel_name; + } u; SilcGetChannelCallback completion; void *context; -} *GetChannelByIDInternal; +} *GetChannelInternal; + +SILC_CLIENT_CMD_FUNC(get_channel_resolve_callback) +{ + GetChannelInternal i = (GetChannelInternal)context; + SilcChannelEntry entry; + + SILC_LOG_DEBUG(("Start")); + + /* Get the channel */ + entry = silc_client_get_channel(i->client, i->conn, i->u.channel_name); + if (entry) { + i->completion(i->client, i->conn, &entry, 1, i->context); + } else { + i->completion(i->client, i->conn, NULL, 0, i->context); + } + + silc_free(i->u.channel_name); + silc_free(i); +} + +/* Resolves channel entry from the server by the channel name. */ + +void silc_client_get_channel_resolve(SilcClient client, + SilcClientConnection conn, + char *channel_name, + SilcGetChannelCallback completion, + void *context) +{ + GetChannelInternal i = silc_calloc(1, sizeof(*i)); + + assert(client && conn && channel_name); + + SILC_LOG_DEBUG(("Start")); + + i->client = client; + i->conn = conn; + i->u.channel_name = strdup(channel_name); + i->completion = completion; + i->context = context; + + /* 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 */ + silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY, + conn->cmd_ident, + 1, 3, channel_name, strlen(channel_name)); + + /* Add pending callback */ + silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident, + silc_client_command_get_channel_resolve_callback, + (void *)i); +} SILC_CLIENT_CMD_FUNC(get_channel_by_id_callback) { - GetChannelByIDInternal i = (GetChannelByIDInternal)context; + GetChannelInternal i = (GetChannelInternal)context; SilcChannelEntry entry; SILC_LOG_DEBUG(("Start")); /* Get the channel */ - entry = silc_client_get_channel_by_id(i->client, i->conn, i->channel_id); + entry = silc_client_get_channel_by_id(i->client, i->conn, i->u.channel_id); if (entry) { i->completion(i->client, i->conn, &entry, 1, i->context); } else { i->completion(i->client, i->conn, NULL, 0, i->context); } - silc_free(i->channel_id); + silc_free(i->u.channel_id); silc_free(i); } @@ -933,7 +1163,7 @@ void silc_client_get_channel_by_id_resolve(SilcClient client, void *context) { SilcBuffer idp; - GetChannelByIDInternal i = silc_calloc(1, sizeof(*i)); + GetChannelInternal i = silc_calloc(1, sizeof(*i)); assert(client && conn && channel_id); @@ -941,10 +1171,10 @@ void silc_client_get_channel_by_id_resolve(SilcClient client, i->client = client; i->conn = conn; - i->channel_id = silc_id_dup(channel_id, SILC_ID_CHANNEL); + i->u.channel_id = silc_id_dup(channel_id, SILC_ID_CHANNEL); i->completion = completion; i->context = context; - + /* 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, @@ -952,14 +1182,14 @@ void silc_client_get_channel_by_id_resolve(SilcClient client, /* Send the command */ idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL); - silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY, + silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident, 1, 5, idp->data, idp->len); silc_buffer_free(idp); /* Add pending callback */ silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident, - silc_client_command_get_channel_by_id_callback, + silc_client_command_get_channel_by_id_callback, (void *)i); } @@ -1093,7 +1323,7 @@ void silc_client_update_server(SilcClient client, nickname and replace the old nickname in the client entry. If the format string is not specified then this function has no effect. */ -void silc_client_nickname_format(SilcClient client, +void silc_client_nickname_format(SilcClient client, SilcClientConnection conn, SilcClientEntry client_entry) {