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;
382 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
384 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
386 silc_buffer_pull(client_id_list, idp_len);
390 /* Check if we have this client cached already. */
392 silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
394 silc_hash_client_id_compare, NULL,
397 /* If we don't have the entry or it has incomplete info, then resolve
398 it from the server. */
399 entry = id_cache ? (SilcClientEntry)id_cache->context : NULL;
400 if (!id_cache || !entry->nickname) {
403 if (entry->status & SILC_CLIENT_STATUS_RESOLVING) {
404 entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
405 silc_free(client_id);
406 silc_buffer_pull(client_id_list, idp_len);
410 entry->status |= SILC_CLIENT_STATUS_RESOLVING;
413 /* No we don't have it, query it from the server. Assemble argument
414 table that will be sent fr the IDENTIFY command later. */
415 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
417 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
419 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
421 res_argv[res_argc] = client_id_list->data;
422 res_argv_lens[res_argc] = idp_len;
423 res_argv_types[res_argc] = res_argc + 5;
427 silc_free(client_id);
428 silc_buffer_pull(client_id_list, idp_len);
431 /* Query the client information from server if the list included clients
432 that we don't know about. */
436 /* Send the IDENTIFY command to server */
437 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
438 res_argc, res_argv, res_argv_lens,
439 res_argv_types, ++conn->cmd_ident);
440 silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
441 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
444 /* Register our own command reply for this command */
445 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
446 silc_client_command_reply_identify_i, 0,
449 /* Process the applications request after reply has been received */
450 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
451 silc_client_command_get_clients_list_callback,
454 silc_buffer_push(client_id_list, client_id_list->data -
455 client_id_list->head);
456 silc_buffer_free(res_cmd);
458 silc_free(res_argv_lens);
459 silc_free(res_argv_types);
463 silc_buffer_push(client_id_list, client_id_list->data -
464 client_id_list->head);
466 /* We have the clients in cache, get them and call the completion */
467 silc_client_command_get_clients_list_callback((void *)in, NULL);
470 /* Finds entry for client by the client's ID. Returns the entry or NULL
471 if the entry was not found. */
473 SilcClientEntry silc_client_get_client_by_id(SilcClient client,
474 SilcClientConnection conn,
475 SilcClientID *client_id)
477 SilcIDCacheEntry id_cache;
479 SILC_LOG_DEBUG(("Finding client by ID (%s)",
480 silc_id_render(client_id, SILC_ID_CLIENT)));
482 /* Find ID from cache */
483 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
485 silc_hash_client_id_compare, NULL,
489 SILC_LOG_DEBUG(("Found"));
491 return (SilcClientEntry)id_cache->context;
496 SilcClientConnection conn;
497 SilcClientID *client_id;
498 SilcGetClientCallback completion;
500 } *GetClientByIDInternal;
502 SILC_CLIENT_CMD_FUNC(get_client_by_id_callback)
504 GetClientByIDInternal i = (GetClientByIDInternal)context;
505 SilcClientEntry entry;
508 entry = silc_client_get_client_by_id(i->client, i->conn, i->client_id);
511 i->completion(i->client, i->conn, &entry, 1, i->context);
514 i->completion(i->client, i->conn, NULL, 0, i->context);
517 silc_free(i->client_id);
521 /* Same as above but will always resolve the information from the server.
522 Use this only if you know that you don't have the entry and the only
523 thing you know about the client is its ID. */
525 void silc_client_get_client_by_id_resolve(SilcClient client,
526 SilcClientConnection conn,
527 SilcClientID *client_id,
528 SilcGetClientCallback completion,
532 GetClientByIDInternal i = silc_calloc(1, sizeof(*i));
534 SILC_LOG_DEBUG(("Start"));
538 i->client_id = silc_id_dup(client_id, SILC_ID_CLIENT);
539 i->completion = completion;
540 i->context = context;
542 /* Register our own command reply for this command */
543 silc_client_command_register(client, SILC_COMMAND_WHOIS, NULL, NULL,
544 silc_client_command_reply_whois_i, 0,
547 /* Send the command */
548 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
549 silc_client_command_send(client, conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
550 1, 3, idp->data, idp->len);
551 silc_buffer_free(idp);
553 /* Add pending callback */
554 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
555 silc_client_command_get_client_by_id_callback,
560 /******************************************************************************
562 Client, Channel and Server entry manipulation
564 ******************************************************************************/
567 /* Creates new client entry and adds it to the ID cache. Returns pointer
571 silc_client_add_client(SilcClient client, SilcClientConnection conn,
572 char *nickname, char *username,
573 char *userinfo, SilcClientID *id, SilcUInt32 mode)
575 SilcClientEntry client_entry;
578 SILC_LOG_DEBUG(("Start"));
580 /* Save the client infos */
581 client_entry = silc_calloc(1, sizeof(*client_entry));
582 client_entry->id = id;
583 client_entry->valid = TRUE;
584 silc_parse_userfqdn(nickname, &nick, &client_entry->server);
585 silc_parse_userfqdn(username, &client_entry->username,
586 &client_entry->hostname);
588 client_entry->realname = strdup(userinfo);
589 client_entry->mode = mode;
591 client_entry->nickname = strdup(nick);
592 client_entry->channels = silc_hash_table_alloc(1, silc_hash_ptr, NULL, NULL,
593 NULL, NULL, NULL, TRUE);
595 /* Format the nickname */
596 silc_client_nickname_format(client, conn, client_entry);
598 /* Add client to cache, the non-formatted nickname is saved to cache */
599 if (!silc_idcache_add(conn->client_cache, nick, client_entry->id,
600 (void *)client_entry, 0, NULL)) {
601 silc_free(client_entry->nickname);
602 silc_free(client_entry->username);
603 silc_free(client_entry->hostname);
604 silc_free(client_entry->server);
605 silc_hash_table_free(client_entry->channels);
606 silc_free(client_entry);
613 /* Updates the `client_entry' with the new information sent as argument. */
615 void silc_client_update_client(SilcClient client,
616 SilcClientConnection conn,
617 SilcClientEntry client_entry,
618 const char *nickname,
619 const char *username,
620 const char *userinfo,
625 SILC_LOG_DEBUG(("Start"));
627 if (!client_entry->username && username)
628 silc_parse_userfqdn(username, &client_entry->username,
629 &client_entry->hostname);
630 if (!client_entry->realname && userinfo)
631 client_entry->realname = strdup(userinfo);
632 if (!client_entry->nickname && nickname) {
633 silc_parse_userfqdn(nickname, &nick, &client_entry->server);
634 client_entry->nickname = strdup(nick);
635 silc_client_nickname_format(client, conn, client_entry);
637 client_entry->mode = mode;
640 /* Remove the old cache entry and create a new one */
641 silc_idcache_del_by_context(conn->client_cache, client_entry);
642 silc_idcache_add(conn->client_cache, nick, client_entry->id,
643 client_entry, 0, NULL);
647 /* Deletes the client entry and frees all memory. */
649 void silc_client_del_client_entry(SilcClient client,
650 SilcClientConnection conn,
651 SilcClientEntry client_entry)
653 SILC_LOG_DEBUG(("Start"));
655 silc_free(client_entry->nickname);
656 silc_free(client_entry->username);
657 silc_free(client_entry->realname);
658 silc_free(client_entry->hostname);
659 silc_free(client_entry->server);
660 silc_free(client_entry->id);
661 silc_free(client_entry->fingerprint);
662 silc_hash_table_free(client_entry->channels);
663 if (client_entry->send_key)
664 silc_cipher_free(client_entry->send_key);
665 if (client_entry->receive_key)
666 silc_cipher_free(client_entry->receive_key);
667 silc_free(client_entry->key);
668 silc_client_ftp_session_free_client(conn, client_entry);
669 if (client_entry->ke)
670 silc_client_abort_key_agreement(client, conn, client_entry);
671 silc_free(client_entry);
674 /* Removes client from the cache by the client entry. */
676 bool silc_client_del_client(SilcClient client, SilcClientConnection conn,
677 SilcClientEntry client_entry)
679 bool ret = silc_idcache_del_by_context(conn->client_cache, client_entry);
681 /* Remove from channels */
682 silc_client_remove_from_channels(client, conn, client_entry);
684 /* Free the client entry data */
685 silc_client_del_client_entry(client, conn, client_entry);
690 /* Add new channel entry to the ID Cache */
692 SilcChannelEntry silc_client_add_channel(SilcClient client,
693 SilcClientConnection conn,
694 const char *channel_name,
696 SilcChannelID *channel_id)
698 SilcChannelEntry channel;
700 SILC_LOG_DEBUG(("Start"));
702 channel = silc_calloc(1, sizeof(*channel));
703 channel->channel_name = strdup(channel_name);
704 channel->id = channel_id;
705 channel->mode = mode;
706 channel->user_list = silc_hash_table_alloc(1, silc_hash_ptr, NULL, NULL,
707 NULL, NULL, NULL, TRUE);
709 /* Put it to the ID cache */
710 if (!silc_idcache_add(conn->channel_cache, channel->channel_name,
711 (void *)channel->id, (void *)channel, 0, NULL)) {
712 silc_free(channel->channel_name);
713 silc_hash_table_free(channel->user_list);
721 /* Foreach callbcak to free all users from the channel when deleting a
724 static void silc_client_del_channel_foreach(void *key, void *context,
727 SilcChannelUser chu = (SilcChannelUser)context;
729 SILC_LOG_DEBUG(("Start"));
731 /* Remove the context from the client's channel hash table as that
732 table and channel's user_list hash table share this same context. */
733 silc_hash_table_del(chu->client->channels, chu->channel);
737 /* Removes channel from the cache by the channel entry. */
739 bool silc_client_del_channel(SilcClient client, SilcClientConnection conn,
740 SilcChannelEntry channel)
742 bool ret = silc_idcache_del_by_context(conn->channel_cache, channel);
744 SILC_LOG_DEBUG(("Start"));
746 /* Free all client entrys from the users list. The silc_hash_table_free
747 will free all the entries so they are not freed at the foreach
749 silc_hash_table_foreach(channel->user_list, silc_client_del_channel_foreach,
751 silc_hash_table_free(channel->user_list);
753 silc_free(channel->channel_name);
754 silc_free(channel->id);
755 silc_free(channel->key);
756 if (channel->channel_key)
757 silc_cipher_free(channel->channel_key);
759 silc_hmac_free(channel->hmac);
760 if (channel->old_channel_key)
761 silc_cipher_free(channel->old_channel_key);
762 if (channel->old_hmac)
763 silc_hmac_free(channel->old_hmac);
764 if (channel->rekey_task)
765 silc_schedule_task_del(conn->client->schedule, channel->rekey_task);
766 silc_client_del_channel_private_keys(client, conn, channel);
771 /* Replaces the channel ID of the `channel' to `new_id'. Returns FALSE
772 if the ID could not be changed. */
774 bool silc_client_replace_channel_id(SilcClient client,
775 SilcClientConnection conn,
776 SilcChannelEntry channel,
777 SilcChannelID *new_id)
782 SILC_LOG_DEBUG(("Old Channel ID id(%s)",
783 silc_id_render(channel->id, SILC_ID_CHANNEL)));
784 SILC_LOG_DEBUG(("New Channel ID id(%s)",
785 silc_id_render(new_id, SILC_ID_CHANNEL)));
787 silc_idcache_del_by_id(conn->channel_cache, channel->id);
788 silc_free(channel->id);
789 channel->id = new_id;
790 return silc_idcache_add(conn->channel_cache, channel->channel_name,
791 (void *)channel->id, (void *)channel, 0, NULL);
795 /* Finds entry for channel by the channel name. Returns the entry or NULL
796 if the entry was not found. It is found only if the client is joined
799 SilcChannelEntry silc_client_get_channel(SilcClient client,
800 SilcClientConnection conn,
803 SilcIDCacheEntry id_cache;
804 SilcChannelEntry entry;
806 SILC_LOG_DEBUG(("Start"));
808 if (!silc_idcache_find_by_name_one(conn->channel_cache, channel,
812 entry = (SilcChannelEntry)id_cache->context;
814 SILC_LOG_DEBUG(("Found"));
819 /* Finds entry for channel by the channel ID. Returns the entry or NULL
820 if the entry was not found. It is found only if the client is joined
823 SilcChannelEntry silc_client_get_channel_by_id(SilcClient client,
824 SilcClientConnection conn,
825 SilcChannelID *channel_id)
827 SilcIDCacheEntry id_cache;
828 SilcChannelEntry entry;
830 SILC_LOG_DEBUG(("Start"));
832 if (!silc_idcache_find_by_id_one(conn->channel_cache, channel_id,
836 entry = (SilcChannelEntry)id_cache->context;
838 SILC_LOG_DEBUG(("Found"));
845 SilcClientConnection conn;
846 SilcChannelID *channel_id;
847 SilcGetChannelCallback completion;
849 } *GetChannelByIDInternal;
851 SILC_CLIENT_CMD_FUNC(get_channel_by_id_callback)
853 GetChannelByIDInternal i = (GetChannelByIDInternal)context;
854 SilcChannelEntry entry;
856 SILC_LOG_DEBUG(("Start"));
858 /* Get the channel */
859 entry = silc_client_get_channel_by_id(i->client, i->conn, i->channel_id);
861 i->completion(i->client, i->conn, &entry, 1, i->context);
863 i->completion(i->client, i->conn, NULL, 0, i->context);
866 silc_free(i->channel_id);
870 /* Resolves channel information from the server by the channel ID. */
872 void silc_client_get_channel_by_id_resolve(SilcClient client,
873 SilcClientConnection conn,
874 SilcChannelID *channel_id,
875 SilcGetChannelCallback completion,
879 GetChannelByIDInternal i = silc_calloc(1, sizeof(*i));
881 SILC_LOG_DEBUG(("Start"));
885 i->channel_id = silc_id_dup(channel_id, SILC_ID_CHANNEL);
886 i->completion = completion;
887 i->context = context;
889 /* Register our own command reply for this command */
890 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
891 silc_client_command_reply_identify_i, 0,
894 /* Send the command */
895 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
896 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
898 1, 5, idp->data, idp->len);
899 silc_buffer_free(idp);
901 /* Add pending callback */
902 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
903 silc_client_command_get_channel_by_id_callback,
907 /* Finds entry for server by the server name. */
909 SilcServerEntry silc_client_get_server(SilcClient client,
910 SilcClientConnection conn,
913 SilcIDCacheEntry id_cache;
914 SilcServerEntry entry;
916 SILC_LOG_DEBUG(("Start"));
918 if (!silc_idcache_find_by_name_one(conn->server_cache, server_name,
922 entry = (SilcServerEntry)id_cache->context;
927 /* Finds entry for server by the server ID. */
929 SilcServerEntry silc_client_get_server_by_id(SilcClient client,
930 SilcClientConnection conn,
931 SilcServerID *server_id)
933 SilcIDCacheEntry id_cache;
934 SilcServerEntry entry;
936 SILC_LOG_DEBUG(("Start"));
938 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
942 entry = (SilcServerEntry)id_cache->context;
947 /* Add new server entry */
949 SilcServerEntry silc_client_add_server(SilcClient client,
950 SilcClientConnection conn,
951 const char *server_name,
952 const char *server_info,
953 SilcServerID *server_id)
955 SilcServerEntry server_entry;
957 server_entry = silc_calloc(1, sizeof(*server_entry));
958 if (!server_entry || !server_id)
961 server_entry->server_id = server_id;
963 server_entry->server_name = strdup(server_name);
965 server_entry->server_info = strdup(server_info);
967 /* Add server to cache */
968 if (!silc_idcache_add(conn->server_cache, server_entry->server_name,
969 server_entry->server_id, server_entry, 0, NULL)) {
970 silc_free(server_entry->server_id);
971 silc_free(server_entry->server_name);
972 silc_free(server_entry->server_info);
973 silc_free(server_entry);
980 /* Removes server from the cache by the server entry. */
982 bool silc_client_del_server(SilcClient client, SilcClientConnection conn,
983 SilcServerEntry server)
985 bool ret = silc_idcache_del_by_context(conn->server_cache, server);
986 silc_free(server->server_name);
987 silc_free(server->server_info);
988 silc_free(server->server_id);
993 /* Formats the nickname of the client specified by the `client_entry'.
994 If the format is specified by the application this will format the
995 nickname and replace the old nickname in the client entry. If the
996 format string is not specified then this function has no effect. */
998 void silc_client_nickname_format(SilcClient client,
999 SilcClientConnection conn,
1000 SilcClientEntry client_entry)
1003 char *newnick = NULL;
1004 int i, off = 0, len;
1006 SilcClientEntry *clients;
1007 SilcUInt32 clients_count = 0;
1008 SilcClientEntry unformatted = NULL;
1010 SILC_LOG_DEBUG(("Start"));
1012 if (!client->internal->params->nickname_format[0])
1015 if (!client_entry->nickname)
1018 /* Get all clients with same nickname. Do not perform the formatting
1019 if there aren't any clients with same nickname unless the application
1020 is forcing us to do so. */
1021 clients = silc_client_get_clients_local(client, conn,
1022 client_entry->nickname, NULL,
1024 if (!clients && !client->internal->params->nickname_force_format)
1029 for (i = 0; i < clients_count; i++) {
1030 if (clients[i]->valid && clients[i] != client_entry)
1032 if (clients[i]->valid && clients[i] != client_entry &&
1033 !strcmp(clients[i]->nickname, client_entry->nickname))
1036 if (!len || freebase)
1039 cp = client->internal->params->nickname_format;
1049 if (!client_entry->nickname)
1051 len = strlen(client_entry->nickname);
1052 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1053 memcpy(&newnick[off], client_entry->nickname, len);
1057 /* Stripped hostname */
1058 if (!client_entry->hostname)
1060 len = strcspn(client_entry->hostname, ".");
1061 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1062 memcpy(&newnick[off], client_entry->hostname, len);
1067 if (!client_entry->hostname)
1069 len = strlen(client_entry->hostname);
1070 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1071 memcpy(&newnick[off], client_entry->hostname, len);
1075 /* Stripped server name */
1076 if (!client_entry->server)
1078 len = strcspn(client_entry->server, ".");
1079 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1080 memcpy(&newnick[off], client_entry->server, len);
1084 /* Full server name */
1085 if (!client_entry->server)
1087 len = strlen(client_entry->server);
1088 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1089 memcpy(&newnick[off], client_entry->server, len);
1093 /* Ascending number */
1098 if (clients_count == 1) {
1099 unformatted = clients[0];
1103 for (i = 0; i < clients_count; i++) {
1104 if (!strncasecmp(clients[i]->nickname, client_entry->nickname,
1105 strlen(clients[i]->nickname)))
1106 unformatted = clients[i];
1107 if (strncasecmp(clients[i]->nickname, newnick, off))
1109 if (strlen(clients[i]->nickname) <= off)
1111 num = atoi(&clients[i]->nickname[off]);
1116 memset(tmp, 0, sizeof(tmp));
1117 snprintf(tmp, sizeof(tmp) - 1, "%d", ++max);
1119 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1120 memcpy(&newnick[off], tmp, len);
1125 /* Some other character in the string */
1126 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
1127 memcpy(&newnick[off], cp, 1);
1135 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
1138 /* If we are changing nickname of our local entry we'll enforce
1139 that we will always get the unformatted nickname. Give our
1140 format number to the one that is not formatted now. */
1141 if (unformatted && client_entry == conn->local_entry)
1142 client_entry = unformatted;
1144 silc_free(client_entry->nickname);
1145 client_entry->nickname = newnick;