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;
365 bool wait_res = FALSE;
367 SILC_LOG_DEBUG(("Start"));
369 in = silc_calloc(1, sizeof(*in));
372 in->list_count = list_count;
373 in->client_id_list = silc_buffer_copy(client_id_list);
374 in->completion = completion;
375 in->context = context;
377 for (i = 0; i < list_count; i++) {
379 SilcClientID *client_id;
380 SilcClientEntry entry;
384 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
386 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
388 silc_buffer_pull(client_id_list, idp_len);
392 /* Check if we have this client cached already. */
394 silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
396 silc_hash_client_id_compare, NULL,
399 /* If we don't have the entry or it has incomplete info, then resolve
400 it from the server. */
401 if (!ret || !((SilcClientEntry)id_cache->context)->nickname) {
402 entry = ret ? (SilcClientEntry)id_cache->context : NULL;
405 if (entry->status & SILC_CLIENT_STATUS_RESOLVING) {
406 /* Attach to this resolving and wait until it finishes */
407 silc_client_command_pending(
408 conn, SILC_COMMAND_NONE,
409 entry->resolve_cmd_ident,
410 silc_client_command_get_clients_list_callback,
414 silc_free(client_id);
415 silc_buffer_pull(client_id_list, idp_len);
419 entry->status |= SILC_CLIENT_STATUS_RESOLVING;
420 entry->resolve_cmd_ident = conn->cmd_ident + 1;
423 /* No we don't have it, query it from the server. Assemble argument
424 table that will be sent fr the IDENTIFY command later. */
425 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
427 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
429 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
431 res_argv[res_argc] = client_id_list->data;
432 res_argv_lens[res_argc] = idp_len;
433 res_argv_types[res_argc] = res_argc + 5;
437 silc_free(client_id);
438 silc_buffer_pull(client_id_list, idp_len);
441 silc_buffer_push(client_id_list, client_id_list->data -
442 client_id_list->head);
444 /* Query the client information from server if the list included clients
445 that we don't know about. */
449 /* Send the IDENTIFY command to server */
450 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
451 res_argc, res_argv, res_argv_lens,
452 res_argv_types, ++conn->cmd_ident);
453 silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
454 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
457 /* Register our own command reply for this command */
458 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
459 silc_client_command_reply_identify_i, 0,
462 /* Process the applications request after reply has been received */
463 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
464 silc_client_command_get_clients_list_callback,
467 silc_buffer_free(res_cmd);
469 silc_free(res_argv_lens);
470 silc_free(res_argv_types);
477 /* We have the clients in cache, get them and call the completion */
478 silc_client_command_get_clients_list_callback((void *)in, NULL);
481 /* Finds entry for client by the client's ID. Returns the entry or NULL
482 if the entry was not found. */
484 SilcClientEntry silc_client_get_client_by_id(SilcClient client,
485 SilcClientConnection conn,
486 SilcClientID *client_id)
488 SilcIDCacheEntry id_cache;
490 SILC_LOG_DEBUG(("Finding client by ID (%s)",
491 silc_id_render(client_id, SILC_ID_CLIENT)));
493 /* Find ID from cache */
494 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
496 silc_hash_client_id_compare, NULL,
500 SILC_LOG_DEBUG(("Found"));
502 return (SilcClientEntry)id_cache->context;
507 SilcClientConnection conn;
508 SilcClientID *client_id;
509 SilcGetClientCallback completion;
511 } *GetClientByIDInternal;
513 SILC_CLIENT_CMD_FUNC(get_client_by_id_callback)
515 GetClientByIDInternal i = (GetClientByIDInternal)context;
516 SilcClientEntry entry;
519 entry = silc_client_get_client_by_id(i->client, i->conn, i->client_id);
522 i->completion(i->client, i->conn, &entry, 1, i->context);
525 i->completion(i->client, i->conn, NULL, 0, i->context);
528 silc_free(i->client_id);
532 /* Same as above but will always resolve the information from the server.
533 Use this only if you know that you don't have the entry and the only
534 thing you know about the client is its ID. */
536 void silc_client_get_client_by_id_resolve(SilcClient client,
537 SilcClientConnection conn,
538 SilcClientID *client_id,
539 SilcGetClientCallback completion,
543 GetClientByIDInternal i = silc_calloc(1, sizeof(*i));
545 SILC_LOG_DEBUG(("Start"));
549 i->client_id = silc_id_dup(client_id, SILC_ID_CLIENT);
550 i->completion = completion;
551 i->context = context;
553 /* Register our own command reply for this command */
554 silc_client_command_register(client, SILC_COMMAND_WHOIS, NULL, NULL,
555 silc_client_command_reply_whois_i, 0,
558 /* Send the command */
559 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
560 silc_client_command_send(client, conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
561 1, 4, idp->data, idp->len);
562 silc_buffer_free(idp);
564 /* Add pending callback */
565 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
566 silc_client_command_get_client_by_id_callback,
571 /******************************************************************************
573 Client, Channel and Server entry manipulation
575 ******************************************************************************/
578 /* Creates new client entry and adds it to the ID cache. Returns pointer
582 silc_client_add_client(SilcClient client, SilcClientConnection conn,
583 char *nickname, char *username,
584 char *userinfo, SilcClientID *id, SilcUInt32 mode)
586 SilcClientEntry client_entry;
589 SILC_LOG_DEBUG(("Start"));
591 /* Save the client infos */
592 client_entry = silc_calloc(1, sizeof(*client_entry));
593 client_entry->id = id;
594 client_entry->valid = TRUE;
595 silc_parse_userfqdn(nickname, &nick, &client_entry->server);
596 silc_parse_userfqdn(username, &client_entry->username,
597 &client_entry->hostname);
599 client_entry->realname = strdup(userinfo);
600 client_entry->mode = mode;
602 client_entry->nickname = strdup(nick);
603 client_entry->channels = silc_hash_table_alloc(1, silc_hash_ptr, NULL, NULL,
604 NULL, NULL, NULL, TRUE);
606 /* Format the nickname */
607 silc_client_nickname_format(client, conn, client_entry);
609 /* Add client to cache, the non-formatted nickname is saved to cache */
610 if (!silc_idcache_add(conn->client_cache, nick, client_entry->id,
611 (void *)client_entry, 0, NULL)) {
612 silc_free(client_entry->nickname);
613 silc_free(client_entry->username);
614 silc_free(client_entry->hostname);
615 silc_free(client_entry->server);
616 silc_hash_table_free(client_entry->channels);
617 silc_free(client_entry);
624 /* Updates the `client_entry' with the new information sent as argument. */
626 void silc_client_update_client(SilcClient client,
627 SilcClientConnection conn,
628 SilcClientEntry client_entry,
629 const char *nickname,
630 const char *username,
631 const char *userinfo,
636 SILC_LOG_DEBUG(("Start"));
638 if (!client_entry->username && username)
639 silc_parse_userfqdn(username, &client_entry->username,
640 &client_entry->hostname);
641 if (!client_entry->realname && userinfo)
642 client_entry->realname = strdup(userinfo);
643 if (!client_entry->nickname && nickname) {
644 silc_parse_userfqdn(nickname, &nick, &client_entry->server);
645 client_entry->nickname = strdup(nick);
646 silc_client_nickname_format(client, conn, client_entry);
648 client_entry->mode = mode;
651 /* Remove the old cache entry and create a new one */
652 silc_idcache_del_by_context(conn->client_cache, client_entry);
653 silc_idcache_add(conn->client_cache, nick, client_entry->id,
654 client_entry, 0, NULL);
658 /* Deletes the client entry and frees all memory. */
660 void silc_client_del_client_entry(SilcClient client,
661 SilcClientConnection conn,
662 SilcClientEntry client_entry)
664 SILC_LOG_DEBUG(("Start"));
666 silc_free(client_entry->nickname);
667 silc_free(client_entry->username);
668 silc_free(client_entry->realname);
669 silc_free(client_entry->hostname);
670 silc_free(client_entry->server);
671 silc_free(client_entry->id);
672 silc_free(client_entry->fingerprint);
673 silc_hash_table_free(client_entry->channels);
674 if (client_entry->send_key)
675 silc_cipher_free(client_entry->send_key);
676 if (client_entry->receive_key)
677 silc_cipher_free(client_entry->receive_key);
678 silc_free(client_entry->key);
679 silc_client_ftp_session_free_client(conn, client_entry);
680 if (client_entry->ke)
681 silc_client_abort_key_agreement(client, conn, client_entry);
682 silc_free(client_entry);
685 /* Removes client from the cache by the client entry. */
687 bool silc_client_del_client(SilcClient client, SilcClientConnection conn,
688 SilcClientEntry client_entry)
690 bool ret = silc_idcache_del_by_context(conn->client_cache, client_entry);
692 /* Remove from channels */
693 silc_client_remove_from_channels(client, conn, client_entry);
695 /* Free the client entry data */
696 silc_client_del_client_entry(client, conn, client_entry);
701 /* Add new channel entry to the ID Cache */
703 SilcChannelEntry silc_client_add_channel(SilcClient client,
704 SilcClientConnection conn,
705 const char *channel_name,
707 SilcChannelID *channel_id)
709 SilcChannelEntry channel;
711 SILC_LOG_DEBUG(("Start"));
713 channel = silc_calloc(1, sizeof(*channel));
714 channel->channel_name = strdup(channel_name);
715 channel->id = channel_id;
716 channel->mode = mode;
717 channel->user_list = silc_hash_table_alloc(1, silc_hash_ptr, NULL, NULL,
718 NULL, NULL, NULL, TRUE);
720 /* Put it to the ID cache */
721 if (!silc_idcache_add(conn->channel_cache, channel->channel_name,
722 (void *)channel->id, (void *)channel, 0, NULL)) {
723 silc_free(channel->channel_name);
724 silc_hash_table_free(channel->user_list);
732 /* Foreach callbcak to free all users from the channel when deleting a
735 static void silc_client_del_channel_foreach(void *key, void *context,
738 SilcChannelUser chu = (SilcChannelUser)context;
740 SILC_LOG_DEBUG(("Start"));
742 /* Remove the context from the client's channel hash table as that
743 table and channel's user_list hash table share this same context. */
744 silc_hash_table_del(chu->client->channels, chu->channel);
748 /* Removes channel from the cache by the channel entry. */
750 bool silc_client_del_channel(SilcClient client, SilcClientConnection conn,
751 SilcChannelEntry channel)
753 bool ret = silc_idcache_del_by_context(conn->channel_cache, channel);
755 SILC_LOG_DEBUG(("Start"));
757 /* Free all client entrys from the users list. The silc_hash_table_free
758 will free all the entries so they are not freed at the foreach
760 silc_hash_table_foreach(channel->user_list, silc_client_del_channel_foreach,
762 silc_hash_table_free(channel->user_list);
764 silc_free(channel->channel_name);
765 silc_free(channel->id);
766 silc_free(channel->key);
767 if (channel->channel_key)
768 silc_cipher_free(channel->channel_key);
770 silc_hmac_free(channel->hmac);
771 if (channel->old_channel_key)
772 silc_cipher_free(channel->old_channel_key);
773 if (channel->old_hmac)
774 silc_hmac_free(channel->old_hmac);
775 if (channel->rekey_task)
776 silc_schedule_task_del(conn->client->schedule, channel->rekey_task);
777 silc_client_del_channel_private_keys(client, conn, channel);
782 /* Replaces the channel ID of the `channel' to `new_id'. Returns FALSE
783 if the ID could not be changed. */
785 bool silc_client_replace_channel_id(SilcClient client,
786 SilcClientConnection conn,
787 SilcChannelEntry channel,
788 SilcChannelID *new_id)
793 SILC_LOG_DEBUG(("Old Channel ID id(%s)",
794 silc_id_render(channel->id, SILC_ID_CHANNEL)));
795 SILC_LOG_DEBUG(("New Channel ID id(%s)",
796 silc_id_render(new_id, SILC_ID_CHANNEL)));
798 silc_idcache_del_by_id(conn->channel_cache, channel->id);
799 silc_free(channel->id);
800 channel->id = new_id;
801 return silc_idcache_add(conn->channel_cache, channel->channel_name,
802 (void *)channel->id, (void *)channel, 0, NULL);
806 /* Finds entry for channel by the channel name. Returns the entry or NULL
807 if the entry was not found. It is found only if the client is joined
810 SilcChannelEntry silc_client_get_channel(SilcClient client,
811 SilcClientConnection conn,
814 SilcIDCacheEntry id_cache;
815 SilcChannelEntry entry;
817 SILC_LOG_DEBUG(("Start"));
819 if (!silc_idcache_find_by_name_one(conn->channel_cache, channel,
823 entry = (SilcChannelEntry)id_cache->context;
825 SILC_LOG_DEBUG(("Found"));
830 /* Finds entry for channel by the channel ID. Returns the entry or NULL
831 if the entry was not found. It is found only if the client is joined
834 SilcChannelEntry silc_client_get_channel_by_id(SilcClient client,
835 SilcClientConnection conn,
836 SilcChannelID *channel_id)
838 SilcIDCacheEntry id_cache;
839 SilcChannelEntry entry;
841 SILC_LOG_DEBUG(("Start"));
843 if (!silc_idcache_find_by_id_one(conn->channel_cache, channel_id,
847 entry = (SilcChannelEntry)id_cache->context;
849 SILC_LOG_DEBUG(("Found"));
856 SilcClientConnection conn;
857 SilcChannelID *channel_id;
858 SilcGetChannelCallback completion;
860 } *GetChannelByIDInternal;
862 SILC_CLIENT_CMD_FUNC(get_channel_by_id_callback)
864 GetChannelByIDInternal i = (GetChannelByIDInternal)context;
865 SilcChannelEntry entry;
867 SILC_LOG_DEBUG(("Start"));
869 /* Get the channel */
870 entry = silc_client_get_channel_by_id(i->client, i->conn, i->channel_id);
872 i->completion(i->client, i->conn, &entry, 1, i->context);
874 i->completion(i->client, i->conn, NULL, 0, i->context);
877 silc_free(i->channel_id);
881 /* Resolves channel information from the server by the channel ID. */
883 void silc_client_get_channel_by_id_resolve(SilcClient client,
884 SilcClientConnection conn,
885 SilcChannelID *channel_id,
886 SilcGetChannelCallback completion,
890 GetChannelByIDInternal i = silc_calloc(1, sizeof(*i));
892 SILC_LOG_DEBUG(("Start"));
896 i->channel_id = silc_id_dup(channel_id, SILC_ID_CHANNEL);
897 i->completion = completion;
898 i->context = context;
900 /* Register our own command reply for this command */
901 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
902 silc_client_command_reply_identify_i, 0,
905 /* Send the command */
906 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
907 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
909 1, 5, idp->data, idp->len);
910 silc_buffer_free(idp);
912 /* Add pending callback */
913 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
914 silc_client_command_get_channel_by_id_callback,
918 /* Finds entry for server by the server name. */
920 SilcServerEntry silc_client_get_server(SilcClient client,
921 SilcClientConnection conn,
924 SilcIDCacheEntry id_cache;
925 SilcServerEntry entry;
927 SILC_LOG_DEBUG(("Start"));
929 if (!silc_idcache_find_by_name_one(conn->server_cache, server_name,
933 entry = (SilcServerEntry)id_cache->context;
938 /* Finds entry for server by the server ID. */
940 SilcServerEntry silc_client_get_server_by_id(SilcClient client,
941 SilcClientConnection conn,
942 SilcServerID *server_id)
944 SilcIDCacheEntry id_cache;
945 SilcServerEntry entry;
947 SILC_LOG_DEBUG(("Start"));
949 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
953 entry = (SilcServerEntry)id_cache->context;
958 /* Add new server entry */
960 SilcServerEntry silc_client_add_server(SilcClient client,
961 SilcClientConnection conn,
962 const char *server_name,
963 const char *server_info,
964 SilcServerID *server_id)
966 SilcServerEntry server_entry;
968 server_entry = silc_calloc(1, sizeof(*server_entry));
969 if (!server_entry || !server_id)
972 server_entry->server_id = server_id;
974 server_entry->server_name = strdup(server_name);
976 server_entry->server_info = strdup(server_info);
978 /* Add server to cache */
979 if (!silc_idcache_add(conn->server_cache, server_entry->server_name,
980 server_entry->server_id, server_entry, 0, NULL)) {
981 silc_free(server_entry->server_id);
982 silc_free(server_entry->server_name);
983 silc_free(server_entry->server_info);
984 silc_free(server_entry);
991 /* Removes server from the cache by the server entry. */
993 bool silc_client_del_server(SilcClient client, SilcClientConnection conn,
994 SilcServerEntry server)
996 bool ret = silc_idcache_del_by_context(conn->server_cache, server);
997 silc_free(server->server_name);
998 silc_free(server->server_info);
999 silc_free(server->server_id);
1004 /* Formats the nickname of the client specified by the `client_entry'.
1005 If the format is specified by the application this will format the
1006 nickname and replace the old nickname in the client entry. If the
1007 format string is not specified then this function has no effect. */
1009 void silc_client_nickname_format(SilcClient client,
1010 SilcClientConnection conn,
1011 SilcClientEntry client_entry)
1014 char *newnick = NULL;
1015 int i, off = 0, len;
1017 SilcClientEntry *clients;
1018 SilcUInt32 clients_count = 0;
1019 SilcClientEntry unformatted = NULL;
1021 SILC_LOG_DEBUG(("Start"));
1023 if (!client->internal->params->nickname_format[0])
1026 if (!client_entry->nickname)
1029 /* Get all clients with same nickname. Do not perform the formatting
1030 if there aren't any clients with same nickname unless the application
1031 is forcing us to do so. */
1032 clients = silc_client_get_clients_local(client, conn,
1033 client_entry->nickname, NULL,
1035 if (!clients && !client->internal->params->nickname_force_format)
1040 for (i = 0; i < clients_count; i++) {
1041 if (clients[i]->valid && clients[i] != client_entry)
1043 if (clients[i]->valid && clients[i] != client_entry &&
1044 !strcmp(clients[i]->nickname, client_entry->nickname))
1047 if (!len || freebase)
1050 cp = client->internal->params->nickname_format;
1060 if (!client_entry->nickname)
1062 len = strlen(client_entry->nickname);
1063 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1064 memcpy(&newnick[off], client_entry->nickname, len);
1068 /* Stripped hostname */
1069 if (!client_entry->hostname)
1071 len = strcspn(client_entry->hostname, ".");
1072 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1073 memcpy(&newnick[off], client_entry->hostname, len);
1078 if (!client_entry->hostname)
1080 len = strlen(client_entry->hostname);
1081 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1082 memcpy(&newnick[off], client_entry->hostname, len);
1086 /* Stripped server name */
1087 if (!client_entry->server)
1089 len = strcspn(client_entry->server, ".");
1090 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1091 memcpy(&newnick[off], client_entry->server, len);
1095 /* Full server name */
1096 if (!client_entry->server)
1098 len = strlen(client_entry->server);
1099 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1100 memcpy(&newnick[off], client_entry->server, len);
1104 /* Ascending number */
1109 if (clients_count == 1) {
1110 unformatted = clients[0];
1114 for (i = 0; i < clients_count; i++) {
1115 if (!strncasecmp(clients[i]->nickname, client_entry->nickname,
1116 strlen(clients[i]->nickname)))
1117 unformatted = clients[i];
1118 if (strncasecmp(clients[i]->nickname, newnick, off))
1120 if (strlen(clients[i]->nickname) <= off)
1122 num = atoi(&clients[i]->nickname[off]);
1127 memset(tmp, 0, sizeof(tmp));
1128 snprintf(tmp, sizeof(tmp) - 1, "%d", ++max);
1130 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1131 memcpy(&newnick[off], tmp, len);
1136 /* Some other character in the string */
1137 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
1138 memcpy(&newnick[off], cp, 1);
1146 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
1149 /* If we are changing nickname of our local entry we'll enforce
1150 that we will always get the unformatted nickname. Give our
1151 format number to the one that is not formatted now. */
1152 if (unformatted && client_entry == conn->local_entry)
1153 client_entry = unformatted;
1155 silc_free(client_entry->nickname);
1156 client_entry->nickname = newnick;