/*
- idlist.c
+ idlist.c
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2001 Pekka Riikonen
+ Copyright (C) 2001 - 2002 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
- 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
void *context;
char *nickname;
char *server;
- bool found;
} *GetClientInternal;
SILC_CLIENT_CMD_FUNC(get_client_callback)
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);
/* 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);
SilcBuffer client_id_list;
SilcGetClientCallback completion;
void *context;
- int found;
} *GetClientsByListInternal;
SILC_CLIENT_CMD_FUNC(get_clients_list_callback)
SilcBuffer client_id_list = i->client_id_list;
SilcClientEntry *clients = NULL;
uint32 clients_count = 0;
+ bool found = FALSE;
int c;
SILC_LOG_DEBUG(("Start"));
(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);
/* 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);
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);
- if (entry) {
+ 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;
- }
-}
-
-static void silc_client_get_client_by_id_destructor(void *context)
-{
- GetClientByIDInternal i = (GetClientByIDInternal)context;
-
- if (i->found == FALSE)
+ else
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);
}
/* 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);
}
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;
}
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)
SilcClientEntry client_entry)
{
bool ret = silc_idcache_del_by_context(conn->client_cache, client_entry);
+
+ /* 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);
+
return ret;
}
+/* Add new channel entry to the ID Cache */
+
+SilcChannelEntry silc_client_add_channel(SilcClient client,
+ SilcClientConnection conn,
+ const char *channel_name,
+ uint32 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;
+
+ /* 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);
+
+ /* 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. */
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);
/* 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,
int i, off = 0, len;
SilcClientEntry *clients;
uint32 clients_count = 0;
+ SilcClientEntry unformatted = NULL;
SILC_LOG_DEBUG(("Start"));
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);