+
+/* Finds entry for channel by the channel ID. Returns the entry or NULL
+ if the entry was not found. It is found only if the client is joined
+ to the channel. */
+
+SilcChannelEntry silc_client_get_channel_by_id(SilcClient client,
+ SilcClientConnection conn,
+ SilcChannelID *channel_id)
+{
+ 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,
+ &id_cache))
+ return NULL;
+
+ entry = (SilcChannelEntry)id_cache->context;
+
+ SILC_LOG_DEBUG(("Found"));
+
+ return entry;
+}
+
+typedef struct {
+ SilcClient client;
+ SilcClientConnection conn;
+ union {
+ SilcChannelID *channel_id;
+ char *channel_name;
+ } u;
+ SilcGetChannelCallback completion;
+ void *context;
+} *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)
+{
+ 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->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->u.channel_id);
+ silc_free(i);
+}
+
+/* Resolves channel information from the server by the channel ID. */
+
+void silc_client_get_channel_by_id_resolve(SilcClient client,
+ SilcClientConnection conn,
+ SilcChannelID *channel_id,
+ SilcGetChannelCallback completion,
+ void *context)
+{
+ SilcBuffer idp;
+ GetChannelInternal i = silc_calloc(1, sizeof(*i));
+
+ assert(client && conn && channel_id);
+
+ SILC_LOG_DEBUG(("Start"));
+
+ i->client = client;
+ i->conn = conn;
+ 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,
+ ++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);
+
+ /* Add pending callback */
+ silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
+ silc_client_command_get_channel_by_id_callback,
+ (void *)i);
+}
+
+/* Finds entry for server by the server name. */
+
+SilcServerEntry silc_client_get_server(SilcClient client,
+ SilcClientConnection conn,
+ char *server_name)
+{
+ SilcIDCacheEntry id_cache;
+ SilcServerEntry entry;
+
+ assert(client && conn);
+ if (!server_name)
+ return NULL;
+
+ 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)) {
+ silc_free(server_name);
+ return NULL;
+ }
+
+ entry = (SilcServerEntry)id_cache->context;
+
+ silc_free(server_name);
+
+ return entry;
+}
+
+/* Finds entry for server by the server ID. */
+
+SilcServerEntry silc_client_get_server_by_id(SilcClient client,
+ SilcClientConnection conn,
+ SilcServerID *server_id)
+{
+ 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,
+ (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;
+ char *server_namec = NULL;
+
+ 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);
+
+ /* 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_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);
+ 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->internal->server_cache, server);
+ silc_free(server->server_name);
+ silc_free(server->server_info);
+ silc_free(server->server_id);
+ silc_free(server);
+ 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)
+{
+ char *server_namec = NULL;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ 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);
+
+ /* 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 ||
+ !silc_utf8_strcasecmp(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
+ format string is not specified then this function has no effect. */
+
+void silc_client_nickname_format(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry client_entry)
+{
+ char *cp;
+ char *newnick = NULL;
+ int i, off = 0, len;
+ bool freebase;
+ SilcClientEntry *clients;
+ SilcUInt32 clients_count = 0;
+ SilcClientEntry unformatted = NULL;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (!client->internal->params->nickname_format[0])
+ return;
+
+ if (!client_entry->nickname)
+ return;
+
+ /* Get all clients with same nickname. Do not perform the formatting
+ if there aren't any clients with same nickname unless the application
+ is forcing us to do so. */
+ clients = silc_client_get_clients_local(client, conn,
+ client_entry->nickname, NULL,
+ &clients_count);
+ if (!clients && !client->internal->params->nickname_force_format)
+ return;
+
+ len = 0;
+ freebase = TRUE;
+ for (i = 0; i < clients_count; i++) {
+ if (clients[i]->valid && clients[i] != client_entry)
+ len++;
+ if (clients[i]->valid && clients[i] != client_entry &&
+ silc_utf8_strcasecmp(clients[i]->nickname, client_entry->nickname))
+ freebase = FALSE;
+ }
+ if (!len || freebase)
+ return;
+
+ if (clients_count == 1)
+ unformatted = clients[0];
+ else
+ for (i = 0; i < clients_count; i++)
+ 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
+ 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 == '%') {
+ cp++;
+ continue;
+ }
+
+ switch(*cp) {
+ case 'n':
+ /* Nickname */
+ if (!client_entry->nickname)
+ break;
+ len = strlen(client_entry->nickname);
+ newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
+ memcpy(&newnick[off], client_entry->nickname, len);
+ off += len;
+ break;
+ case 'h':
+ /* Stripped hostname */
+ 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;
+ break;
+ case 'H':
+ /* Full hostname */
+ if (!client_entry->hostname)
+ break;
+ len = strlen(client_entry->hostname);
+ newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
+ memcpy(&newnick[off], client_entry->hostname, len);
+ off += len;
+ break;
+ case 's':
+ /* Stripped server name */
+ if (!client_entry->server)
+ break;
+ len = strcspn(client_entry->server, ".");
+ newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
+ memcpy(&newnick[off], client_entry->server, len);
+ off += len;
+ break;
+ case 'S':
+ /* Full server name */
+ if (!client_entry->server)
+ break;
+ len = strlen(client_entry->server);
+ newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
+ memcpy(&newnick[off], client_entry->server, len);
+ off += len;
+ break;
+ case 'a':
+ /* Ascending number */
+ {
+ char tmp[6];
+ int num, max = 1;
+
+ if (clients_count == 1)
+ break;
+
+ for (i = 0; i < clients_count; i++) {
+ if (!silc_utf8_strncasecmp(clients[i]->nickname, newnick, off))
+ continue;
+ if (strlen(clients[i]->nickname) <= off)
+ continue;
+ num = atoi(&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 + len));
+ memcpy(&newnick[off], tmp, len);
+ off += len;
+ }
+ break;
+ default:
+ /* Some other character in the string */
+ newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
+ memcpy(&newnick[off], cp, 1);
+ off++;
+ break;
+ }
+
+ cp++;
+ }
+
+ newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
+ newnick[off] = 0;
+
+ silc_free(client_entry->nickname);
+ client_entry->nickname = newnick;
+ silc_free(clients);
+}