/*
- 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;
int i = 0;
bool found = FALSE;
+ assert(client && conn);
+ if (!nickname)
+ return NULL;
+
/* Find ID from cache */
- if (!silc_idcache_find_by_name(conn->client_cache, (char *)nickname, &list))
+ if (!silc_idcache_find_by_name(conn->internal->client_cache,
+ (char *)nickname, &list))
return NULL;
if (!silc_idcache_list_count(list)) {
void *context;
char *nickname;
char *server;
- bool found;
} *GetClientInternal;
SILC_CLIENT_CMD_FUNC(get_client_callback)
{
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,
i->nickname, i->server,
&clients_count);
if (clients) {
- i->completion(i->client, i->conn, clients,
- clients_count, i->context);
- i->found = TRUE;
+ i->completion(i->client, i->conn, clients, clients_count, i->context);
silc_free(clients);
- }
-}
-
-static void silc_client_get_client_destructor(void *context)
-{
- GetClientInternal i = (GetClientInternal)context;
-
- if (i->found == FALSE)
+ } else {
i->completion(i->client, i->conn, NULL, 0, i->context);
+ }
silc_free(i->nickname);
silc_free(i->server);
void *context)
{
GetClientInternal i;
+ int len;
char *userhost;
+ assert(client && conn);
+
if (!nickname)
return;
i->context = context;
if (nickname && server) {
- userhost = silc_calloc(strlen(nickname) + strlen(server) + 2,
- sizeof(*userhost));
- strncat(userhost, nickname, strlen(nickname));
- strncat(userhost, "@", 1);
- strncat(userhost, server, strlen(server));
+ len = strlen(nickname) + strlen(server) + 3;
+ userhost = silc_calloc(len, sizeof(*userhost));
+ silc_strncat(userhost, len, nickname, strlen(nickname));
+ silc_strncat(userhost, len, "@", 1);
+ silc_strncat(userhost, len, server, strlen(server));
} else {
- userhost = strdup(nickname);
+ userhost = silc_memdup(nickname, strlen(nickname));
}
/* Register our own command reply for this command */
/* Add pending callback */
silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
- silc_client_get_client_destructor,
silc_client_command_get_client_callback,
(void *)i);
SILC_LOG_DEBUG(("Start"));
/* Find ID from cache */
- if (!silc_idcache_find_by_name(conn->client_cache, (char *)nickname,
- &list)) {
+ if (!silc_idcache_find_by_name(conn->internal->client_cache,
+ (char *)nickname, &list)) {
identify:
if (query) {
typedef struct {
SilcClient client;
SilcClientConnection conn;
- uint32 list_count;
+ SilcUInt32 list_count;
SilcBuffer client_id_list;
SilcGetClientCallback completion;
void *context;
- int found;
+ int res_count;
} *GetClientsByListInternal;
SILC_CLIENT_CMD_FUNC(get_clients_list_callback)
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"));
+ if (i->res_count) {
+ i->res_count--;
+ if (i->res_count)
+ return;
+ }
+
+ SILC_LOG_DEBUG(("Resolved all clients"));
+
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;
}
/* Get the client entry */
- if (silc_idcache_find_by_id_one_ext(i->conn->client_cache,
+ if (silc_idcache_find_by_id_one_ext(i->conn->internal->client_cache,
(void *)client_id,
NULL, NULL,
silc_hash_client_id_compare, NULL,
(clients_count + 1));
clients[clients_count] = (SilcClientEntry)id_cache->context;
clients_count++;
- i->found = TRUE;
+ found = TRUE;
}
silc_free(client_id);
silc_buffer_pull(client_id_list, idp_len);
}
- if (i->found) {
+ if (found) {
i->completion(i->client, i->conn, clients, clients_count, i->context);
silc_free(clients);
- }
-}
-
-static void silc_client_get_clients_list_destructor(void *context)
-{
- GetClientsByListInternal i = (GetClientsByListInternal)context;
-
- SILC_LOG_DEBUG(("Start"));
-
- if (i->found == FALSE)
+ } else {
i->completion(i->client, i->conn, NULL, 0, i->context);
+ }
if (i->client_id_list)
silc_buffer_free(i->client_id_list);
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;
+
+ assert(client && conn && client_id_list);
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->internal->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;
+ in->res_count++;
+
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
- table that will be sent fr the IDENTIFY command later. */
+ table that will be sent for the IDENTIFY 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) *
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) {
/* Process the applications request after reply has been received */
silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
- silc_client_get_clients_list_destructor,
silc_client_command_get_clients_list_callback,
(void *)in);
+ in->res_count++;
- 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);
{
SilcIDCacheEntry id_cache;
+ assert(client && conn);
+ if (!client_id)
+ return NULL;
+
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->client_cache, (void *)client_id,
- NULL, NULL,
+ if (!silc_idcache_find_by_id_one_ext(conn->internal->client_cache,
+ (void *)client_id, NULL, NULL,
silc_hash_client_id_compare, NULL,
&id_cache))
return NULL;
SilcClientID *client_id;
SilcGetClientCallback completion;
void *context;
- int found;
} *GetClientByIDInternal;
SILC_CLIENT_CMD_FUNC(get_client_by_id_callback)
SilcClientEntry entry;
/* Get the client */
- entry = silc_client_get_client_by_id(i->client, i->conn,
- i->client_id);
+ 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);
- i->found = TRUE;
+ 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);
}
-}
-
-static void silc_client_get_client_by_id_destructor(void *context)
-{
- GetClientByIDInternal i = (GetClientByIDInternal)context;
- if (i->found == FALSE)
- i->completion(i->client, i->conn, NULL, 0, i->context);
-
- if (i->client_id)
- silc_free(i->client_id);
+ silc_free(i->client_id);
silc_free(i);
}
void silc_client_get_client_by_id_resolve(SilcClient client,
SilcClientConnection conn,
SilcClientID *client_id,
+ SilcBuffer attributes,
SilcGetClientCallback completion,
void *context)
{
SilcBuffer idp;
GetClientByIDInternal i = silc_calloc(1, sizeof(*i));
+ assert(client && conn && client_id);
+
SILC_LOG_DEBUG(("Start"));
i->client = client;
/* Send the command */
idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
silc_client_command_send(client, conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
- 1, 3, idp->data, idp->len);
+ 2, 3, attributes ? attributes->data : NULL,
+ attributes ? attributes->len : 0,
+ 4, idp->data, idp->len);
silc_buffer_free(idp);
/* Add pending callback */
silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
- silc_client_get_client_by_id_destructor,
silc_client_command_get_client_by_id_callback,
(void *)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);
/* Add client to cache, the non-formatted nickname is saved to cache */
- if (!silc_idcache_add(conn->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);
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_LOG_DEBUG(("Start"));
- if (!client_entry->username && username)
- silc_parse_userfqdn(username, &client_entry->username,
+ if ((!client_entry->username || !client_entry->hostname) && username) {
+ silc_free(client_entry->username);
+ silc_free(client_entry->hostname);
+ client_entry->username = NULL;
+ client_entry->hostname = NULL;
+ silc_parse_userfqdn(username, &client_entry->username,
&client_entry->hostname);
+ }
if (!client_entry->realname && userinfo)
client_entry->realname = strdup(userinfo);
if (!client_entry->nickname && nickname) {
if (nick) {
/* Remove the old cache entry and create a new one */
- silc_idcache_del_by_context(conn->client_cache, client_entry);
- silc_idcache_add(conn->client_cache, nick, client_entry->id,
+ silc_idcache_del_by_context(conn->internal->client_cache, client_entry);
+ silc_idcache_add(conn->internal->client_cache, nick, client_entry->id,
client_entry, 0, 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)
bool silc_client_del_client(SilcClient client, SilcClientConnection conn,
SilcClientEntry client_entry)
{
- bool ret = silc_idcache_del_by_context(conn->client_cache, client_entry);
+ 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);
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->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);
+ 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);
+ bool ret = silc_idcache_del_by_context(conn->internal->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->internal->channel_cache, channel->id);
+ silc_free(channel->id);
+ channel->id = new_id;
+ return silc_idcache_add(conn->internal->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. */
SilcIDCacheEntry id_cache;
SilcChannelEntry entry;
+ assert(client && conn);
+ if (!channel)
+ return NULL;
+
SILC_LOG_DEBUG(("Start"));
- if (!silc_idcache_find_by_name_one(conn->channel_cache, channel,
+ if (!silc_idcache_find_by_name_one(conn->internal->channel_cache, channel,
&id_cache))
return NULL;
SilcIDCacheEntry id_cache;
SilcChannelEntry entry;
+ assert(client && conn);
+ if (!channel_id)
+ return NULL;
+
SILC_LOG_DEBUG(("Start"));
- if (!silc_idcache_find_by_id_one(conn->channel_cache, channel_id,
+ if (!silc_idcache_find_by_id_one(conn->internal->channel_cache, channel_id,
&id_cache))
return NULL;
SilcChannelID *channel_id;
SilcGetChannelCallback completion;
void *context;
- int found;
} *GetChannelByIDInternal;
SILC_CLIENT_CMD_FUNC(get_channel_by_id_callback)
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->channel_id);
if (entry) {
i->completion(i->client, i->conn, &entry, 1, i->context);
- i->found = TRUE;
- }
-}
-
-static void silc_client_get_channel_by_id_destructor(void *context)
-{
- GetChannelByIDInternal i = (GetChannelByIDInternal)context;
-
- if (i->found == FALSE)
+ } else {
i->completion(i->client, i->conn, NULL, 0, i->context);
+ }
silc_free(i->channel_id);
silc_free(i);
SilcBuffer idp;
GetChannelByIDInternal i = silc_calloc(1, sizeof(*i));
+ assert(client && conn && channel_id);
+
SILC_LOG_DEBUG(("Start"));
i->client = client;
/* Add pending callback */
silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
- silc_client_get_channel_by_id_destructor,
silc_client_command_get_channel_by_id_callback,
(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,
SilcIDCacheEntry id_cache;
SilcServerEntry entry;
+ assert(client && conn);
+ if (!server_name)
+ return NULL;
+
SILC_LOG_DEBUG(("Start"));
- if (!silc_idcache_find_by_name_one(conn->server_cache, server_name,
- &id_cache))
+ if (!silc_idcache_find_by_name_one(conn->internal->server_cache,
+ server_name, &id_cache))
return NULL;
entry = (SilcServerEntry)id_cache->context;
SilcIDCacheEntry id_cache;
SilcServerEntry entry;
+ assert(client && conn);
+ if (!server_id)
+ return NULL;
+
SILC_LOG_DEBUG(("Start"));
- if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
- &id_cache))
+ if (!silc_idcache_find_by_id_one(conn->internal->server_cache,
+ (void *)server_id, &id_cache))
return NULL;
entry = (SilcServerEntry)id_cache->context;
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;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ 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->internal->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,
SilcServerEntry server)
{
- bool ret = silc_idcache_del_by_context(conn->server_cache, server);
+ bool ret = silc_idcache_del_by_context(conn->internal->server_cache, server);
silc_free(server->server_name);
silc_free(server->server_info);
silc_free(server->server_id);
return ret;
}
+/* Updates the `server_entry' with the new information sent as argument. */
+
+void silc_client_update_server(SilcClient client,
+ SilcClientConnection conn,
+ SilcServerEntry server_entry,
+ const char *server_name,
+ const char *server_info)
+{
+ SILC_LOG_DEBUG(("Start"));
+
+ if (server_name && (!server_entry->server_name ||
+ strcmp(server_entry->server_name, server_name))) {
+
+ silc_idcache_del_by_context(conn->internal->server_cache, server_entry);
+ silc_free(server_entry->server_name);
+ server_entry->server_name = strdup(server_name);
+ silc_idcache_add(conn->internal->server_cache, server_entry->server_name,
+ server_entry->server_id,
+ server_entry, 0, NULL);
+ }
+
+ if (server_info && (!server_entry->server_info ||
+ strcmp(server_entry->server_info, server_info))) {
+ silc_free(server_entry->server_info);
+ server_entry->server_info = strdup(server_info);
+ }
+}
+
/* Formats the nickname of the client specified by the `client_entry'.
If the format is specified by the application this will format the
nickname and replace the old nickname in the client entry. If the
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;
if (!client_entry->hostname)
break;
len = strcspn(client_entry->hostname, ".");
+ i = strcspn(client_entry->hostname, "-");
+ if (i < len)
+ len = i;
newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
memcpy(&newnick[off], client_entry->hostname, len);
off += len;
char tmp[6];
int num, max = 1;
- if (clients_count == 1)
+ if (clients_count == 1) {
+ unformatted = clients[0];
break;
+ }
for (i = 0; i < clients_count; i++) {
+ if (!strncasecmp(clients[i]->nickname, client_entry->nickname,
+ strlen(clients[i]->nickname)))
+ unformatted = clients[i];
if (strncasecmp(clients[i]->nickname, newnick, off))
continue;
if (strlen(clients[i]->nickname) <= off)
if (num > max)
max = num;
}
-
+
memset(tmp, 0, sizeof(tmp));
snprintf(tmp, sizeof(tmp) - 1, "%d", ++max);
len = strlen(tmp);
newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
newnick[off] = 0;
+ /* If we are changing nickname of our local entry we'll enforce
+ that we will always get the unformatted nickname. Give our
+ format number to the one that is not formatted now. */
+ if (unformatted && client_entry == conn->local_entry)
+ client_entry = unformatted;
+
silc_free(client_entry->nickname);
client_entry->nickname = newnick;
silc_free(clients);