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 "clientlibincludes.h"
22 #include "client_internal.h"
24 /******************************************************************************
26 Client Searching Locally
28 ******************************************************************************/
30 /* Same as silc_client_get_clients function but does not resolve anything
31 from the server. This checks local cache and returns all matching
32 clients from the local cache. If none was found this returns NULL.
33 The `nickname' is the real nickname of the client, and the `format'
34 is the formatted nickname to find exact match from multiple found
35 entries. The format must be same as given in the SilcClientParams
36 structure to the client library. If the `format' is NULL all found
37 clients by `nickname' are returned. */
39 SilcClientEntry *silc_client_get_clients_local(SilcClient client,
40 SilcClientConnection conn,
43 uint32 *clients_count)
45 SilcIDCacheEntry id_cache;
46 SilcIDCacheList list = NULL;
47 SilcClientEntry entry, *clients;
51 /* Find ID from cache */
52 if (!silc_idcache_find_by_name(conn->client_cache, (char *)nickname, &list))
55 if (!silc_idcache_list_count(list)) {
56 silc_idcache_list_free(list);
60 clients = silc_calloc(silc_idcache_list_count(list), sizeof(*clients));
61 *clients_count = silc_idcache_list_count(list);
64 /* Take all without any further checking */
65 silc_idcache_list_first(list, &id_cache);
67 clients[i++] = id_cache->context;
69 if (!silc_idcache_list_next(list, &id_cache))
73 /* Check multiple cache entries for match */
74 silc_idcache_list_first(list, &id_cache);
76 entry = (SilcClientEntry)id_cache->context;
77 if (strcasecmp(entry->nickname, format)) {
78 if (!silc_idcache_list_next(list, &id_cache)) {
85 clients[i++] = id_cache->context;
87 if (!silc_idcache_list_next(list, &id_cache))
93 silc_idcache_list_free(list);
106 /******************************************************************************
108 Client Resolving from Server
110 ******************************************************************************/
114 SilcClientConnection conn;
115 SilcGetClientCallback completion;
119 } *GetClientInternal;
121 SILC_CLIENT_CMD_FUNC(get_client_callback)
123 GetClientInternal i = (GetClientInternal)context;
124 SilcClientEntry *clients;
125 uint32 clients_count;
127 /* Get the clients */
128 clients = silc_client_get_clients_local(i->client, i->conn,
129 i->nickname, i->server,
132 i->completion(i->client, i->conn, clients, clients_count, i->context);
135 i->completion(i->client, i->conn, NULL, 0, i->context);
138 silc_free(i->nickname);
139 silc_free(i->server);
143 /* Finds client entry or entries by the `nickname' and `server'. The
144 completion callback will be called when the client entries has been found.
146 Note: this function is always asynchronous and resolves the client
147 information from the server. Thus, if you already know the client
148 information then use the silc_client_get_client_by_id function to
149 get the client entry since this function may be very slow and should
150 be used only to initially get the client entries. */
152 void silc_client_get_clients(SilcClient client,
153 SilcClientConnection conn,
154 const char *nickname,
156 SilcGetClientCallback completion,
165 i = silc_calloc(1, sizeof(*i));
168 i->nickname = strdup(nickname);
169 i->server = server ? strdup(server) : NULL;
170 i->completion = completion;
171 i->context = context;
173 if (nickname && server) {
174 userhost = silc_calloc(strlen(nickname) + strlen(server) + 2,
176 strncat(userhost, nickname, strlen(nickname));
177 strncat(userhost, "@", 1);
178 strncat(userhost, server, strlen(server));
180 userhost = strdup(nickname);
183 /* Register our own command reply for this command */
184 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
185 silc_client_command_reply_identify_i, 0,
188 /* Send the command */
189 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
190 conn->cmd_ident, 1, 1, userhost,
193 /* Add pending callback */
194 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
195 silc_client_command_get_client_callback,
201 /* The old style function to find client entry. This is used by the
202 library internally. If `query' is TRUE then the client information is
203 requested by the server. The pending command callback must be set
205 /* XXX This function should be removed */
207 SilcClientEntry silc_idlist_get_client(SilcClient client,
208 SilcClientConnection conn,
209 const char *nickname,
213 SilcIDCacheEntry id_cache;
214 SilcIDCacheList list = NULL;
215 SilcClientEntry entry = NULL;
217 SILC_LOG_DEBUG(("Start"));
219 /* Find ID from cache */
220 if (!silc_idcache_find_by_name(conn->client_cache, (char *)nickname,
225 SILC_LOG_DEBUG(("Requesting Client ID from server"));
227 /* Register our own command reply for this command */
228 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
229 silc_client_command_reply_identify_i, 0,
232 /* Send the command */
233 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
234 conn->cmd_ident, 1, 1, nickname,
238 silc_idcache_list_free(list);
246 /* Take first found cache entry */
247 if (!silc_idcache_list_first(list, &id_cache))
250 entry = (SilcClientEntry)id_cache->context;
252 /* Check multiple cache entries for match */
253 silc_idcache_list_first(list, &id_cache);
255 entry = (SilcClientEntry)id_cache->context;
257 if (strcasecmp(entry->nickname, format)) {
258 if (!silc_idcache_list_next(list, &id_cache)) {
270 /* If match weren't found, request it */
276 silc_idcache_list_free(list);
284 SilcClientConnection conn;
286 SilcBuffer client_id_list;
287 SilcGetClientCallback completion;
289 } *GetClientsByListInternal;
291 SILC_CLIENT_CMD_FUNC(get_clients_list_callback)
293 GetClientsByListInternal i = (GetClientsByListInternal)context;
294 SilcIDCacheEntry id_cache = NULL;
295 SilcBuffer client_id_list = i->client_id_list;
296 SilcClientEntry *clients = NULL;
297 uint32 clients_count = 0;
301 SILC_LOG_DEBUG(("Start"));
303 for (c = 0; c < i->list_count; c++) {
305 SilcClientID *client_id;
308 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
310 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
312 silc_buffer_pull(client_id_list, idp_len);
316 /* Get the client entry */
317 if (silc_idcache_find_by_id_one_ext(i->conn->client_cache,
320 silc_hash_client_id_compare, NULL,
322 clients = silc_realloc(clients, sizeof(*clients) *
323 (clients_count + 1));
324 clients[clients_count] = (SilcClientEntry)id_cache->context;
329 silc_free(client_id);
330 silc_buffer_pull(client_id_list, idp_len);
334 i->completion(i->client, i->conn, clients, clients_count, i->context);
337 i->completion(i->client, i->conn, NULL, 0, i->context);
340 if (i->client_id_list)
341 silc_buffer_free(i->client_id_list);
345 /* Gets client entries by the list of client ID's `client_id_list'. This
346 always resolves those client ID's it does not know yet from the server
347 so this function might take a while. The `client_id_list' is a list
348 of ID Payloads added one after other. JOIN command reply and USERS
349 command reply for example returns this sort of list. The `completion'
350 will be called after the entries are available. */
352 void silc_client_get_clients_by_list(SilcClient client,
353 SilcClientConnection conn,
355 SilcBuffer client_id_list,
356 SilcGetClientCallback completion,
359 SilcIDCacheEntry id_cache = NULL;
361 unsigned char **res_argv = NULL;
362 uint32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
363 GetClientsByListInternal in;
365 SILC_LOG_DEBUG(("Start"));
367 in = silc_calloc(1, sizeof(*in));
370 in->list_count = list_count;
371 in->client_id_list = silc_buffer_copy(client_id_list);
372 in->completion = completion;
373 in->context = context;
375 for (i = 0; i < list_count; i++) {
377 SilcClientID *client_id;
378 SilcClientEntry entry;
381 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
383 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
385 silc_buffer_pull(client_id_list, idp_len);
389 /* Check if we have this client cached already. */
391 silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
393 silc_hash_client_id_compare, NULL,
396 /* If we don't have the entry or it has incomplete info, then resolve
397 it from the server. */
398 entry = id_cache ? (SilcClientEntry)id_cache->context : NULL;
399 if (!id_cache || !entry->nickname) {
402 if (entry->status & SILC_CLIENT_STATUS_RESOLVING) {
403 entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
404 silc_free(client_id);
405 silc_buffer_pull(client_id_list, idp_len);
409 entry->status |= SILC_CLIENT_STATUS_RESOLVING;
412 /* No we don't have it, query it from the server. Assemble argument
413 table that will be sent fr the IDENTIFY command later. */
414 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
416 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
418 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
420 res_argv[res_argc] = client_id_list->data;
421 res_argv_lens[res_argc] = idp_len;
422 res_argv_types[res_argc] = res_argc + 5;
426 silc_free(client_id);
427 silc_buffer_pull(client_id_list, idp_len);
430 /* Query the client information from server if the list included clients
431 that we don't know about. */
435 /* Send the IDENTIFY command to server */
436 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
437 res_argc, res_argv, res_argv_lens,
438 res_argv_types, ++conn->cmd_ident);
439 silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
440 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
443 /* Register our own command reply for this command */
444 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
445 silc_client_command_reply_identify_i, 0,
448 /* Process the applications request after reply has been received */
449 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
450 silc_client_command_get_clients_list_callback,
453 silc_buffer_push(client_id_list, client_id_list->data -
454 client_id_list->head);
455 silc_buffer_free(res_cmd);
457 silc_free(res_argv_lens);
458 silc_free(res_argv_types);
462 silc_buffer_push(client_id_list, client_id_list->data -
463 client_id_list->head);
465 /* We have the clients in cache, get them and call the completion */
466 silc_client_command_get_clients_list_callback((void *)in, NULL);
469 /* Finds entry for client by the client's ID. Returns the entry or NULL
470 if the entry was not found. */
472 SilcClientEntry silc_client_get_client_by_id(SilcClient client,
473 SilcClientConnection conn,
474 SilcClientID *client_id)
476 SilcIDCacheEntry id_cache;
478 SILC_LOG_DEBUG(("Finding client by ID (%s)",
479 silc_id_render(client_id, SILC_ID_CLIENT)));
481 /* Find ID from cache */
482 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
484 silc_hash_client_id_compare, NULL,
488 SILC_LOG_DEBUG(("Found"));
490 return (SilcClientEntry)id_cache->context;
495 SilcClientConnection conn;
496 SilcClientID *client_id;
497 SilcGetClientCallback completion;
499 } *GetClientByIDInternal;
501 SILC_CLIENT_CMD_FUNC(get_client_by_id_callback)
503 GetClientByIDInternal i = (GetClientByIDInternal)context;
504 SilcClientEntry entry;
507 entry = silc_client_get_client_by_id(i->client, i->conn, i->client_id);
509 i->completion(i->client, i->conn, &entry, 1, i->context);
511 i->completion(i->client, i->conn, NULL, 0, i->context);
513 silc_free(i->client_id);
517 /* Same as above but will always resolve the information from the server.
518 Use this only if you know that you don't have the entry and the only
519 thing you know about the client is its ID. */
521 void silc_client_get_client_by_id_resolve(SilcClient client,
522 SilcClientConnection conn,
523 SilcClientID *client_id,
524 SilcGetClientCallback completion,
528 GetClientByIDInternal i = silc_calloc(1, sizeof(*i));
530 SILC_LOG_DEBUG(("Start"));
534 i->client_id = silc_id_dup(client_id, SILC_ID_CLIENT);
535 i->completion = completion;
536 i->context = context;
538 /* Register our own command reply for this command */
539 silc_client_command_register(client, SILC_COMMAND_WHOIS, NULL, NULL,
540 silc_client_command_reply_whois_i, 0,
543 /* Send the command */
544 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
545 silc_client_command_send(client, conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
546 1, 3, idp->data, idp->len);
547 silc_buffer_free(idp);
549 /* Add pending callback */
550 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
551 silc_client_command_get_client_by_id_callback,
556 /******************************************************************************
558 Client, Channel and Server entry manipulation
560 ******************************************************************************/
563 /* Creates new client entry and adds it to the ID cache. Returns pointer
567 silc_client_add_client(SilcClient client, SilcClientConnection conn,
568 char *nickname, char *username,
569 char *userinfo, SilcClientID *id, uint32 mode)
571 SilcClientEntry client_entry;
574 SILC_LOG_DEBUG(("Start"));
576 /* Save the client infos */
577 client_entry = silc_calloc(1, sizeof(*client_entry));
578 client_entry->id = id;
579 client_entry->valid = TRUE;
580 silc_parse_userfqdn(nickname, &nick, &client_entry->server);
581 silc_parse_userfqdn(username, &client_entry->username,
582 &client_entry->hostname);
584 client_entry->realname = strdup(userinfo);
585 client_entry->mode = mode;
587 client_entry->nickname = strdup(nick);
588 client_entry->channels = silc_hash_table_alloc(1, silc_hash_ptr, NULL, NULL,
589 NULL, NULL, NULL, TRUE);
591 /* Format the nickname */
592 silc_client_nickname_format(client, conn, client_entry);
594 /* Add client to cache, the non-formatted nickname is saved to cache */
595 if (!silc_idcache_add(conn->client_cache, nick, client_entry->id,
596 (void *)client_entry, 0, NULL)) {
597 silc_free(client_entry->nickname);
598 silc_free(client_entry->username);
599 silc_free(client_entry->hostname);
600 silc_free(client_entry->server);
601 silc_hash_table_free(client_entry->channels);
602 silc_free(client_entry);
609 /* Updates the `client_entry' with the new information sent as argument. */
611 void silc_client_update_client(SilcClient client,
612 SilcClientConnection conn,
613 SilcClientEntry client_entry,
614 const char *nickname,
615 const char *username,
616 const char *userinfo,
621 SILC_LOG_DEBUG(("Start"));
623 if (!client_entry->username && username)
624 silc_parse_userfqdn(username, &client_entry->username,
625 &client_entry->hostname);
626 if (!client_entry->realname && userinfo)
627 client_entry->realname = strdup(userinfo);
628 if (!client_entry->nickname && nickname) {
629 silc_parse_userfqdn(nickname, &nick, &client_entry->server);
630 client_entry->nickname = strdup(nick);
631 silc_client_nickname_format(client, conn, client_entry);
633 client_entry->mode = mode;
636 /* Remove the old cache entry and create a new one */
637 silc_idcache_del_by_context(conn->client_cache, client_entry);
638 silc_idcache_add(conn->client_cache, nick, client_entry->id,
639 client_entry, 0, NULL);
643 /* Deletes the client entry and frees all memory. */
645 void silc_client_del_client_entry(SilcClient client,
646 SilcClientConnection conn,
647 SilcClientEntry client_entry)
649 SILC_LOG_DEBUG(("Start"));
651 silc_free(client_entry->nickname);
652 silc_free(client_entry->username);
653 silc_free(client_entry->realname);
654 silc_free(client_entry->hostname);
655 silc_free(client_entry->server);
656 silc_free(client_entry->id);
657 silc_free(client_entry->fingerprint);
658 silc_hash_table_free(client_entry->channels);
659 if (client_entry->send_key)
660 silc_cipher_free(client_entry->send_key);
661 if (client_entry->receive_key)
662 silc_cipher_free(client_entry->receive_key);
663 silc_free(client_entry->key);
664 silc_client_ftp_session_free_client(conn, client_entry);
665 if (client_entry->ke)
666 silc_client_abort_key_agreement(client, conn, client_entry);
667 silc_free(client_entry);
670 /* Removes client from the cache by the client entry. */
672 bool silc_client_del_client(SilcClient client, SilcClientConnection conn,
673 SilcClientEntry client_entry)
675 bool ret = silc_idcache_del_by_context(conn->client_cache, client_entry);
677 /* Remove from channels */
678 silc_client_remove_from_channels(client, conn, client_entry);
680 /* Free the client entry data */
681 silc_client_del_client_entry(client, conn, client_entry);
686 /* Add new channel entry to the ID Cache */
688 SilcChannelEntry silc_client_add_channel(SilcClient client,
689 SilcClientConnection conn,
690 const char *channel_name,
692 SilcChannelID *channel_id)
694 SilcChannelEntry channel;
696 SILC_LOG_DEBUG(("Start"));
698 channel = silc_calloc(1, sizeof(*channel));
699 channel->channel_name = strdup(channel_name);
700 channel->id = channel_id;
701 channel->mode = mode;
702 channel->user_list = silc_hash_table_alloc(1, silc_hash_ptr, NULL, NULL,
703 NULL, NULL, NULL, TRUE);
705 /* Put it to the ID cache */
706 if (!silc_idcache_add(conn->channel_cache, channel->channel_name,
707 (void *)channel->id, (void *)channel, 0, NULL)) {
708 silc_free(channel->channel_name);
709 silc_hash_table_free(channel->user_list);
717 /* Foreach callbcak to free all users from the channel when deleting a
720 static void silc_client_del_channel_foreach(void *key, void *context,
723 SilcChannelUser chu = (SilcChannelUser)context;
725 /* Remove the context from the client's channel hash table as that
726 table and channel's user_list hash table share this same context. */
727 silc_hash_table_del(chu->client->channels, chu->channel);
731 /* Removes channel from the cache by the channel entry. */
733 bool silc_client_del_channel(SilcClient client, SilcClientConnection conn,
734 SilcChannelEntry channel)
736 bool ret = silc_idcache_del_by_context(conn->channel_cache, channel);
738 /* Free all client entrys from the users list. The silc_hash_table_free
739 will free all the entries so they are not freed at the foreach
741 silc_hash_table_foreach(channel->user_list, silc_client_del_channel_foreach,
743 silc_hash_table_free(channel->user_list);
745 silc_free(channel->channel_name);
746 silc_free(channel->id);
747 silc_free(channel->key);
748 if (channel->channel_key)
749 silc_cipher_free(channel->channel_key);
751 silc_hmac_free(channel->hmac);
752 if (channel->old_channel_key)
753 silc_cipher_free(channel->old_channel_key);
754 if (channel->old_hmac)
755 silc_hmac_free(channel->old_hmac);
756 if (channel->rekey_task)
757 silc_schedule_task_del(conn->client->schedule, channel->rekey_task);
758 silc_client_del_channel_private_keys(client, conn, channel);
763 /* Replaces the channel ID of the `channel' to `new_id'. Returns FALSE
764 if the ID could not be changed. */
766 bool silc_client_replace_channel_id(SilcClient client,
767 SilcClientConnection conn,
768 SilcChannelEntry channel,
769 SilcChannelID *new_id)
774 SILC_LOG_DEBUG(("Old Channel ID id(%s)",
775 silc_id_render(channel->id, SILC_ID_CHANNEL)));
776 SILC_LOG_DEBUG(("New Channel ID id(%s)",
777 silc_id_render(new_id, SILC_ID_CHANNEL)));
779 silc_idcache_del_by_id(conn->channel_cache, channel->id);
780 silc_free(channel->id);
781 channel->id = new_id;
782 return silc_idcache_add(conn->channel_cache, channel->channel_name,
783 (void *)channel->id, (void *)channel, 0, NULL);
787 /* Finds entry for channel by the channel name. Returns the entry or NULL
788 if the entry was not found. It is found only if the client is joined
791 SilcChannelEntry silc_client_get_channel(SilcClient client,
792 SilcClientConnection conn,
795 SilcIDCacheEntry id_cache;
796 SilcChannelEntry entry;
798 SILC_LOG_DEBUG(("Start"));
800 if (!silc_idcache_find_by_name_one(conn->channel_cache, channel,
804 entry = (SilcChannelEntry)id_cache->context;
806 SILC_LOG_DEBUG(("Found"));
811 /* Finds entry for channel by the channel ID. Returns the entry or NULL
812 if the entry was not found. It is found only if the client is joined
815 SilcChannelEntry silc_client_get_channel_by_id(SilcClient client,
816 SilcClientConnection conn,
817 SilcChannelID *channel_id)
819 SilcIDCacheEntry id_cache;
820 SilcChannelEntry entry;
822 SILC_LOG_DEBUG(("Start"));
824 if (!silc_idcache_find_by_id_one(conn->channel_cache, channel_id,
828 entry = (SilcChannelEntry)id_cache->context;
830 SILC_LOG_DEBUG(("Found"));
837 SilcClientConnection conn;
838 SilcChannelID *channel_id;
839 SilcGetChannelCallback completion;
841 } *GetChannelByIDInternal;
843 SILC_CLIENT_CMD_FUNC(get_channel_by_id_callback)
845 GetChannelByIDInternal i = (GetChannelByIDInternal)context;
846 SilcChannelEntry entry;
848 SILC_LOG_DEBUG(("Start"));
850 /* Get the channel */
851 entry = silc_client_get_channel_by_id(i->client, i->conn, i->channel_id);
853 i->completion(i->client, i->conn, &entry, 1, i->context);
855 i->completion(i->client, i->conn, NULL, 0, i->context);
858 silc_free(i->channel_id);
862 /* Resolves channel information from the server by the channel ID. */
864 void silc_client_get_channel_by_id_resolve(SilcClient client,
865 SilcClientConnection conn,
866 SilcChannelID *channel_id,
867 SilcGetChannelCallback completion,
871 GetChannelByIDInternal i = silc_calloc(1, sizeof(*i));
873 SILC_LOG_DEBUG(("Start"));
877 i->channel_id = silc_id_dup(channel_id, SILC_ID_CHANNEL);
878 i->completion = completion;
879 i->context = context;
881 /* Register our own command reply for this command */
882 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
883 silc_client_command_reply_identify_i, 0,
886 /* Send the command */
887 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
888 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
890 1, 5, idp->data, idp->len);
891 silc_buffer_free(idp);
893 /* Add pending callback */
894 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
895 silc_client_command_get_channel_by_id_callback,
899 /* Finds entry for server by the server name. */
901 SilcServerEntry silc_client_get_server(SilcClient client,
902 SilcClientConnection conn,
905 SilcIDCacheEntry id_cache;
906 SilcServerEntry entry;
908 SILC_LOG_DEBUG(("Start"));
910 if (!silc_idcache_find_by_name_one(conn->server_cache, server_name,
914 entry = (SilcServerEntry)id_cache->context;
919 /* Finds entry for server by the server ID. */
921 SilcServerEntry silc_client_get_server_by_id(SilcClient client,
922 SilcClientConnection conn,
923 SilcServerID *server_id)
925 SilcIDCacheEntry id_cache;
926 SilcServerEntry entry;
928 SILC_LOG_DEBUG(("Start"));
930 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
934 entry = (SilcServerEntry)id_cache->context;
939 /* Removes server from the cache by the server entry. */
941 bool silc_client_del_server(SilcClient client, SilcClientConnection conn,
942 SilcServerEntry server)
944 bool ret = silc_idcache_del_by_context(conn->server_cache, server);
945 silc_free(server->server_name);
946 silc_free(server->server_info);
947 silc_free(server->server_id);
952 /* Formats the nickname of the client specified by the `client_entry'.
953 If the format is specified by the application this will format the
954 nickname and replace the old nickname in the client entry. If the
955 format string is not specified then this function has no effect. */
957 void silc_client_nickname_format(SilcClient client,
958 SilcClientConnection conn,
959 SilcClientEntry client_entry)
962 char *newnick = NULL;
964 SilcClientEntry *clients;
965 uint32 clients_count = 0;
966 SilcClientEntry unformatted = NULL;
968 SILC_LOG_DEBUG(("Start"));
970 if (!client->internal->params->nickname_format[0])
973 if (!client_entry->nickname)
976 /* Get all clients with same nickname. Do not perform the formatting
977 if there aren't any clients with same nickname unless the application
978 is forcing us to do so. */
979 clients = silc_client_get_clients_local(client, conn,
980 client_entry->nickname, NULL,
982 if (!clients && !client->internal->params->nickname_force_format)
986 for (i = 0; i < clients_count; i++)
987 if (clients[i]->valid && clients[i] != client_entry)
992 cp = client->internal->params->nickname_format;
1002 if (!client_entry->nickname)
1004 len = strlen(client_entry->nickname);
1005 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1006 memcpy(&newnick[off], client_entry->nickname, len);
1010 /* Stripped hostname */
1011 if (!client_entry->hostname)
1013 len = strcspn(client_entry->hostname, ".");
1014 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1015 memcpy(&newnick[off], client_entry->hostname, len);
1020 if (!client_entry->hostname)
1022 len = strlen(client_entry->hostname);
1023 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1024 memcpy(&newnick[off], client_entry->hostname, len);
1028 /* Stripped server name */
1029 if (!client_entry->server)
1031 len = strcspn(client_entry->server, ".");
1032 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1033 memcpy(&newnick[off], client_entry->server, len);
1037 /* Full server name */
1038 if (!client_entry->server)
1040 len = strlen(client_entry->server);
1041 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1042 memcpy(&newnick[off], client_entry->server, len);
1046 /* Ascending number */
1051 if (clients_count == 1) {
1052 unformatted = clients[0];
1056 for (i = 0; i < clients_count; i++) {
1057 if (!strncasecmp(clients[i]->nickname, client_entry->nickname,
1058 strlen(clients[i]->nickname)))
1059 unformatted = clients[i];
1060 if (strncasecmp(clients[i]->nickname, newnick, off))
1062 if (strlen(clients[i]->nickname) <= off)
1064 num = atoi(&clients[i]->nickname[off]);
1069 memset(tmp, 0, sizeof(tmp));
1070 snprintf(tmp, sizeof(tmp) - 1, "%d", ++max);
1072 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1073 memcpy(&newnick[off], tmp, len);
1078 /* Some other character in the string */
1079 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
1080 memcpy(&newnick[off], cp, 1);
1088 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
1091 /* If we are changing nickname of our local entry we'll enforce
1092 that we will always get the unformatted nickname. Give our
1093 format number to the one that is not formatted now. */
1094 if (unformatted && client_entry == conn->local_entry)
1095 client_entry = unformatted;
1097 silc_free(client_entry->nickname);
1098 client_entry->nickname = newnick;