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;
291 } *GetClientsByListInternal;
293 SILC_CLIENT_CMD_FUNC(get_clients_list_callback)
295 GetClientsByListInternal i = (GetClientsByListInternal)context;
296 SilcIDCacheEntry id_cache = NULL;
297 SilcBuffer client_id_list = i->client_id_list;
298 SilcClientEntry *clients = NULL;
299 SilcUInt32 clients_count = 0;
303 SILC_LOG_DEBUG(("Start"));
311 SILC_LOG_DEBUG(("Resolved all clients"));
313 for (c = 0; c < i->list_count; c++) {
315 SilcClientID *client_id;
318 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
320 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
322 silc_buffer_pull(client_id_list, idp_len);
326 /* Get the client entry */
327 if (silc_idcache_find_by_id_one_ext(i->conn->client_cache,
330 silc_hash_client_id_compare, NULL,
332 clients = silc_realloc(clients, sizeof(*clients) *
333 (clients_count + 1));
334 clients[clients_count] = (SilcClientEntry)id_cache->context;
339 silc_free(client_id);
340 silc_buffer_pull(client_id_list, idp_len);
344 i->completion(i->client, i->conn, clients, clients_count, i->context);
347 i->completion(i->client, i->conn, NULL, 0, i->context);
350 if (i->client_id_list)
351 silc_buffer_free(i->client_id_list);
355 /* Gets client entries by the list of client ID's `client_id_list'. This
356 always resolves those client ID's it does not know yet from the server
357 so this function might take a while. The `client_id_list' is a list
358 of ID Payloads added one after other. JOIN command reply and USERS
359 command reply for example returns this sort of list. The `completion'
360 will be called after the entries are available. */
362 void silc_client_get_clients_by_list(SilcClient client,
363 SilcClientConnection conn,
364 SilcUInt32 list_count,
365 SilcBuffer client_id_list,
366 SilcGetClientCallback completion,
369 SilcIDCacheEntry id_cache = NULL;
371 unsigned char **res_argv = NULL;
372 SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
373 GetClientsByListInternal in;
374 bool wait_res = FALSE;
376 SILC_LOG_DEBUG(("Start"));
378 in = silc_calloc(1, sizeof(*in));
381 in->list_count = list_count;
382 in->client_id_list = silc_buffer_copy(client_id_list);
383 in->completion = completion;
384 in->context = context;
386 for (i = 0; i < list_count; i++) {
388 SilcClientID *client_id;
389 SilcClientEntry entry;
393 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
395 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
397 silc_buffer_pull(client_id_list, idp_len);
401 /* Check if we have this client cached already. */
403 silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
405 silc_hash_client_id_compare, NULL,
408 /* If we don't have the entry or it has incomplete info, then resolve
409 it from the server. */
410 if (!ret || !((SilcClientEntry)id_cache->context)->nickname) {
411 entry = ret ? (SilcClientEntry)id_cache->context : NULL;
414 if (entry->status & SILC_CLIENT_STATUS_RESOLVING) {
415 /* Attach to this resolving and wait until it finishes */
416 silc_client_command_pending(
417 conn, SILC_COMMAND_NONE,
418 entry->resolve_cmd_ident,
419 silc_client_command_get_clients_list_callback,
424 silc_free(client_id);
425 silc_buffer_pull(client_id_list, idp_len);
429 entry->status |= SILC_CLIENT_STATUS_RESOLVING;
430 entry->resolve_cmd_ident = conn->cmd_ident + 1;
433 /* No we don't have it, query it from the server. Assemble argument
434 table that will be sent for the IDENTIFY command later. */
435 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
437 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
439 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
441 res_argv[res_argc] = client_id_list->data;
442 res_argv_lens[res_argc] = idp_len;
443 res_argv_types[res_argc] = res_argc + 5;
447 silc_free(client_id);
448 silc_buffer_pull(client_id_list, idp_len);
451 silc_buffer_push(client_id_list, client_id_list->data -
452 client_id_list->head);
454 /* Query the client information from server if the list included clients
455 that we don't know about. */
459 /* Send the IDENTIFY command to server */
460 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
461 res_argc, res_argv, res_argv_lens,
462 res_argv_types, ++conn->cmd_ident);
463 silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
464 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
467 /* Register our own command reply for this command */
468 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
469 silc_client_command_reply_identify_i, 0,
472 /* Process the applications request after reply has been received */
473 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
474 silc_client_command_get_clients_list_callback,
478 silc_buffer_free(res_cmd);
480 silc_free(res_argv_lens);
481 silc_free(res_argv_types);
488 /* We have the clients in cache, get them and call the completion */
489 silc_client_command_get_clients_list_callback((void *)in, NULL);
492 /* Finds entry for client by the client's ID. Returns the entry or NULL
493 if the entry was not found. */
495 SilcClientEntry silc_client_get_client_by_id(SilcClient client,
496 SilcClientConnection conn,
497 SilcClientID *client_id)
499 SilcIDCacheEntry id_cache;
501 SILC_LOG_DEBUG(("Finding client by ID (%s)",
502 silc_id_render(client_id, SILC_ID_CLIENT)));
504 /* Find ID from cache */
505 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
507 silc_hash_client_id_compare, NULL,
511 SILC_LOG_DEBUG(("Found"));
513 return (SilcClientEntry)id_cache->context;
518 SilcClientConnection conn;
519 SilcClientID *client_id;
520 SilcGetClientCallback completion;
522 } *GetClientByIDInternal;
524 SILC_CLIENT_CMD_FUNC(get_client_by_id_callback)
526 GetClientByIDInternal i = (GetClientByIDInternal)context;
527 SilcClientEntry entry;
530 entry = silc_client_get_client_by_id(i->client, i->conn, i->client_id);
533 i->completion(i->client, i->conn, &entry, 1, i->context);
536 i->completion(i->client, i->conn, NULL, 0, i->context);
539 silc_free(i->client_id);
543 /* Same as above but will always resolve the information from the server.
544 Use this only if you know that you don't have the entry and the only
545 thing you know about the client is its ID. */
547 void silc_client_get_client_by_id_resolve(SilcClient client,
548 SilcClientConnection conn,
549 SilcClientID *client_id,
550 SilcBuffer attributes,
551 SilcGetClientCallback completion,
555 GetClientByIDInternal i = silc_calloc(1, sizeof(*i));
557 SILC_LOG_DEBUG(("Start"));
561 i->client_id = silc_id_dup(client_id, SILC_ID_CLIENT);
562 i->completion = completion;
563 i->context = context;
565 /* Register our own command reply for this command */
566 silc_client_command_register(client, SILC_COMMAND_WHOIS, NULL, NULL,
567 silc_client_command_reply_whois_i, 0,
570 /* Send the command */
571 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
572 silc_client_command_send(client, conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
573 2, 3, attributes ? attributes->data : NULL,
574 attributes ? attributes->len : 0,
575 4, idp->data, idp->len);
576 silc_buffer_free(idp);
578 /* Add pending callback */
579 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
580 silc_client_command_get_client_by_id_callback,
585 /******************************************************************************
587 Client, Channel and Server entry manipulation
589 ******************************************************************************/
592 /* Creates new client entry and adds it to the ID cache. Returns pointer
596 silc_client_add_client(SilcClient client, SilcClientConnection conn,
597 char *nickname, char *username,
598 char *userinfo, SilcClientID *id, SilcUInt32 mode)
600 SilcClientEntry client_entry;
603 SILC_LOG_DEBUG(("Start"));
605 /* Save the client infos */
606 client_entry = silc_calloc(1, sizeof(*client_entry));
607 client_entry->id = id;
608 client_entry->valid = TRUE;
609 silc_parse_userfqdn(nickname, &nick, &client_entry->server);
610 silc_parse_userfqdn(username, &client_entry->username,
611 &client_entry->hostname);
613 client_entry->realname = strdup(userinfo);
614 client_entry->mode = mode;
616 client_entry->nickname = strdup(nick);
617 client_entry->channels = silc_hash_table_alloc(1, silc_hash_ptr, NULL, NULL,
618 NULL, NULL, NULL, TRUE);
620 /* Format the nickname */
621 silc_client_nickname_format(client, conn, client_entry);
623 /* Add client to cache, the non-formatted nickname is saved to cache */
624 if (!silc_idcache_add(conn->client_cache, nick, client_entry->id,
625 (void *)client_entry, 0, NULL)) {
626 silc_free(client_entry->nickname);
627 silc_free(client_entry->username);
628 silc_free(client_entry->hostname);
629 silc_free(client_entry->server);
630 silc_hash_table_free(client_entry->channels);
631 silc_free(client_entry);
638 /* Updates the `client_entry' with the new information sent as argument. */
640 void silc_client_update_client(SilcClient client,
641 SilcClientConnection conn,
642 SilcClientEntry client_entry,
643 const char *nickname,
644 const char *username,
645 const char *userinfo,
650 SILC_LOG_DEBUG(("Start"));
652 if ((!client_entry->username || !client_entry->hostname) && username) {
653 silc_free(client_entry->username);
654 silc_free(client_entry->hostname);
655 client_entry->username = NULL;
656 client_entry->hostname = NULL;
657 silc_parse_userfqdn(username, &client_entry->username,
658 &client_entry->hostname);
660 if (!client_entry->realname && userinfo)
661 client_entry->realname = strdup(userinfo);
662 if (!client_entry->nickname && nickname) {
663 silc_parse_userfqdn(nickname, &nick, &client_entry->server);
664 client_entry->nickname = strdup(nick);
665 silc_client_nickname_format(client, conn, client_entry);
667 client_entry->mode = mode;
670 /* Remove the old cache entry and create a new one */
671 silc_idcache_del_by_context(conn->client_cache, client_entry);
672 silc_idcache_add(conn->client_cache, nick, client_entry->id,
673 client_entry, 0, NULL);
677 /* Deletes the client entry and frees all memory. */
679 void silc_client_del_client_entry(SilcClient client,
680 SilcClientConnection conn,
681 SilcClientEntry client_entry)
683 SILC_LOG_DEBUG(("Start"));
685 silc_free(client_entry->nickname);
686 silc_free(client_entry->username);
687 silc_free(client_entry->realname);
688 silc_free(client_entry->hostname);
689 silc_free(client_entry->server);
690 silc_free(client_entry->id);
691 silc_free(client_entry->fingerprint);
692 silc_hash_table_free(client_entry->channels);
693 if (client_entry->send_key)
694 silc_cipher_free(client_entry->send_key);
695 if (client_entry->receive_key)
696 silc_cipher_free(client_entry->receive_key);
697 silc_free(client_entry->key);
698 silc_client_ftp_session_free_client(conn, client_entry);
699 if (client_entry->ke)
700 silc_client_abort_key_agreement(client, conn, client_entry);
701 silc_free(client_entry);
704 /* Removes client from the cache by the client entry. */
706 bool silc_client_del_client(SilcClient client, SilcClientConnection conn,
707 SilcClientEntry client_entry)
709 bool ret = silc_idcache_del_by_context(conn->client_cache, client_entry);
711 /* Remove from channels */
712 silc_client_remove_from_channels(client, conn, client_entry);
714 /* Free the client entry data */
715 silc_client_del_client_entry(client, conn, client_entry);
720 /* Add new channel entry to the ID Cache */
722 SilcChannelEntry silc_client_add_channel(SilcClient client,
723 SilcClientConnection conn,
724 const char *channel_name,
726 SilcChannelID *channel_id)
728 SilcChannelEntry channel;
730 SILC_LOG_DEBUG(("Start"));
732 channel = silc_calloc(1, sizeof(*channel));
733 channel->channel_name = strdup(channel_name);
734 channel->id = channel_id;
735 channel->mode = mode;
736 channel->user_list = silc_hash_table_alloc(1, silc_hash_ptr, NULL, NULL,
737 NULL, NULL, NULL, TRUE);
739 /* Put it to the ID cache */
740 if (!silc_idcache_add(conn->channel_cache, channel->channel_name,
741 (void *)channel->id, (void *)channel, 0, NULL)) {
742 silc_free(channel->channel_name);
743 silc_hash_table_free(channel->user_list);
751 /* Foreach callbcak to free all users from the channel when deleting a
754 static void silc_client_del_channel_foreach(void *key, void *context,
757 SilcChannelUser chu = (SilcChannelUser)context;
759 SILC_LOG_DEBUG(("Start"));
761 /* Remove the context from the client's channel hash table as that
762 table and channel's user_list hash table share this same context. */
763 silc_hash_table_del(chu->client->channels, chu->channel);
767 /* Removes channel from the cache by the channel entry. */
769 bool silc_client_del_channel(SilcClient client, SilcClientConnection conn,
770 SilcChannelEntry channel)
772 bool ret = silc_idcache_del_by_context(conn->channel_cache, channel);
774 SILC_LOG_DEBUG(("Start"));
776 /* Free all client entrys from the users list. The silc_hash_table_free
777 will free all the entries so they are not freed at the foreach
779 silc_hash_table_foreach(channel->user_list, silc_client_del_channel_foreach,
781 silc_hash_table_free(channel->user_list);
783 silc_free(channel->channel_name);
784 silc_free(channel->id);
785 silc_free(channel->key);
786 if (channel->channel_key)
787 silc_cipher_free(channel->channel_key);
789 silc_hmac_free(channel->hmac);
790 if (channel->old_channel_key)
791 silc_cipher_free(channel->old_channel_key);
792 if (channel->old_hmac)
793 silc_hmac_free(channel->old_hmac);
794 if (channel->rekey_task)
795 silc_schedule_task_del(conn->client->schedule, channel->rekey_task);
796 silc_client_del_channel_private_keys(client, conn, channel);
801 /* Replaces the channel ID of the `channel' to `new_id'. Returns FALSE
802 if the ID could not be changed. */
804 bool silc_client_replace_channel_id(SilcClient client,
805 SilcClientConnection conn,
806 SilcChannelEntry channel,
807 SilcChannelID *new_id)
812 SILC_LOG_DEBUG(("Old Channel ID id(%s)",
813 silc_id_render(channel->id, SILC_ID_CHANNEL)));
814 SILC_LOG_DEBUG(("New Channel ID id(%s)",
815 silc_id_render(new_id, SILC_ID_CHANNEL)));
817 silc_idcache_del_by_id(conn->channel_cache, channel->id);
818 silc_free(channel->id);
819 channel->id = new_id;
820 return silc_idcache_add(conn->channel_cache, channel->channel_name,
821 (void *)channel->id, (void *)channel, 0, NULL);
825 /* Finds entry for channel by the channel name. Returns the entry or NULL
826 if the entry was not found. It is found only if the client is joined
829 SilcChannelEntry silc_client_get_channel(SilcClient client,
830 SilcClientConnection conn,
833 SilcIDCacheEntry id_cache;
834 SilcChannelEntry entry;
836 SILC_LOG_DEBUG(("Start"));
838 if (!silc_idcache_find_by_name_one(conn->channel_cache, channel,
842 entry = (SilcChannelEntry)id_cache->context;
844 SILC_LOG_DEBUG(("Found"));
849 /* Finds entry for channel by the channel ID. Returns the entry or NULL
850 if the entry was not found. It is found only if the client is joined
853 SilcChannelEntry silc_client_get_channel_by_id(SilcClient client,
854 SilcClientConnection conn,
855 SilcChannelID *channel_id)
857 SilcIDCacheEntry id_cache;
858 SilcChannelEntry entry;
860 SILC_LOG_DEBUG(("Start"));
862 if (!silc_idcache_find_by_id_one(conn->channel_cache, channel_id,
866 entry = (SilcChannelEntry)id_cache->context;
868 SILC_LOG_DEBUG(("Found"));
875 SilcClientConnection conn;
876 SilcChannelID *channel_id;
877 SilcGetChannelCallback completion;
879 } *GetChannelByIDInternal;
881 SILC_CLIENT_CMD_FUNC(get_channel_by_id_callback)
883 GetChannelByIDInternal i = (GetChannelByIDInternal)context;
884 SilcChannelEntry entry;
886 SILC_LOG_DEBUG(("Start"));
888 /* Get the channel */
889 entry = silc_client_get_channel_by_id(i->client, i->conn, i->channel_id);
891 i->completion(i->client, i->conn, &entry, 1, i->context);
893 i->completion(i->client, i->conn, NULL, 0, i->context);
896 silc_free(i->channel_id);
900 /* Resolves channel information from the server by the channel ID. */
902 void silc_client_get_channel_by_id_resolve(SilcClient client,
903 SilcClientConnection conn,
904 SilcChannelID *channel_id,
905 SilcGetChannelCallback completion,
909 GetChannelByIDInternal i = silc_calloc(1, sizeof(*i));
911 SILC_LOG_DEBUG(("Start"));
915 i->channel_id = silc_id_dup(channel_id, SILC_ID_CHANNEL);
916 i->completion = completion;
917 i->context = context;
919 /* Register our own command reply for this command */
920 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
921 silc_client_command_reply_identify_i, 0,
924 /* Send the command */
925 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
926 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
928 1, 5, idp->data, idp->len);
929 silc_buffer_free(idp);
931 /* Add pending callback */
932 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
933 silc_client_command_get_channel_by_id_callback,
937 /* Finds entry for server by the server name. */
939 SilcServerEntry silc_client_get_server(SilcClient client,
940 SilcClientConnection conn,
943 SilcIDCacheEntry id_cache;
944 SilcServerEntry entry;
946 SILC_LOG_DEBUG(("Start"));
948 if (!silc_idcache_find_by_name_one(conn->server_cache, server_name,
952 entry = (SilcServerEntry)id_cache->context;
957 /* Finds entry for server by the server ID. */
959 SilcServerEntry silc_client_get_server_by_id(SilcClient client,
960 SilcClientConnection conn,
961 SilcServerID *server_id)
963 SilcIDCacheEntry id_cache;
964 SilcServerEntry entry;
966 SILC_LOG_DEBUG(("Start"));
968 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
972 entry = (SilcServerEntry)id_cache->context;
977 /* Add new server entry */
979 SilcServerEntry silc_client_add_server(SilcClient client,
980 SilcClientConnection conn,
981 const char *server_name,
982 const char *server_info,
983 SilcServerID *server_id)
985 SilcServerEntry server_entry;
987 SILC_LOG_DEBUG(("Start"));
989 server_entry = silc_calloc(1, sizeof(*server_entry));
990 if (!server_entry || !server_id)
993 server_entry->server_id = server_id;
995 server_entry->server_name = strdup(server_name);
997 server_entry->server_info = strdup(server_info);
999 /* Add server to cache */
1000 if (!silc_idcache_add(conn->server_cache, server_entry->server_name,
1001 server_entry->server_id, server_entry, 0, NULL)) {
1002 silc_free(server_entry->server_id);
1003 silc_free(server_entry->server_name);
1004 silc_free(server_entry->server_info);
1005 silc_free(server_entry);
1009 return server_entry;
1012 /* Removes server from the cache by the server entry. */
1014 bool silc_client_del_server(SilcClient client, SilcClientConnection conn,
1015 SilcServerEntry server)
1017 bool ret = silc_idcache_del_by_context(conn->server_cache, server);
1018 silc_free(server->server_name);
1019 silc_free(server->server_info);
1020 silc_free(server->server_id);
1025 /* Updates the `server_entry' with the new information sent as argument. */
1027 void silc_client_update_server(SilcClient client,
1028 SilcClientConnection conn,
1029 SilcServerEntry server_entry,
1030 const char *server_name,
1031 const char *server_info)
1033 SILC_LOG_DEBUG(("Start"));
1035 if (server_name && (!server_entry->server_name ||
1036 strcmp(server_entry->server_name, server_name))) {
1038 silc_idcache_del_by_context(conn->server_cache, server_entry);
1039 silc_free(server_entry->server_name);
1040 server_entry->server_name = strdup(server_name);
1041 silc_idcache_add(conn->server_cache, server_entry->server_name,
1042 server_entry->server_id,
1043 server_entry, 0, NULL);
1046 if (server_info && (!server_entry->server_info ||
1047 strcmp(server_entry->server_info, server_info))) {
1048 silc_free(server_entry->server_info);
1049 server_entry->server_info = strdup(server_info);
1053 /* Formats the nickname of the client specified by the `client_entry'.
1054 If the format is specified by the application this will format the
1055 nickname and replace the old nickname in the client entry. If the
1056 format string is not specified then this function has no effect. */
1058 void silc_client_nickname_format(SilcClient client,
1059 SilcClientConnection conn,
1060 SilcClientEntry client_entry)
1063 char *newnick = NULL;
1064 int i, off = 0, len;
1066 SilcClientEntry *clients;
1067 SilcUInt32 clients_count = 0;
1068 SilcClientEntry unformatted = NULL;
1070 SILC_LOG_DEBUG(("Start"));
1072 if (!client->internal->params->nickname_format[0])
1075 if (!client_entry->nickname)
1078 /* Get all clients with same nickname. Do not perform the formatting
1079 if there aren't any clients with same nickname unless the application
1080 is forcing us to do so. */
1081 clients = silc_client_get_clients_local(client, conn,
1082 client_entry->nickname, NULL,
1084 if (!clients && !client->internal->params->nickname_force_format)
1089 for (i = 0; i < clients_count; i++) {
1090 if (clients[i]->valid && clients[i] != client_entry)
1092 if (clients[i]->valid && clients[i] != client_entry &&
1093 !strcmp(clients[i]->nickname, client_entry->nickname))
1096 if (!len || freebase)
1099 cp = client->internal->params->nickname_format;
1109 if (!client_entry->nickname)
1111 len = strlen(client_entry->nickname);
1112 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1113 memcpy(&newnick[off], client_entry->nickname, len);
1117 /* Stripped hostname */
1118 if (!client_entry->hostname)
1120 len = strcspn(client_entry->hostname, ".");
1121 i = strcspn(client_entry->hostname, "-");
1124 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1125 memcpy(&newnick[off], client_entry->hostname, len);
1130 if (!client_entry->hostname)
1132 len = strlen(client_entry->hostname);
1133 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1134 memcpy(&newnick[off], client_entry->hostname, len);
1138 /* Stripped server name */
1139 if (!client_entry->server)
1141 len = strcspn(client_entry->server, ".");
1142 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1143 memcpy(&newnick[off], client_entry->server, len);
1147 /* Full server name */
1148 if (!client_entry->server)
1150 len = strlen(client_entry->server);
1151 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1152 memcpy(&newnick[off], client_entry->server, len);
1156 /* Ascending number */
1161 if (clients_count == 1) {
1162 unformatted = clients[0];
1166 for (i = 0; i < clients_count; i++) {
1167 if (!strncasecmp(clients[i]->nickname, client_entry->nickname,
1168 strlen(clients[i]->nickname)))
1169 unformatted = clients[i];
1170 if (strncasecmp(clients[i]->nickname, newnick, off))
1172 if (strlen(clients[i]->nickname) <= off)
1174 num = atoi(&clients[i]->nickname[off]);
1179 memset(tmp, 0, sizeof(tmp));
1180 snprintf(tmp, sizeof(tmp) - 1, "%d", ++max);
1182 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1183 memcpy(&newnick[off], tmp, len);
1188 /* Some other character in the string */
1189 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
1190 memcpy(&newnick[off], cp, 1);
1198 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
1201 /* If we are changing nickname of our local entry we'll enforce
1202 that we will always get the unformatted nickname. Give our
1203 format number to the one that is not formatted now. */
1204 if (unformatted && client_entry == conn->local_entry)
1205 client_entry = unformatted;
1207 silc_free(client_entry->nickname);
1208 client_entry->nickname = newnick;