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 SILC_LOG_DEBUG(("Start"));
727 /* Remove the context from the client's channel hash table as that
728 table and channel's user_list hash table share this same context. */
729 silc_hash_table_del(chu->client->channels, chu->channel);
733 /* Removes channel from the cache by the channel entry. */
735 bool silc_client_del_channel(SilcClient client, SilcClientConnection conn,
736 SilcChannelEntry channel)
738 bool ret = silc_idcache_del_by_context(conn->channel_cache, channel);
740 SILC_LOG_DEBUG(("Start"));
742 /* Free all client entrys from the users list. The silc_hash_table_free
743 will free all the entries so they are not freed at the foreach
745 silc_hash_table_foreach(channel->user_list, silc_client_del_channel_foreach,
747 silc_hash_table_free(channel->user_list);
749 silc_free(channel->channel_name);
750 silc_free(channel->id);
751 silc_free(channel->key);
752 if (channel->channel_key)
753 silc_cipher_free(channel->channel_key);
755 silc_hmac_free(channel->hmac);
756 if (channel->old_channel_key)
757 silc_cipher_free(channel->old_channel_key);
758 if (channel->old_hmac)
759 silc_hmac_free(channel->old_hmac);
760 if (channel->rekey_task)
761 silc_schedule_task_del(conn->client->schedule, channel->rekey_task);
762 silc_client_del_channel_private_keys(client, conn, channel);
767 /* Replaces the channel ID of the `channel' to `new_id'. Returns FALSE
768 if the ID could not be changed. */
770 bool silc_client_replace_channel_id(SilcClient client,
771 SilcClientConnection conn,
772 SilcChannelEntry channel,
773 SilcChannelID *new_id)
778 SILC_LOG_DEBUG(("Old Channel ID id(%s)",
779 silc_id_render(channel->id, SILC_ID_CHANNEL)));
780 SILC_LOG_DEBUG(("New Channel ID id(%s)",
781 silc_id_render(new_id, SILC_ID_CHANNEL)));
783 silc_idcache_del_by_id(conn->channel_cache, channel->id);
784 silc_free(channel->id);
785 channel->id = new_id;
786 return silc_idcache_add(conn->channel_cache, channel->channel_name,
787 (void *)channel->id, (void *)channel, 0, NULL);
791 /* Finds entry for channel by the channel name. Returns the entry or NULL
792 if the entry was not found. It is found only if the client is joined
795 SilcChannelEntry silc_client_get_channel(SilcClient client,
796 SilcClientConnection conn,
799 SilcIDCacheEntry id_cache;
800 SilcChannelEntry entry;
802 SILC_LOG_DEBUG(("Start"));
804 if (!silc_idcache_find_by_name_one(conn->channel_cache, channel,
808 entry = (SilcChannelEntry)id_cache->context;
810 SILC_LOG_DEBUG(("Found"));
815 /* Finds entry for channel by the channel ID. Returns the entry or NULL
816 if the entry was not found. It is found only if the client is joined
819 SilcChannelEntry silc_client_get_channel_by_id(SilcClient client,
820 SilcClientConnection conn,
821 SilcChannelID *channel_id)
823 SilcIDCacheEntry id_cache;
824 SilcChannelEntry entry;
826 SILC_LOG_DEBUG(("Start"));
828 if (!silc_idcache_find_by_id_one(conn->channel_cache, channel_id,
832 entry = (SilcChannelEntry)id_cache->context;
834 SILC_LOG_DEBUG(("Found"));
841 SilcClientConnection conn;
842 SilcChannelID *channel_id;
843 SilcGetChannelCallback completion;
845 } *GetChannelByIDInternal;
847 SILC_CLIENT_CMD_FUNC(get_channel_by_id_callback)
849 GetChannelByIDInternal i = (GetChannelByIDInternal)context;
850 SilcChannelEntry entry;
852 SILC_LOG_DEBUG(("Start"));
854 /* Get the channel */
855 entry = silc_client_get_channel_by_id(i->client, i->conn, i->channel_id);
857 i->completion(i->client, i->conn, &entry, 1, i->context);
859 i->completion(i->client, i->conn, NULL, 0, i->context);
862 silc_free(i->channel_id);
866 /* Resolves channel information from the server by the channel ID. */
868 void silc_client_get_channel_by_id_resolve(SilcClient client,
869 SilcClientConnection conn,
870 SilcChannelID *channel_id,
871 SilcGetChannelCallback completion,
875 GetChannelByIDInternal i = silc_calloc(1, sizeof(*i));
877 SILC_LOG_DEBUG(("Start"));
881 i->channel_id = silc_id_dup(channel_id, SILC_ID_CHANNEL);
882 i->completion = completion;
883 i->context = context;
885 /* Register our own command reply for this command */
886 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
887 silc_client_command_reply_identify_i, 0,
890 /* Send the command */
891 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
892 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
894 1, 5, idp->data, idp->len);
895 silc_buffer_free(idp);
897 /* Add pending callback */
898 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
899 silc_client_command_get_channel_by_id_callback,
903 /* Finds entry for server by the server name. */
905 SilcServerEntry silc_client_get_server(SilcClient client,
906 SilcClientConnection conn,
909 SilcIDCacheEntry id_cache;
910 SilcServerEntry entry;
912 SILC_LOG_DEBUG(("Start"));
914 if (!silc_idcache_find_by_name_one(conn->server_cache, server_name,
918 entry = (SilcServerEntry)id_cache->context;
923 /* Finds entry for server by the server ID. */
925 SilcServerEntry silc_client_get_server_by_id(SilcClient client,
926 SilcClientConnection conn,
927 SilcServerID *server_id)
929 SilcIDCacheEntry id_cache;
930 SilcServerEntry entry;
932 SILC_LOG_DEBUG(("Start"));
934 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
938 entry = (SilcServerEntry)id_cache->context;
943 /* Removes server from the cache by the server entry. */
945 bool silc_client_del_server(SilcClient client, SilcClientConnection conn,
946 SilcServerEntry server)
948 bool ret = silc_idcache_del_by_context(conn->server_cache, server);
949 silc_free(server->server_name);
950 silc_free(server->server_info);
951 silc_free(server->server_id);
956 /* Formats the nickname of the client specified by the `client_entry'.
957 If the format is specified by the application this will format the
958 nickname and replace the old nickname in the client entry. If the
959 format string is not specified then this function has no effect. */
961 void silc_client_nickname_format(SilcClient client,
962 SilcClientConnection conn,
963 SilcClientEntry client_entry)
966 char *newnick = NULL;
968 SilcClientEntry *clients;
969 uint32 clients_count = 0;
970 SilcClientEntry unformatted = NULL;
972 SILC_LOG_DEBUG(("Start"));
974 if (!client->internal->params->nickname_format[0])
977 if (!client_entry->nickname)
980 /* Get all clients with same nickname. Do not perform the formatting
981 if there aren't any clients with same nickname unless the application
982 is forcing us to do so. */
983 clients = silc_client_get_clients_local(client, conn,
984 client_entry->nickname, NULL,
986 if (!clients && !client->internal->params->nickname_force_format)
990 for (i = 0; i < clients_count; i++)
991 if (clients[i]->valid && clients[i] != client_entry)
996 cp = client->internal->params->nickname_format;
1006 if (!client_entry->nickname)
1008 len = strlen(client_entry->nickname);
1009 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1010 memcpy(&newnick[off], client_entry->nickname, len);
1014 /* Stripped hostname */
1015 if (!client_entry->hostname)
1017 len = strcspn(client_entry->hostname, ".");
1018 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1019 memcpy(&newnick[off], client_entry->hostname, len);
1024 if (!client_entry->hostname)
1026 len = strlen(client_entry->hostname);
1027 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1028 memcpy(&newnick[off], client_entry->hostname, len);
1032 /* Stripped server name */
1033 if (!client_entry->server)
1035 len = strcspn(client_entry->server, ".");
1036 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1037 memcpy(&newnick[off], client_entry->server, len);
1041 /* Full server name */
1042 if (!client_entry->server)
1044 len = strlen(client_entry->server);
1045 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1046 memcpy(&newnick[off], client_entry->server, len);
1050 /* Ascending number */
1055 if (clients_count == 1) {
1056 unformatted = clients[0];
1060 for (i = 0; i < clients_count; i++) {
1061 if (!strncasecmp(clients[i]->nickname, client_entry->nickname,
1062 strlen(clients[i]->nickname)))
1063 unformatted = clients[i];
1064 if (strncasecmp(clients[i]->nickname, newnick, off))
1066 if (strlen(clients[i]->nickname) <= off)
1068 num = atoi(&clients[i]->nickname[off]);
1073 memset(tmp, 0, sizeof(tmp));
1074 snprintf(tmp, sizeof(tmp) - 1, "%d", ++max);
1076 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1077 memcpy(&newnick[off], tmp, len);
1082 /* Some other character in the string */
1083 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
1084 memcpy(&newnick[off], cp, 1);
1092 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
1095 /* If we are changing nickname of our local entry we'll enforce
1096 that we will always get the unformatted nickname. Give our
1097 format number to the one that is not formatted now. */
1098 if (unformatted && client_entry == conn->local_entry)
1099 client_entry = unformatted;
1101 silc_free(client_entry->nickname);
1102 client_entry->nickname = newnick;