/*
- 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
*/
/* $Id$ */
-#include "clientlibincludes.h"
+#include "silcincludes.h"
+#include "silcclient.h"
#include "client_internal.h"
/******************************************************************************
SilcClientConnection conn,
const char *nickname,
const char *format,
- uint32 *clients_count)
+ SilcUInt32 *clients_count)
{
SilcIDCacheEntry id_cache;
SilcIDCacheList list = NULL;
{
GetClientInternal i = (GetClientInternal)context;
SilcClientEntry *clients;
- uint32 clients_count;
+ SilcUInt32 clients_count;
/* Get the clients */
clients = silc_client_get_clients_local(i->client, i->conn,
typedef struct {
SilcClient client;
SilcClientConnection conn;
- uint32 list_count;
+ SilcUInt32 list_count;
SilcBuffer client_id_list;
SilcGetClientCallback completion;
void *context;
SilcIDCacheEntry id_cache = NULL;
SilcBuffer client_id_list = i->client_id_list;
SilcClientEntry *clients = NULL;
- uint32 clients_count = 0;
+ SilcUInt32 clients_count = 0;
bool found = FALSE;
int c;
SILC_LOG_DEBUG(("Start"));
for (c = 0; c < i->list_count; c++) {
- uint16 idp_len;
+ SilcUInt16 idp_len;
SilcClientID *client_id;
/* Get Client ID */
SILC_GET16_MSB(idp_len, client_id_list->data + 2);
idp_len += 4;
- client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
+ client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
if (!client_id) {
silc_buffer_pull(client_id_list, idp_len);
continue;
void silc_client_get_clients_by_list(SilcClient client,
SilcClientConnection conn,
- uint32 list_count,
+ SilcUInt32 list_count,
SilcBuffer client_id_list,
SilcGetClientCallback completion,
void *context)
SilcIDCacheEntry id_cache = NULL;
int i;
unsigned char **res_argv = NULL;
- uint32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
+ SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
GetClientsByListInternal in;
+ bool wait_res = FALSE;
SILC_LOG_DEBUG(("Start"));
in->context = context;
for (i = 0; i < list_count; i++) {
- uint16 idp_len;
+ SilcUInt16 idp_len;
SilcClientID *client_id;
SilcClientEntry entry;
+ bool ret;
/* Get Client ID */
SILC_GET16_MSB(idp_len, client_id_list->data + 2);
idp_len += 4;
- client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
+ client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
if (!client_id) {
silc_buffer_pull(client_id_list, idp_len);
continue;
}
/* 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);
+ ret =
+ silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
+ NULL, NULL,
+ silc_hash_client_id_compare, NULL,
+ &id_cache);
/* If we don't have the entry or it has incomplete info, then resolve
it from the server. */
- entry = id_cache ? (SilcClientEntry)id_cache->context : NULL;
- if (!id_cache || !entry->nickname) {
+ if (!ret || !((SilcClientEntry)id_cache->context)->nickname) {
+ entry = ret ? (SilcClientEntry)id_cache->context : NULL;
if (entry) {
if (entry->status & SILC_CLIENT_STATUS_RESOLVING) {
- 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_list_callback,
+ (void *)in);
+ wait_res = TRUE;
+
silc_free(client_id);
silc_buffer_pull(client_id_list, idp_len);
continue;
}
entry->status |= SILC_CLIENT_STATUS_RESOLVING;
+ entry->resolve_cmd_ident = conn->cmd_ident + 1;
}
/* No we don't have it, query it from the server. Assemble argument
silc_buffer_pull(client_id_list, idp_len);
}
+ 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
that we don't know about. */
if (res_argc) {
silc_client_command_get_clients_list_callback,
(void *)in);
- silc_buffer_push(client_id_list, client_id_list->data -
- client_id_list->head);
silc_buffer_free(res_cmd);
silc_free(res_argv);
silc_free(res_argv_lens);
return;
}
- silc_buffer_push(client_id_list, client_id_list->data -
- client_id_list->head);
+ if (wait_res)
+ return;
/* We have the clients in cache, get them and call the completion */
silc_client_command_get_clients_list_callback((void *)in, NULL);
/* Get the client */
entry = silc_client_get_client_by_id(i->client, i->conn, i->client_id);
- if (entry)
- i->completion(i->client, i->conn, &entry, 1, i->context);
- else
- i->completion(i->client, i->conn, NULL, 0, i->context);
+ if (entry) {
+ if (i->completion)
+ i->completion(i->client, i->conn, &entry, 1, i->context);
+ } else {
+ if (i->completion)
+ i->completion(i->client, i->conn, NULL, 0, i->context);
+ }
silc_free(i->client_id);
silc_free(i);
SilcClientEntry
silc_client_add_client(SilcClient client, SilcClientConnection conn,
char *nickname, char *username,
- char *userinfo, SilcClientID *id, uint32 mode)
+ char *userinfo, SilcClientID *id, SilcUInt32 mode)
{
SilcClientEntry client_entry;
char *nick = NULL;
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;
}
const char *nickname,
const char *username,
const char *userinfo,
- uint32 mode)
+ SilcUInt32 mode)
{
char *nick = NULL;
silc_free(client_entry->nickname);
silc_free(client_entry->username);
silc_free(client_entry->realname);
+ silc_free(client_entry->hostname);
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,
+ SilcUInt32 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;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* 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);
+
+ 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
+ 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,
return entry;
}
+/* Add new server entry */
+
+SilcServerEntry silc_client_add_server(SilcClient client,
+ SilcClientConnection conn,
+ const char *server_name,
+ const char *server_info,
+ SilcServerID *server_id)
+{
+ SilcServerEntry server_entry;
+
+ server_entry = silc_calloc(1, sizeof(*server_entry));
+ if (!server_entry || !server_id)
+ return NULL;
+
+ server_entry->server_id = server_id;
+ if (server_name)
+ server_entry->server_name = strdup(server_name);
+ if (server_info)
+ server_entry->server_info = strdup(server_info);
+
+ /* Add server to cache */
+ if (!silc_idcache_add(conn->server_cache, server_entry->server_name,
+ server_entry->server_id, server_entry, 0, NULL)) {
+ silc_free(server_entry->server_id);
+ silc_free(server_entry->server_name);
+ silc_free(server_entry->server_info);
+ silc_free(server_entry);
+ return NULL;
+ }
+
+ return server_entry;
+}
+
/* Removes server from the cache by the server entry. */
bool silc_client_del_server(SilcClient client, SilcClientConnection conn,
char *cp;
char *newnick = NULL;
int i, off = 0, len;
+ bool freebase;
SilcClientEntry *clients;
- uint32 clients_count = 0;
+ SilcUInt32 clients_count = 0;
SilcClientEntry unformatted = NULL;
SILC_LOG_DEBUG(("Start"));
return;
len = 0;
- for (i = 0; i < clients_count; i++)
+ freebase = TRUE;
+ for (i = 0; i < clients_count; i++) {
if (clients[i]->valid && clients[i] != client_entry)
len++;
- if (!len)
+ if (clients[i]->valid && clients[i] != client_entry &&
+ !strcmp(clients[i]->nickname, client_entry->nickname))
+ freebase = FALSE;
+ }
+ if (!len || freebase)
return;
cp = client->internal->params->nickname_format;