Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2001 - 2003 Pekka Riikonen
+ Copyright (C) 2001 - 2005 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
*/
/* $Id$ */
-#include "silcincludes.h"
+#include "silc.h"
#include "silcclient.h"
#include "client_internal.h"
SilcIDCacheList list = NULL;
SilcClientEntry entry, *clients;
int i = 0;
- bool found = FALSE;
+ SilcBool found = FALSE;
+ char *nicknamec;
assert(client && conn);
if (!nickname)
return NULL;
+ /* Normalize nickname for search */
+ nicknamec = silc_identifier_check(nickname, strlen(nickname),
+ SILC_STRING_UTF8, 128, NULL);
+ if (!nicknamec)
+ return NULL;
+
/* Find ID from cache */
- if (!silc_idcache_find_by_name(conn->internal->client_cache,
- (char *)nickname, &list))
+ if (!silc_idcache_find_by_name(conn->internal->client_cache, nicknamec,
+ &list)) {
+ silc_free(nicknamec);
return NULL;
+ }
if (!silc_idcache_list_count(list)) {
silc_idcache_list_free(list);
+ silc_free(nicknamec);
return NULL;
}
silc_idcache_list_first(list, &id_cache);
while (id_cache) {
entry = (SilcClientEntry)id_cache->context;
- if (strcasecmp(entry->nickname, format)) {
+ if (!silc_utf8_strcasecmp(entry->nickname, format)) {
if (!silc_idcache_list_next(list, &id_cache)) {
break;
} else {
}
}
+ silc_free(nicknamec);
+
if (list)
silc_idcache_list_free(list);
SilcGetClientCallback completion;
void *context;
char *nickname;
- char *server;
+ SilcClientEntry *clients;
+ SilcUInt32 clients_count;
} *GetClientInternal;
+/* Completion for IDENTIFY */
+
SILC_CLIENT_CMD_FUNC(get_client_callback)
{
GetClientInternal i = (GetClientInternal)context;
/* Get the clients */
clients = silc_client_get_clients_local(i->client, i->conn,
- i->nickname, i->server,
+ i->nickname, NULL,
&clients_count);
if (clients) {
i->completion(i->client, i->conn, clients, clients_count, i->context);
}
silc_free(i->nickname);
- silc_free(i->server);
silc_free(i);
}
+/* Completion for WHOIS */
+
+SILC_CLIENT_CMD_FUNC(get_client_callback_wc)
+{
+ GetClientInternal i = (GetClientInternal)context;
+ SilcClientCommandReplyContext cmd = context2;
+ SilcClientID *client_id = NULL;
+ SilcClientEntry client_entry = NULL;
+ unsigned char *id_data;
+ SilcUInt32 len;
+
+ /* Get the client entry just returned from server */
+ id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
+ if (id_data)
+ client_id = silc_id_payload_parse_id(id_data, len, NULL);
+ if (client_id)
+ client_entry = silc_client_get_client_by_id(i->client,
+ i->conn, client_id);
+ if (!client_entry) {
+ if (!SILC_STATUS_IS_ERROR(cmd->status) &&
+ cmd->status != SILC_STATUS_OK &&
+ cmd->status != SILC_STATUS_LIST_END) {
+ silc_free(client_id);
+ return;
+ }
+
+ i->completion(i->client, i->conn, i->clients, i->clients_count,
+ i->context);
+ silc_free(client_id);
+ silc_free(i->clients);
+ silc_free(i->nickname);
+ silc_free(i);
+ return;
+ }
+
+ /* Save the client */
+ i->clients = silc_realloc(i->clients,
+ (sizeof(*i->clients) * (i->clients_count + 1)));
+ i->clients[i->clients_count] = client_entry;
+ i->clients_count++;
+
+ /* Return if more data is expected */
+ if (cmd->status != SILC_STATUS_OK &&
+ cmd->status != SILC_STATUS_LIST_END) {
+ silc_free(client_id);
+ return;
+ }
+
+ i->completion(i->client, i->conn, i->clients, i->clients_count,
+ i->context);
+
+ silc_free(client_id);
+ silc_free(i->clients);
+ silc_free(i->nickname);
+ silc_free(i);
+}
+
+/* Our own WHOIS reply processor. */
+
+SILC_CLIENT_CMD_FUNC(get_client_callback_w)
+{
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (!silc_command_get_status(cmd->payload, NULL, NULL)) {
+ if (SILC_STATUS_IS_ERROR(cmd->status))
+ goto out;
+ if (cmd->status == SILC_STATUS_LIST_END)
+ goto out;
+ goto err;
+ }
+
+ /* Save WHOIS info */
+ silc_client_command_reply_whois_save(cmd, cmd->status, FALSE);
+
+ /* Call pending completion for each reply */
+ if (cmd->status != SILC_STATUS_OK &&
+ cmd->status != SILC_STATUS_LIST_END) {
+ if (cmd->callbacks[0].callback)
+ (*cmd->callbacks[0].callback)(cmd->callbacks[0].context, cmd);
+ silc_client_command_reply_free(cmd);
+ return;
+ }
+
+ out:
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
+
+ err:
+ /* If we received notify for invalid ID we'll remove the ID if we
+ have it cached. */
+ if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
+ SilcClientEntry client_entry;
+ SilcUInt32 tmp_len;
+ unsigned char *tmp =
+ silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
+ 2, &tmp_len);
+ if (tmp) {
+ SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+ if (client_id) {
+ client_entry = silc_client_get_client_by_id(cmd->client, conn,
+ client_id);
+ if (client_entry)
+ silc_client_del_client(cmd->client, conn, client_entry);
+ silc_free(client_id);
+ }
+ }
+ }
+
+ /* Unregister this command reply */
+ silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
+ NULL, silc_client_command_reply_whois_i,
+ cmd->ident);
+ silc_client_command_reply_free(cmd);
+}
+
/* Finds client entry or entries by the `nickname' and `server'. The
completion callback will be called when the client entries has been found.
get the client entry since this function may be very slow and should
be used only to initially get the client entries. */
-void silc_client_get_clients(SilcClient client,
- SilcClientConnection conn,
- const char *nickname,
- const char *server,
- SilcGetClientCallback completion,
- void *context)
+void silc_client_get_clients_i(SilcClient client,
+ SilcClientConnection conn,
+ SilcCommand command,
+ const char *nickname,
+ const char *server,
+ SilcBuffer attributes,
+ SilcGetClientCallback completion,
+ void *context)
{
GetClientInternal i;
int len;
- char *userhost;
+ char *userhost = NULL;
assert(client && conn);
- if (!nickname)
+ if (!nickname && !attributes)
return;
i = silc_calloc(1, sizeof(*i));
i->client = client;
i->conn = conn;
- i->nickname = strdup(nickname);
- i->server = server ? strdup(server) : NULL;
+ i->nickname = nickname ? strdup(nickname) : NULL;
i->completion = completion;
i->context = context;
silc_strncat(userhost, len, nickname, strlen(nickname));
silc_strncat(userhost, len, "@", 1);
silc_strncat(userhost, len, server, strlen(server));
- } else {
+ } else if (nickname) {
userhost = silc_memdup(nickname, strlen(nickname));
}
/* 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, 1, userhost,
- strlen(userhost));
+ if (command == SILC_COMMAND_IDENTIFY) {
+ silc_client_command_register(client, command, 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, 1, userhost,
+ strlen(userhost));
+
+ /* Add pending callback */
+ silc_client_command_pending(conn, command, conn->cmd_ident,
+ silc_client_command_get_client_callback,
+ (void *)i);
+ } else {
+ silc_client_command_register(client, command, NULL, NULL,
+ silc_client_command_get_client_callback_w, 0,
+ ++conn->cmd_ident);
+ /* Send the command */
+ silc_client_command_send(client, conn, command, conn->cmd_ident, 2,
+ 1, userhost, userhost ? strlen(userhost) : 0,
+ 3, attributes ? attributes->data : NULL,
+ attributes ? attributes->len : 0);
+
+ /* Add pending callback */
+ silc_client_command_pending(conn, command, conn->cmd_ident,
+ silc_client_command_get_client_callback_wc,
+ (void *)i);
+ }
+ silc_free(userhost);
+}
- /* Add pending callback */
- silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
- silc_client_command_get_client_callback,
- (void *)i);
+void silc_client_get_clients(SilcClient client,
+ SilcClientConnection conn,
+ const char *nickname,
+ const char *server,
+ SilcGetClientCallback completion,
+ void *context)
+{
+ silc_client_get_clients_i(client, conn, SILC_COMMAND_IDENTIFY,
+ nickname, server, NULL,
+ completion, context);
+}
- silc_free(userhost);
+void silc_client_get_clients_whois(SilcClient client,
+ SilcClientConnection conn,
+ const char *nickname,
+ const char *server,
+ SilcBuffer attributes,
+ SilcGetClientCallback completion,
+ void *context)
+{
+ silc_client_get_clients_i(client, conn, SILC_COMMAND_WHOIS,
+ nickname, server, attributes,
+ completion, context);
}
/* The old style function to find client entry. This is used by the
SilcClientConnection conn,
const char *nickname,
const char *format,
- bool query)
+ SilcBool query)
{
SilcIDCacheEntry id_cache;
SilcIDCacheList list = NULL;
SilcClientEntry entry = NULL;
+ char *nicknamec;
SILC_LOG_DEBUG(("Start"));
+ /* Normalize nickname for search */
+ nicknamec = silc_identifier_check(nickname, strlen(nickname),
+ SILC_STRING_UTF8, 128, NULL);
+ if (!nicknamec)
+ return NULL;
+
/* Find ID from cache */
if (!silc_idcache_find_by_name(conn->internal->client_cache,
- (char *)nickname, &list)) {
+ nicknamec, &list)) {
identify:
if (query) {
if (list)
silc_idcache_list_free(list);
+ silc_free(nicknamec);
return NULL;
}
+
+ silc_free(nicknamec);
return NULL;
}
while (id_cache) {
entry = (SilcClientEntry)id_cache->context;
- if (strcasecmp(entry->nickname, format)) {
+ if (!silc_utf8_strcasecmp(entry->nickname, format)) {
if (!silc_idcache_list_next(list, &id_cache)) {
entry = NULL;
break;
goto identify;
}
+ silc_free(nicknamec);
+
if (list)
silc_idcache_list_free(list);
SilcBuffer client_id_list = i->client_id_list;
SilcClientEntry *clients = NULL;
SilcUInt32 clients_count = 0;
- bool found = FALSE;
+ SilcBool found = FALSE;
int c;
SILC_LOG_DEBUG(("Start"));
unsigned char **res_argv = NULL;
SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
GetClientsByListInternal in;
- bool wait_res = FALSE;
+ SilcBool wait_res = FALSE;
assert(client && conn && client_id_list);
SilcUInt16 idp_len;
SilcClientID *client_id;
SilcClientEntry entry;
- bool ret;
+ SilcBool ret;
/* Get Client ID */
SILC_GET16_MSB(idp_len, client_id_list->data + 2);
GetClientsByChannelInternal i = context;
SilcClientEntry *clients = NULL;
SilcUInt32 clients_count = 0;
- bool found = FALSE;
+ SilcBool found = FALSE;
SilcChannelEntry channel;
SilcHashTableList htl;
SilcChannelUser chu;
+ if (i->res_count) {
+ i->res_count--;
+ if (i->res_count)
+ return;
+ }
+
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))
+ while (silc_hash_table_get(&htl, NULL, (void *)&chu))
clients[clients_count++] = chu->client;
silc_hash_table_list_reset(&htl);
found = TRUE;
unsigned char **res_argv = NULL;
SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
SilcBuffer idp;
- bool wait_res = FALSE;
+ SilcBool wait_res = FALSE;
assert(client && conn && channel);
}
silc_hash_table_list(channel->user_list, &htl);
- while (silc_hash_table_get(&htl, NULL, (void **)&chu)) {
+ while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
entry = chu->client;
/* If the entry has incomplete info, then resolve it from the server. */
client_entry->channels = silc_hash_table_alloc(1, silc_hash_ptr, NULL, NULL,
NULL, NULL, NULL, TRUE);
+ /* Normalize nickname */
+ if (client_entry->nickname) {
+ silc_free(nick);
+ nick = silc_identifier_check(client_entry->nickname,
+ strlen(client_entry->nickname),
+ SILC_STRING_UTF8, 128, NULL);
+ if (!nick) {
+ 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;
+ }
+ }
+
/* 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,
(void *)client_entry, 0, NULL)) {
+ silc_free(nick);
silc_free(client_entry->nickname);
silc_free(client_entry->username);
silc_free(client_entry->hostname);
if (!client_entry->nickname && nickname) {
silc_parse_userfqdn(nickname, &nick, &client_entry->server);
client_entry->nickname = strdup(nick);
+
+ /* Normalize nickname */
+ silc_free(nick);
+ nick = silc_identifier_check(client_entry->nickname,
+ strlen(client_entry->nickname),
+ SILC_STRING_UTF8, 128, NULL);
+ if (!nick)
+ return;
+
+ /* Format nickname */
silc_client_nickname_format(client, conn, client_entry);
}
client_entry->mode = mode;
silc_free(client_entry->server);
silc_free(client_entry->id);
silc_free(client_entry->fingerprint);
+ if (client_entry->public_key)
+ silc_pkcs_public_key_free(client_entry->public_key);
silc_hash_table_free(client_entry->channels);
if (client_entry->send_key)
silc_cipher_free(client_entry->send_key);
/* Removes client from the cache by the client entry. */
-bool silc_client_del_client(SilcClient client, SilcClientConnection conn,
+SilcBool silc_client_del_client(SilcClient client, SilcClientConnection conn,
SilcClientEntry client_entry)
{
- bool ret = silc_idcache_del_by_context(conn->internal->client_cache,
+ SilcBool ret = silc_idcache_del_by_context(conn->internal->client_cache,
client_entry);
if (ret) {
SilcChannelID *channel_id)
{
SilcChannelEntry channel;
+ char *channel_namec;
SILC_LOG_DEBUG(("Start"));
channel->user_list = silc_hash_table_alloc(1, silc_hash_ptr, NULL, NULL,
NULL, NULL, NULL, TRUE);
+ /* Normalize channel name */
+ channel_namec = silc_channel_name_check(channel_name, strlen(channel_name),
+ SILC_STRING_UTF8, 256, NULL);
+ if (!channel_namec) {
+ silc_free(channel->channel_name);
+ silc_hash_table_free(channel->user_list);
+ silc_free(channel);
+ return NULL;
+ }
+
/* 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_namec,
(void *)channel->id, (void *)channel, 0, NULL)) {
+ silc_free(channel_namec);
silc_free(channel->channel_name);
silc_hash_table_free(channel->user_list);
silc_free(channel);
/* Removes channel from the cache by the channel entry. */
-bool silc_client_del_channel(SilcClient client, SilcClientConnection conn,
+SilcBool silc_client_del_channel(SilcClient client, SilcClientConnection conn,
SilcChannelEntry channel)
{
- bool ret = silc_idcache_del_by_context(conn->internal->channel_cache,
+ SilcBool ret = silc_idcache_del_by_context(conn->internal->channel_cache,
channel);
SILC_LOG_DEBUG(("Start"));
silc_hash_table_free(channel->user_list);
silc_free(channel->channel_name);
+ silc_free(channel->topic);
silc_free(channel->id);
+ if (channel->founder_key)
+ silc_pkcs_public_key_free(channel->founder_key);
silc_free(channel->key);
if (channel->channel_key)
silc_cipher_free(channel->channel_key);
silc_hmac_free(hmac);
silc_dlist_uninit(channel->old_hmacs);
}
+ silc_schedule_task_del_by_context(conn->client->schedule, channel);
silc_client_del_channel_private_keys(client, conn, channel);
silc_free(channel);
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,
+SilcBool silc_client_replace_channel_id(SilcClient client,
SilcClientConnection conn,
SilcChannelEntry channel,
SilcChannelID *new_id)
{
+ char *channel_namec;
+
if (!new_id)
return FALSE;
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,
+
+ /* Normalize channel name */
+ channel_namec = silc_channel_name_check(channel->channel_name,
+ strlen(channel->channel_name),
+ SILC_STRING_UTF8, 256, NULL);
+ if (!channel_namec)
+ return FALSE;
+
+ return silc_idcache_add(conn->internal->channel_cache, channel_namec,
(void *)channel->id, (void *)channel, 0, NULL);
}
SILC_LOG_DEBUG(("Start"));
+ /* Normalize name for search */
+ channel = silc_channel_name_check(channel, strlen(channel), SILC_STRING_UTF8,
+ 256, NULL);
+ if (!channel)
+ return NULL;
+
if (!silc_idcache_find_by_name_one(conn->internal->channel_cache, channel,
- &id_cache))
+ &id_cache)) {
+ silc_free(channel);
return NULL;
+ }
entry = (SilcChannelEntry)id_cache->context;
SILC_LOG_DEBUG(("Found"));
+ silc_free(channel);
+
return entry;
}
SILC_LOG_DEBUG(("Start"));
+ /* Normalize server name for search */
+ server_name = silc_identifier_check(server_name, strlen(server_name),
+ SILC_STRING_UTF8, 256, NULL);
+ if (!server_name)
+ return NULL;
+
if (!silc_idcache_find_by_name_one(conn->internal->server_cache,
- server_name, &id_cache))
+ server_name, &id_cache)) {
+ silc_free(server_name);
return NULL;
+ }
entry = (SilcServerEntry)id_cache->context;
+ silc_free(server_name);
+
return entry;
}
SilcServerID *server_id)
{
SilcServerEntry server_entry;
+ char *server_namec = NULL;
SILC_LOG_DEBUG(("Start"));
if (server_info)
server_entry->server_info = strdup(server_info);
+ /* Normalize server name */
+ if (server_name) {
+ server_namec = silc_identifier_check(server_name, strlen(server_name),
+ SILC_STRING_UTF8, 256, NULL);
+ if (!server_namec) {
+ silc_free(server_entry->server_id);
+ silc_free(server_entry->server_name);
+ silc_free(server_entry->server_info);
+ silc_free(server_entry);
+ return NULL;
+ }
+ }
+
/* Add server to cache */
- if (!silc_idcache_add(conn->internal->server_cache,
- server_entry->server_name,
+ if (!silc_idcache_add(conn->internal->server_cache, server_namec,
server_entry->server_id, server_entry, 0, NULL)) {
+ silc_free(server_namec);
silc_free(server_entry->server_id);
silc_free(server_entry->server_name);
silc_free(server_entry->server_info);
/* Removes server from the cache by the server entry. */
-bool silc_client_del_server(SilcClient client, SilcClientConnection conn,
+SilcBool silc_client_del_server(SilcClient client, SilcClientConnection conn,
SilcServerEntry server)
{
- bool ret = silc_idcache_del_by_context(conn->internal->server_cache, server);
+ SilcBool 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);
const char *server_name,
const char *server_info)
{
+ char *server_namec = NULL;
+
SILC_LOG_DEBUG(("Start"));
- if (server_name && (!server_entry->server_name ||
- strcmp(server_entry->server_name, server_name))) {
+ if (server_name &&
+ (!server_entry->server_name ||
+ !silc_utf8_strcasecmp(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);
+
+ /* Normalize server name */
+ if (server_name) {
+ server_namec = silc_identifier_check(server_name, strlen(server_name),
+ SILC_STRING_UTF8, 256, NULL);
+ if (!server_namec)
+ return;
+
+ silc_idcache_add(conn->internal->server_cache, server_namec,
+ server_entry->server_id,
+ server_entry, 0, NULL);
+ }
}
- if (server_info && (!server_entry->server_info ||
- strcmp(server_entry->server_info, server_info))) {
+ if (server_info &&
+ (!server_entry->server_info ||
+ !silc_utf8_strcasecmp(server_entry->server_info, server_info))) {
silc_free(server_entry->server_info);
server_entry->server_info = strdup(server_info);
}
char *cp;
char *newnick = NULL;
int i, off = 0, len;
- bool freebase;
+ SilcBool freebase;
SilcClientEntry *clients;
SilcUInt32 clients_count = 0;
SilcClientEntry unformatted = NULL;
if (clients[i]->valid && clients[i] != client_entry)
len++;
if (clients[i]->valid && clients[i] != client_entry &&
- !strcmp(clients[i]->nickname, client_entry->nickname))
+ silc_utf8_strcasecmp(clients[i]->nickname, client_entry->nickname))
freebase = FALSE;
}
if (!len || freebase)
unformatted = clients[0];
else
for (i = 0; i < clients_count; i++)
- if (!strncasecmp(clients[i]->nickname, client_entry->nickname,
- strlen(clients[i]->nickname)))
+ if (silc_utf8_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
break;
for (i = 0; i < clients_count; i++) {
- if (strncasecmp(clients[i]->nickname, newnick, off))
+ if (!silc_utf8_strncasecmp(clients[i]->nickname, newnick, off))
continue;
if (strlen(clients[i]->nickname) <= off)
continue;