5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2001 - 2002 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
21 #include "silcincludes.h"
22 #include "silcclient.h"
23 #include "client_internal.h"
25 /******************************************************************************
27 Client Searching Locally
29 ******************************************************************************/
31 /* Same as silc_client_get_clients function but does not resolve anything
32 from the server. This checks local cache and returns all matching
33 clients from the local cache. If none was found this returns NULL.
34 The `nickname' is the real nickname of the client, and the `format'
35 is the formatted nickname to find exact match from multiple found
36 entries. The format must be same as given in the SilcClientParams
37 structure to the client library. If the `format' is NULL all found
38 clients by `nickname' are returned. */
40 SilcClientEntry *silc_client_get_clients_local(SilcClient client,
41 SilcClientConnection conn,
44 SilcUInt32 *clients_count)
46 SilcIDCacheEntry id_cache;
47 SilcIDCacheList list = NULL;
48 SilcClientEntry entry, *clients;
52 /* Find ID from cache */
53 if (!silc_idcache_find_by_name(conn->client_cache, (char *)nickname, &list))
56 if (!silc_idcache_list_count(list)) {
57 silc_idcache_list_free(list);
61 clients = silc_calloc(silc_idcache_list_count(list), sizeof(*clients));
62 *clients_count = silc_idcache_list_count(list);
65 /* Take all without any further checking */
66 silc_idcache_list_first(list, &id_cache);
68 clients[i++] = id_cache->context;
70 if (!silc_idcache_list_next(list, &id_cache))
74 /* Check multiple cache entries for match */
75 silc_idcache_list_first(list, &id_cache);
77 entry = (SilcClientEntry)id_cache->context;
78 if (strcasecmp(entry->nickname, format)) {
79 if (!silc_idcache_list_next(list, &id_cache)) {
86 clients[i++] = id_cache->context;
88 if (!silc_idcache_list_next(list, &id_cache))
94 silc_idcache_list_free(list);
107 /******************************************************************************
109 Client Resolving from Server
111 ******************************************************************************/
115 SilcClientConnection conn;
116 SilcGetClientCallback completion;
120 } *GetClientInternal;
122 SILC_CLIENT_CMD_FUNC(get_client_callback)
124 GetClientInternal i = (GetClientInternal)context;
125 SilcClientEntry *clients;
126 SilcUInt32 clients_count;
128 /* Get the clients */
129 clients = silc_client_get_clients_local(i->client, i->conn,
130 i->nickname, i->server,
133 i->completion(i->client, i->conn, clients, clients_count, i->context);
136 i->completion(i->client, i->conn, NULL, 0, i->context);
139 silc_free(i->nickname);
140 silc_free(i->server);
144 /* Finds client entry or entries by the `nickname' and `server'. The
145 completion callback will be called when the client entries has been found.
147 Note: this function is always asynchronous and resolves the client
148 information from the server. Thus, if you already know the client
149 information then use the silc_client_get_client_by_id function to
150 get the client entry since this function may be very slow and should
151 be used only to initially get the client entries. */
153 void silc_client_get_clients(SilcClient client,
154 SilcClientConnection conn,
155 const char *nickname,
157 SilcGetClientCallback completion,
166 i = silc_calloc(1, sizeof(*i));
169 i->nickname = strdup(nickname);
170 i->server = server ? strdup(server) : NULL;
171 i->completion = completion;
172 i->context = context;
174 if (nickname && server) {
175 userhost = silc_calloc(strlen(nickname) + strlen(server) + 2,
177 strncat(userhost, nickname, strlen(nickname));
178 strncat(userhost, "@", 1);
179 strncat(userhost, server, strlen(server));
181 userhost = strdup(nickname);
184 /* Register our own command reply for this command */
185 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
186 silc_client_command_reply_identify_i, 0,
189 /* Send the command */
190 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
191 conn->cmd_ident, 1, 1, userhost,
194 /* Add pending callback */
195 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
196 silc_client_command_get_client_callback,
202 /* The old style function to find client entry. This is used by the
203 library internally. If `query' is TRUE then the client information is
204 requested by the server. The pending command callback must be set
206 /* XXX This function should be removed */
208 SilcClientEntry silc_idlist_get_client(SilcClient client,
209 SilcClientConnection conn,
210 const char *nickname,
214 SilcIDCacheEntry id_cache;
215 SilcIDCacheList list = NULL;
216 SilcClientEntry entry = NULL;
218 SILC_LOG_DEBUG(("Start"));
220 /* Find ID from cache */
221 if (!silc_idcache_find_by_name(conn->client_cache, (char *)nickname,
226 SILC_LOG_DEBUG(("Requesting Client ID from server"));
228 /* Register our own command reply for this command */
229 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
230 silc_client_command_reply_identify_i, 0,
233 /* Send the command */
234 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
235 conn->cmd_ident, 1, 1, nickname,
239 silc_idcache_list_free(list);
247 /* Take first found cache entry */
248 if (!silc_idcache_list_first(list, &id_cache))
251 entry = (SilcClientEntry)id_cache->context;
253 /* Check multiple cache entries for match */
254 silc_idcache_list_first(list, &id_cache);
256 entry = (SilcClientEntry)id_cache->context;
258 if (strcasecmp(entry->nickname, format)) {
259 if (!silc_idcache_list_next(list, &id_cache)) {
271 /* If match weren't found, request it */
277 silc_idcache_list_free(list);
285 SilcClientConnection conn;
286 SilcUInt32 list_count;
287 SilcBuffer client_id_list;
288 SilcGetClientCallback completion;
290 } *GetClientsByListInternal;
292 SILC_CLIENT_CMD_FUNC(get_clients_list_callback)
294 GetClientsByListInternal i = (GetClientsByListInternal)context;
295 SilcIDCacheEntry id_cache = NULL;
296 SilcBuffer client_id_list = i->client_id_list;
297 SilcClientEntry *clients = NULL;
298 SilcUInt32 clients_count = 0;
302 SILC_LOG_DEBUG(("Start"));
304 for (c = 0; c < i->list_count; c++) {
306 SilcClientID *client_id;
309 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
311 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
313 silc_buffer_pull(client_id_list, idp_len);
317 /* Get the client entry */
318 if (silc_idcache_find_by_id_one_ext(i->conn->client_cache,
321 silc_hash_client_id_compare, NULL,
323 clients = silc_realloc(clients, sizeof(*clients) *
324 (clients_count + 1));
325 clients[clients_count] = (SilcClientEntry)id_cache->context;
330 silc_free(client_id);
331 silc_buffer_pull(client_id_list, idp_len);
335 i->completion(i->client, i->conn, clients, clients_count, i->context);
338 i->completion(i->client, i->conn, NULL, 0, i->context);
341 if (i->client_id_list)
342 silc_buffer_free(i->client_id_list);
346 /* Gets client entries by the list of client ID's `client_id_list'. This
347 always resolves those client ID's it does not know yet from the server
348 so this function might take a while. The `client_id_list' is a list
349 of ID Payloads added one after other. JOIN command reply and USERS
350 command reply for example returns this sort of list. The `completion'
351 will be called after the entries are available. */
353 void silc_client_get_clients_by_list(SilcClient client,
354 SilcClientConnection conn,
355 SilcUInt32 list_count,
356 SilcBuffer client_id_list,
357 SilcGetClientCallback completion,
360 SilcIDCacheEntry id_cache = NULL;
362 unsigned char **res_argv = NULL;
363 SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
364 GetClientsByListInternal in;
366 SILC_LOG_DEBUG(("Start"));
368 in = silc_calloc(1, sizeof(*in));
371 in->list_count = list_count;
372 in->client_id_list = silc_buffer_copy(client_id_list);
373 in->completion = completion;
374 in->context = context;
376 for (i = 0; i < list_count; i++) {
378 SilcClientID *client_id;
379 SilcClientEntry entry;
383 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
385 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
387 silc_buffer_pull(client_id_list, idp_len);
391 /* Check if we have this client cached already. */
393 silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
395 silc_hash_client_id_compare, NULL,
398 /* If we don't have the entry or it has incomplete info, then resolve
399 it from the server. */
400 if (!ret || !((SilcClientEntry)id_cache->context)->nickname) {
401 entry = ret ? (SilcClientEntry)id_cache->context : NULL;
404 if (entry->status & SILC_CLIENT_STATUS_RESOLVING) {
405 entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
406 silc_free(client_id);
407 silc_buffer_pull(client_id_list, idp_len);
411 entry->status |= SILC_CLIENT_STATUS_RESOLVING;
414 /* No we don't have it, query it from the server. Assemble argument
415 table that will be sent fr the IDENTIFY command later. */
416 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
418 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
420 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
422 res_argv[res_argc] = client_id_list->data;
423 res_argv_lens[res_argc] = idp_len;
424 res_argv_types[res_argc] = res_argc + 5;
428 silc_free(client_id);
429 silc_buffer_pull(client_id_list, idp_len);
432 /* Query the client information from server if the list included clients
433 that we don't know about. */
437 /* Send the IDENTIFY command to server */
438 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
439 res_argc, res_argv, res_argv_lens,
440 res_argv_types, ++conn->cmd_ident);
441 silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
442 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
445 /* Register our own command reply for this command */
446 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
447 silc_client_command_reply_identify_i, 0,
450 /* Process the applications request after reply has been received */
451 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
452 silc_client_command_get_clients_list_callback,
455 silc_buffer_push(client_id_list, client_id_list->data -
456 client_id_list->head);
457 silc_buffer_free(res_cmd);
459 silc_free(res_argv_lens);
460 silc_free(res_argv_types);
464 silc_buffer_push(client_id_list, client_id_list->data -
465 client_id_list->head);
467 /* We have the clients in cache, get them and call the completion */
468 silc_client_command_get_clients_list_callback((void *)in, NULL);
471 /* Finds entry for client by the client's ID. Returns the entry or NULL
472 if the entry was not found. */
474 SilcClientEntry silc_client_get_client_by_id(SilcClient client,
475 SilcClientConnection conn,
476 SilcClientID *client_id)
478 SilcIDCacheEntry id_cache;
480 SILC_LOG_DEBUG(("Finding client by ID (%s)",
481 silc_id_render(client_id, SILC_ID_CLIENT)));
483 /* Find ID from cache */
484 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
486 silc_hash_client_id_compare, NULL,
490 SILC_LOG_DEBUG(("Found"));
492 return (SilcClientEntry)id_cache->context;
497 SilcClientConnection conn;
498 SilcClientID *client_id;
499 SilcGetClientCallback completion;
501 } *GetClientByIDInternal;
503 SILC_CLIENT_CMD_FUNC(get_client_by_id_callback)
505 GetClientByIDInternal i = (GetClientByIDInternal)context;
506 SilcClientEntry entry;
509 entry = silc_client_get_client_by_id(i->client, i->conn, i->client_id);
512 i->completion(i->client, i->conn, &entry, 1, i->context);
515 i->completion(i->client, i->conn, NULL, 0, i->context);
518 silc_free(i->client_id);
522 /* Same as above but will always resolve the information from the server.
523 Use this only if you know that you don't have the entry and the only
524 thing you know about the client is its ID. */
526 void silc_client_get_client_by_id_resolve(SilcClient client,
527 SilcClientConnection conn,
528 SilcClientID *client_id,
529 SilcGetClientCallback completion,
533 GetClientByIDInternal i = silc_calloc(1, sizeof(*i));
535 SILC_LOG_DEBUG(("Start"));
539 i->client_id = silc_id_dup(client_id, SILC_ID_CLIENT);
540 i->completion = completion;
541 i->context = context;
543 /* Register our own command reply for this command */
544 silc_client_command_register(client, SILC_COMMAND_WHOIS, NULL, NULL,
545 silc_client_command_reply_whois_i, 0,
548 /* Send the command */
549 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
550 silc_client_command_send(client, conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
551 1, 3, idp->data, idp->len);
552 silc_buffer_free(idp);
554 /* Add pending callback */
555 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
556 silc_client_command_get_client_by_id_callback,
561 /******************************************************************************
563 Client, Channel and Server entry manipulation
565 ******************************************************************************/
568 /* Creates new client entry and adds it to the ID cache. Returns pointer
572 silc_client_add_client(SilcClient client, SilcClientConnection conn,
573 char *nickname, char *username,
574 char *userinfo, SilcClientID *id, SilcUInt32 mode)
576 SilcClientEntry client_entry;
579 SILC_LOG_DEBUG(("Start"));
581 /* Save the client infos */
582 client_entry = silc_calloc(1, sizeof(*client_entry));
583 client_entry->id = id;
584 client_entry->valid = TRUE;
585 silc_parse_userfqdn(nickname, &nick, &client_entry->server);
586 silc_parse_userfqdn(username, &client_entry->username,
587 &client_entry->hostname);
589 client_entry->realname = strdup(userinfo);
590 client_entry->mode = mode;
592 client_entry->nickname = strdup(nick);
593 client_entry->channels = silc_hash_table_alloc(1, silc_hash_ptr, NULL, NULL,
594 NULL, NULL, NULL, TRUE);
596 /* Format the nickname */
597 silc_client_nickname_format(client, conn, client_entry);
599 /* Add client to cache, the non-formatted nickname is saved to cache */
600 if (!silc_idcache_add(conn->client_cache, nick, client_entry->id,
601 (void *)client_entry, 0, NULL)) {
602 silc_free(client_entry->nickname);
603 silc_free(client_entry->username);
604 silc_free(client_entry->hostname);
605 silc_free(client_entry->server);
606 silc_hash_table_free(client_entry->channels);
607 silc_free(client_entry);
614 /* Updates the `client_entry' with the new information sent as argument. */
616 void silc_client_update_client(SilcClient client,
617 SilcClientConnection conn,
618 SilcClientEntry client_entry,
619 const char *nickname,
620 const char *username,
621 const char *userinfo,
626 SILC_LOG_DEBUG(("Start"));
628 if (!client_entry->username && username)
629 silc_parse_userfqdn(username, &client_entry->username,
630 &client_entry->hostname);
631 if (!client_entry->realname && userinfo)
632 client_entry->realname = strdup(userinfo);
633 if (!client_entry->nickname && nickname) {
634 silc_parse_userfqdn(nickname, &nick, &client_entry->server);
635 client_entry->nickname = strdup(nick);
636 silc_client_nickname_format(client, conn, client_entry);
638 client_entry->mode = mode;
641 /* Remove the old cache entry and create a new one */
642 silc_idcache_del_by_context(conn->client_cache, client_entry);
643 silc_idcache_add(conn->client_cache, nick, client_entry->id,
644 client_entry, 0, NULL);
648 /* Deletes the client entry and frees all memory. */
650 void silc_client_del_client_entry(SilcClient client,
651 SilcClientConnection conn,
652 SilcClientEntry client_entry)
654 SILC_LOG_DEBUG(("Start"));
656 silc_free(client_entry->nickname);
657 silc_free(client_entry->username);
658 silc_free(client_entry->realname);
659 silc_free(client_entry->hostname);
660 silc_free(client_entry->server);
661 silc_free(client_entry->id);
662 silc_free(client_entry->fingerprint);
663 silc_hash_table_free(client_entry->channels);
664 if (client_entry->send_key)
665 silc_cipher_free(client_entry->send_key);
666 if (client_entry->receive_key)
667 silc_cipher_free(client_entry->receive_key);
668 silc_free(client_entry->key);
669 silc_client_ftp_session_free_client(conn, client_entry);
670 if (client_entry->ke)
671 silc_client_abort_key_agreement(client, conn, client_entry);
672 silc_free(client_entry);
675 /* Removes client from the cache by the client entry. */
677 bool silc_client_del_client(SilcClient client, SilcClientConnection conn,
678 SilcClientEntry client_entry)
680 bool ret = silc_idcache_del_by_context(conn->client_cache, client_entry);
682 /* Remove from channels */
683 silc_client_remove_from_channels(client, conn, client_entry);
685 /* Free the client entry data */
686 silc_client_del_client_entry(client, conn, client_entry);
691 /* Add new channel entry to the ID Cache */
693 SilcChannelEntry silc_client_add_channel(SilcClient client,
694 SilcClientConnection conn,
695 const char *channel_name,
697 SilcChannelID *channel_id)
699 SilcChannelEntry channel;
701 SILC_LOG_DEBUG(("Start"));
703 channel = silc_calloc(1, sizeof(*channel));
704 channel->channel_name = strdup(channel_name);
705 channel->id = channel_id;
706 channel->mode = mode;
707 channel->user_list = silc_hash_table_alloc(1, silc_hash_ptr, NULL, NULL,
708 NULL, NULL, NULL, TRUE);
710 /* Put it to the ID cache */
711 if (!silc_idcache_add(conn->channel_cache, channel->channel_name,
712 (void *)channel->id, (void *)channel, 0, NULL)) {
713 silc_free(channel->channel_name);
714 silc_hash_table_free(channel->user_list);
722 /* Foreach callbcak to free all users from the channel when deleting a
725 static void silc_client_del_channel_foreach(void *key, void *context,
728 SilcChannelUser chu = (SilcChannelUser)context;
730 SILC_LOG_DEBUG(("Start"));
732 /* Remove the context from the client's channel hash table as that
733 table and channel's user_list hash table share this same context. */
734 silc_hash_table_del(chu->client->channels, chu->channel);
738 /* Removes channel from the cache by the channel entry. */
740 bool silc_client_del_channel(SilcClient client, SilcClientConnection conn,
741 SilcChannelEntry channel)
743 bool ret = silc_idcache_del_by_context(conn->channel_cache, channel);
745 SILC_LOG_DEBUG(("Start"));
747 /* Free all client entrys from the users list. The silc_hash_table_free
748 will free all the entries so they are not freed at the foreach
750 silc_hash_table_foreach(channel->user_list, silc_client_del_channel_foreach,
752 silc_hash_table_free(channel->user_list);
754 silc_free(channel->channel_name);
755 silc_free(channel->id);
756 silc_free(channel->key);
757 if (channel->channel_key)
758 silc_cipher_free(channel->channel_key);
760 silc_hmac_free(channel->hmac);
761 if (channel->old_channel_key)
762 silc_cipher_free(channel->old_channel_key);
763 if (channel->old_hmac)
764 silc_hmac_free(channel->old_hmac);
765 if (channel->rekey_task)
766 silc_schedule_task_del(conn->client->schedule, channel->rekey_task);
767 silc_client_del_channel_private_keys(client, conn, channel);
772 /* Replaces the channel ID of the `channel' to `new_id'. Returns FALSE
773 if the ID could not be changed. */
775 bool silc_client_replace_channel_id(SilcClient client,
776 SilcClientConnection conn,
777 SilcChannelEntry channel,
778 SilcChannelID *new_id)
783 SILC_LOG_DEBUG(("Old Channel ID id(%s)",
784 silc_id_render(channel->id, SILC_ID_CHANNEL)));
785 SILC_LOG_DEBUG(("New Channel ID id(%s)",
786 silc_id_render(new_id, SILC_ID_CHANNEL)));
788 silc_idcache_del_by_id(conn->channel_cache, channel->id);
789 silc_free(channel->id);
790 channel->id = new_id;
791 return silc_idcache_add(conn->channel_cache, channel->channel_name,
792 (void *)channel->id, (void *)channel, 0, NULL);
796 /* Finds entry for channel by the channel name. Returns the entry or NULL
797 if the entry was not found. It is found only if the client is joined
800 SilcChannelEntry silc_client_get_channel(SilcClient client,
801 SilcClientConnection conn,
804 SilcIDCacheEntry id_cache;
805 SilcChannelEntry entry;
807 SILC_LOG_DEBUG(("Start"));
809 if (!silc_idcache_find_by_name_one(conn->channel_cache, channel,
813 entry = (SilcChannelEntry)id_cache->context;
815 SILC_LOG_DEBUG(("Found"));
820 /* Finds entry for channel by the channel ID. Returns the entry or NULL
821 if the entry was not found. It is found only if the client is joined
824 SilcChannelEntry silc_client_get_channel_by_id(SilcClient client,
825 SilcClientConnection conn,
826 SilcChannelID *channel_id)
828 SilcIDCacheEntry id_cache;
829 SilcChannelEntry entry;
831 SILC_LOG_DEBUG(("Start"));
833 if (!silc_idcache_find_by_id_one(conn->channel_cache, channel_id,
837 entry = (SilcChannelEntry)id_cache->context;
839 SILC_LOG_DEBUG(("Found"));
846 SilcClientConnection conn;
847 SilcChannelID *channel_id;
848 SilcGetChannelCallback completion;
850 } *GetChannelByIDInternal;
852 SILC_CLIENT_CMD_FUNC(get_channel_by_id_callback)
854 GetChannelByIDInternal i = (GetChannelByIDInternal)context;
855 SilcChannelEntry entry;
857 SILC_LOG_DEBUG(("Start"));
859 /* Get the channel */
860 entry = silc_client_get_channel_by_id(i->client, i->conn, i->channel_id);
862 i->completion(i->client, i->conn, &entry, 1, i->context);
864 i->completion(i->client, i->conn, NULL, 0, i->context);
867 silc_free(i->channel_id);
871 /* Resolves channel information from the server by the channel ID. */
873 void silc_client_get_channel_by_id_resolve(SilcClient client,
874 SilcClientConnection conn,
875 SilcChannelID *channel_id,
876 SilcGetChannelCallback completion,
880 GetChannelByIDInternal i = silc_calloc(1, sizeof(*i));
882 SILC_LOG_DEBUG(("Start"));
886 i->channel_id = silc_id_dup(channel_id, SILC_ID_CHANNEL);
887 i->completion = completion;
888 i->context = context;
890 /* Register our own command reply for this command */
891 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
892 silc_client_command_reply_identify_i, 0,
895 /* Send the command */
896 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
897 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
899 1, 5, idp->data, idp->len);
900 silc_buffer_free(idp);
902 /* Add pending callback */
903 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
904 silc_client_command_get_channel_by_id_callback,
908 /* Finds entry for server by the server name. */
910 SilcServerEntry silc_client_get_server(SilcClient client,
911 SilcClientConnection conn,
914 SilcIDCacheEntry id_cache;
915 SilcServerEntry entry;
917 SILC_LOG_DEBUG(("Start"));
919 if (!silc_idcache_find_by_name_one(conn->server_cache, server_name,
923 entry = (SilcServerEntry)id_cache->context;
928 /* Finds entry for server by the server ID. */
930 SilcServerEntry silc_client_get_server_by_id(SilcClient client,
931 SilcClientConnection conn,
932 SilcServerID *server_id)
934 SilcIDCacheEntry id_cache;
935 SilcServerEntry entry;
937 SILC_LOG_DEBUG(("Start"));
939 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
943 entry = (SilcServerEntry)id_cache->context;
948 /* Add new server entry */
950 SilcServerEntry silc_client_add_server(SilcClient client,
951 SilcClientConnection conn,
952 const char *server_name,
953 const char *server_info,
954 SilcServerID *server_id)
956 SilcServerEntry server_entry;
958 server_entry = silc_calloc(1, sizeof(*server_entry));
959 if (!server_entry || !server_id)
962 server_entry->server_id = server_id;
964 server_entry->server_name = strdup(server_name);
966 server_entry->server_info = strdup(server_info);
968 /* Add server to cache */
969 if (!silc_idcache_add(conn->server_cache, server_entry->server_name,
970 server_entry->server_id, server_entry, 0, NULL)) {
971 silc_free(server_entry->server_id);
972 silc_free(server_entry->server_name);
973 silc_free(server_entry->server_info);
974 silc_free(server_entry);
981 /* Removes server from the cache by the server entry. */
983 bool silc_client_del_server(SilcClient client, SilcClientConnection conn,
984 SilcServerEntry server)
986 bool ret = silc_idcache_del_by_context(conn->server_cache, server);
987 silc_free(server->server_name);
988 silc_free(server->server_info);
989 silc_free(server->server_id);
994 /* Formats the nickname of the client specified by the `client_entry'.
995 If the format is specified by the application this will format the
996 nickname and replace the old nickname in the client entry. If the
997 format string is not specified then this function has no effect. */
999 void silc_client_nickname_format(SilcClient client,
1000 SilcClientConnection conn,
1001 SilcClientEntry client_entry)
1004 char *newnick = NULL;
1005 int i, off = 0, len;
1007 SilcClientEntry *clients;
1008 SilcUInt32 clients_count = 0;
1009 SilcClientEntry unformatted = NULL;
1011 SILC_LOG_DEBUG(("Start"));
1013 if (!client->internal->params->nickname_format[0])
1016 if (!client_entry->nickname)
1019 /* Get all clients with same nickname. Do not perform the formatting
1020 if there aren't any clients with same nickname unless the application
1021 is forcing us to do so. */
1022 clients = silc_client_get_clients_local(client, conn,
1023 client_entry->nickname, NULL,
1025 if (!clients && !client->internal->params->nickname_force_format)
1030 for (i = 0; i < clients_count; i++) {
1031 if (clients[i]->valid && clients[i] != client_entry)
1033 if (clients[i]->valid && clients[i] != client_entry &&
1034 !strcmp(clients[i]->nickname, client_entry->nickname))
1037 if (!len || freebase)
1040 cp = client->internal->params->nickname_format;
1050 if (!client_entry->nickname)
1052 len = strlen(client_entry->nickname);
1053 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1054 memcpy(&newnick[off], client_entry->nickname, len);
1058 /* Stripped hostname */
1059 if (!client_entry->hostname)
1061 len = strcspn(client_entry->hostname, ".");
1062 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1063 memcpy(&newnick[off], client_entry->hostname, len);
1068 if (!client_entry->hostname)
1070 len = strlen(client_entry->hostname);
1071 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1072 memcpy(&newnick[off], client_entry->hostname, len);
1076 /* Stripped server name */
1077 if (!client_entry->server)
1079 len = strcspn(client_entry->server, ".");
1080 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1081 memcpy(&newnick[off], client_entry->server, len);
1085 /* Full server name */
1086 if (!client_entry->server)
1088 len = strlen(client_entry->server);
1089 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1090 memcpy(&newnick[off], client_entry->server, len);
1094 /* Ascending number */
1099 if (clients_count == 1) {
1100 unformatted = clients[0];
1104 for (i = 0; i < clients_count; i++) {
1105 if (!strncasecmp(clients[i]->nickname, client_entry->nickname,
1106 strlen(clients[i]->nickname)))
1107 unformatted = clients[i];
1108 if (strncasecmp(clients[i]->nickname, newnick, off))
1110 if (strlen(clients[i]->nickname) <= off)
1112 num = atoi(&clients[i]->nickname[off]);
1117 memset(tmp, 0, sizeof(tmp));
1118 snprintf(tmp, sizeof(tmp) - 1, "%d", ++max);
1120 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1121 memcpy(&newnick[off], tmp, len);
1126 /* Some other character in the string */
1127 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
1128 memcpy(&newnick[off], cp, 1);
1136 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
1139 /* If we are changing nickname of our local entry we'll enforce
1140 that we will always get the unformatted nickname. Give our
1141 format number to the one that is not formatted now. */
1142 if (unformatted && client_entry == conn->local_entry)
1143 client_entry = unformatted;
1145 silc_free(client_entry->nickname);
1146 client_entry->nickname = newnick;