/*
- idlist.c
+ idlist.c
Author: Pekka Riikonen <priikone@silcnet.org>
- 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
int i = 0;
bool found = FALSE;
+ assert(client && conn);
+ if (!nickname)
+ return NULL;
+
/* Find ID from cache */
if (!silc_idcache_find_by_name(conn->internal->client_cache,
(char *)nickname, &list))
continue;
}
}
-
+
clients[i++] = id_cache->context;
found = TRUE;
if (!silc_idcache_list_next(list, &id_cache))
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
int len;
char *userhost;
+ assert(client && conn);
+
if (!nickname)
return;
++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);
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));
return entry;
}
-
typedef struct {
SilcClient client;
SilcClientConnection conn;
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;
}
/* 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;
GetClientsByListInternal in;
bool wait_res = FALSE;
+ assert(client && conn && client_id_list);
+
SILC_LOG_DEBUG(("Start"));
in = silc_calloc(1, sizeof(*in));
/* 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);
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++;
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
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);
/* 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++;
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. */
{
SilcIDCacheEntry id_cache;
- SILC_LOG_DEBUG(("Finding client by ID (%s)",
+ 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->internal->client_cache,
- (void *)client_id, NULL, NULL,
+ (void *)client_id, NULL, NULL,
silc_hash_client_id_compare, NULL,
&id_cache))
return NULL;
SilcBuffer idp;
GetClientByIDInternal i = silc_calloc(1, sizeof(*i));
+ assert(client && conn && client_id);
+
SILC_LOG_DEBUG(("Start"));
i->client = 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,
/* 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);
}
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;
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);
/* 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);
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)
{
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;
}
SilcChannelEntry silc_client_add_channel(SilcClient client,
SilcClientConnection conn,
const char *channel_name,
- SilcUInt32 mode,
+ SilcUInt32 mode,
SilcChannelID *channel_id)
{
SilcChannelEntry channel;
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);
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);
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;
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);
}
SilcIDCacheEntry id_cache;
SilcChannelEntry entry;
+ assert(client && conn);
+ if (!channel)
+ return NULL;
+
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;
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->internal->channel_cache, channel_id,
+ if (!silc_idcache_find_by_id_one(conn->internal->channel_cache, channel_id,
&id_cache))
return NULL;
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);
}
void *context)
{
SilcBuffer idp;
- GetChannelByIDInternal i = silc_calloc(1, sizeof(*i));
+ GetChannelInternal i = silc_calloc(1, sizeof(*i));
+
+ assert(client && conn && channel_id);
SILC_LOG_DEBUG(("Start"));
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,
/* 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);
}
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->internal->server_cache,
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->internal->server_cache,
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)
{
if (!len || freebase)
return;
+ if (clients_count == 1)
+ unformatted = clients[0];
+ else
+ for (i = 0; i < clients_count; i++)
+ if (!strncasecmp(clients[i]->nickname, client_entry->nickname,
+ strlen(clients[i]->nickname)))
+ unformatted = clients[i];
+
+ /* 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;
+
cp = client->internal->params->nickname_format;
while (*cp) {
if (*cp == '%') {
char tmp[6];
int num, max = 1;
- if (clients_count == 1) {
- unformatted = clients[0];
+ if (clients_count == 1)
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)
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);