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,
167 i = silc_calloc(1, sizeof(*i));
170 i->nickname = strdup(nickname);
171 i->server = server ? strdup(server) : NULL;
172 i->completion = completion;
173 i->context = context;
175 if (nickname && server) {
176 len = strlen(nickname) + strlen(server) + 3;
177 userhost = silc_calloc(len, sizeof(*userhost));
178 silc_strncat(userhost, len, nickname, strlen(nickname));
179 silc_strncat(userhost, len, "@", 1);
180 silc_strncat(userhost, len, server, strlen(server));
182 userhost = silc_memdup(nickname, strlen(nickname));
185 /* Register our own command reply for this command */
186 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
187 silc_client_command_reply_identify_i, 0,
190 /* Send the command */
191 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
192 conn->cmd_ident, 1, 1, userhost,
195 /* Add pending callback */
196 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
197 silc_client_command_get_client_callback,
203 /* The old style function to find client entry. This is used by the
204 library internally. If `query' is TRUE then the client information is
205 requested by the server. The pending command callback must be set
207 /* XXX This function should be removed */
209 SilcClientEntry silc_idlist_get_client(SilcClient client,
210 SilcClientConnection conn,
211 const char *nickname,
215 SilcIDCacheEntry id_cache;
216 SilcIDCacheList list = NULL;
217 SilcClientEntry entry = NULL;
219 SILC_LOG_DEBUG(("Start"));
221 /* Find ID from cache */
222 if (!silc_idcache_find_by_name(conn->client_cache, (char *)nickname,
227 SILC_LOG_DEBUG(("Requesting Client ID from server"));
229 /* Register our own command reply for this command */
230 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
231 silc_client_command_reply_identify_i, 0,
234 /* Send the command */
235 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
236 conn->cmd_ident, 1, 1, nickname,
240 silc_idcache_list_free(list);
248 /* Take first found cache entry */
249 if (!silc_idcache_list_first(list, &id_cache))
252 entry = (SilcClientEntry)id_cache->context;
254 /* Check multiple cache entries for match */
255 silc_idcache_list_first(list, &id_cache);
257 entry = (SilcClientEntry)id_cache->context;
259 if (strcasecmp(entry->nickname, format)) {
260 if (!silc_idcache_list_next(list, &id_cache)) {
272 /* If match weren't found, request it */
278 silc_idcache_list_free(list);
286 SilcClientConnection conn;
287 SilcUInt32 list_count;
288 SilcBuffer client_id_list;
289 SilcGetClientCallback completion;
292 } *GetClientsByListInternal;
294 SILC_CLIENT_CMD_FUNC(get_clients_list_callback)
296 GetClientsByListInternal i = (GetClientsByListInternal)context;
297 SilcIDCacheEntry id_cache = NULL;
298 SilcBuffer client_id_list = i->client_id_list;
299 SilcClientEntry *clients = NULL;
300 SilcUInt32 clients_count = 0;
304 SILC_LOG_DEBUG(("Start"));
312 SILC_LOG_DEBUG(("Resolved all clients"));
314 for (c = 0; c < i->list_count; c++) {
316 SilcClientID *client_id;
319 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
321 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
323 silc_buffer_pull(client_id_list, idp_len);
327 /* Get the client entry */
328 if (silc_idcache_find_by_id_one_ext(i->conn->client_cache,
331 silc_hash_client_id_compare, NULL,
333 clients = silc_realloc(clients, sizeof(*clients) *
334 (clients_count + 1));
335 clients[clients_count] = (SilcClientEntry)id_cache->context;
340 silc_free(client_id);
341 silc_buffer_pull(client_id_list, idp_len);
345 i->completion(i->client, i->conn, clients, clients_count, i->context);
348 i->completion(i->client, i->conn, NULL, 0, i->context);
351 if (i->client_id_list)
352 silc_buffer_free(i->client_id_list);
356 /* Gets client entries by the list of client ID's `client_id_list'. This
357 always resolves those client ID's it does not know yet from the server
358 so this function might take a while. The `client_id_list' is a list
359 of ID Payloads added one after other. JOIN command reply and USERS
360 command reply for example returns this sort of list. The `completion'
361 will be called after the entries are available. */
363 void silc_client_get_clients_by_list(SilcClient client,
364 SilcClientConnection conn,
365 SilcUInt32 list_count,
366 SilcBuffer client_id_list,
367 SilcGetClientCallback completion,
370 SilcIDCacheEntry id_cache = NULL;
372 unsigned char **res_argv = NULL;
373 SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
374 GetClientsByListInternal in;
375 bool wait_res = FALSE;
377 SILC_LOG_DEBUG(("Start"));
379 in = silc_calloc(1, sizeof(*in));
382 in->list_count = list_count;
383 in->client_id_list = silc_buffer_copy(client_id_list);
384 in->completion = completion;
385 in->context = context;
387 for (i = 0; i < list_count; i++) {
389 SilcClientID *client_id;
390 SilcClientEntry entry;
394 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
396 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
398 silc_buffer_pull(client_id_list, idp_len);
402 /* Check if we have this client cached already. */
404 silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
406 silc_hash_client_id_compare, NULL,
409 /* If we don't have the entry or it has incomplete info, then resolve
410 it from the server. */
411 if (!ret || !((SilcClientEntry)id_cache->context)->nickname) {
412 entry = ret ? (SilcClientEntry)id_cache->context : NULL;
415 if (entry->status & SILC_CLIENT_STATUS_RESOLVING) {
416 /* Attach to this resolving and wait until it finishes */
417 silc_client_command_pending(
418 conn, SILC_COMMAND_NONE,
419 entry->resolve_cmd_ident,
420 silc_client_command_get_clients_list_callback,
425 silc_free(client_id);
426 silc_buffer_pull(client_id_list, idp_len);
430 entry->status |= SILC_CLIENT_STATUS_RESOLVING;
431 entry->resolve_cmd_ident = conn->cmd_ident + 1;
434 /* No we don't have it, query it from the server. Assemble argument
435 table that will be sent for the IDENTIFY command later. */
436 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
438 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
440 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
442 res_argv[res_argc] = client_id_list->data;
443 res_argv_lens[res_argc] = idp_len;
444 res_argv_types[res_argc] = res_argc + 5;
448 silc_free(client_id);
449 silc_buffer_pull(client_id_list, idp_len);
452 silc_buffer_push(client_id_list, client_id_list->data -
453 client_id_list->head);
455 /* Query the client information from server if the list included clients
456 that we don't know about. */
460 /* Send the IDENTIFY command to server */
461 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
462 res_argc, res_argv, res_argv_lens,
463 res_argv_types, ++conn->cmd_ident);
464 silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
465 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
468 /* Register our own command reply for this command */
469 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
470 silc_client_command_reply_identify_i, 0,
473 /* Process the applications request after reply has been received */
474 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
475 silc_client_command_get_clients_list_callback,
479 silc_buffer_free(res_cmd);
481 silc_free(res_argv_lens);
482 silc_free(res_argv_types);
489 /* We have the clients in cache, get them and call the completion */
490 silc_client_command_get_clients_list_callback((void *)in, NULL);
493 /* Finds entry for client by the client's ID. Returns the entry or NULL
494 if the entry was not found. */
496 SilcClientEntry silc_client_get_client_by_id(SilcClient client,
497 SilcClientConnection conn,
498 SilcClientID *client_id)
500 SilcIDCacheEntry id_cache;
502 SILC_LOG_DEBUG(("Finding client by ID (%s)",
503 silc_id_render(client_id, SILC_ID_CLIENT)));
505 /* Find ID from cache */
506 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
508 silc_hash_client_id_compare, NULL,
512 SILC_LOG_DEBUG(("Found"));
514 return (SilcClientEntry)id_cache->context;
519 SilcClientConnection conn;
520 SilcClientID *client_id;
521 SilcGetClientCallback completion;
523 } *GetClientByIDInternal;
525 SILC_CLIENT_CMD_FUNC(get_client_by_id_callback)
527 GetClientByIDInternal i = (GetClientByIDInternal)context;
528 SilcClientEntry entry;
531 entry = silc_client_get_client_by_id(i->client, i->conn, i->client_id);
534 i->completion(i->client, i->conn, &entry, 1, i->context);
537 i->completion(i->client, i->conn, NULL, 0, i->context);
540 silc_free(i->client_id);
544 /* Same as above but will always resolve the information from the server.
545 Use this only if you know that you don't have the entry and the only
546 thing you know about the client is its ID. */
548 void silc_client_get_client_by_id_resolve(SilcClient client,
549 SilcClientConnection conn,
550 SilcClientID *client_id,
551 SilcBuffer attributes,
552 SilcGetClientCallback completion,
556 GetClientByIDInternal i = silc_calloc(1, sizeof(*i));
558 SILC_LOG_DEBUG(("Start"));
562 i->client_id = silc_id_dup(client_id, SILC_ID_CLIENT);
563 i->completion = completion;
564 i->context = context;
566 /* Register our own command reply for this command */
567 silc_client_command_register(client, SILC_COMMAND_WHOIS, NULL, NULL,
568 silc_client_command_reply_whois_i, 0,
571 /* Send the command */
572 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
573 silc_client_command_send(client, conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
574 2, 3, attributes ? attributes->data : NULL,
575 attributes ? attributes->len : 0,
576 4, idp->data, idp->len);
577 silc_buffer_free(idp);
579 /* Add pending callback */
580 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
581 silc_client_command_get_client_by_id_callback,
586 /******************************************************************************
588 Client, Channel and Server entry manipulation
590 ******************************************************************************/
593 /* Creates new client entry and adds it to the ID cache. Returns pointer
597 silc_client_add_client(SilcClient client, SilcClientConnection conn,
598 char *nickname, char *username,
599 char *userinfo, SilcClientID *id, SilcUInt32 mode)
601 SilcClientEntry client_entry;
604 SILC_LOG_DEBUG(("Start"));
606 /* Save the client infos */
607 client_entry = silc_calloc(1, sizeof(*client_entry));
608 client_entry->id = id;
609 client_entry->valid = TRUE;
610 silc_parse_userfqdn(nickname, &nick, &client_entry->server);
611 silc_parse_userfqdn(username, &client_entry->username,
612 &client_entry->hostname);
614 client_entry->realname = strdup(userinfo);
615 client_entry->mode = mode;
617 client_entry->nickname = strdup(nick);
618 client_entry->channels = silc_hash_table_alloc(1, silc_hash_ptr, NULL, NULL,
619 NULL, NULL, NULL, TRUE);
621 /* Format the nickname */
622 silc_client_nickname_format(client, conn, client_entry);
624 /* Add client to cache, the non-formatted nickname is saved to cache */
625 if (!silc_idcache_add(conn->client_cache, nick, client_entry->id,
626 (void *)client_entry, 0, NULL)) {
627 silc_free(client_entry->nickname);
628 silc_free(client_entry->username);
629 silc_free(client_entry->hostname);
630 silc_free(client_entry->server);
631 silc_hash_table_free(client_entry->channels);
632 silc_free(client_entry);
639 /* Updates the `client_entry' with the new information sent as argument. */
641 void silc_client_update_client(SilcClient client,
642 SilcClientConnection conn,
643 SilcClientEntry client_entry,
644 const char *nickname,
645 const char *username,
646 const char *userinfo,
651 SILC_LOG_DEBUG(("Start"));
653 if ((!client_entry->username || !client_entry->hostname) && username) {
654 silc_free(client_entry->username);
655 silc_free(client_entry->hostname);
656 client_entry->username = NULL;
657 client_entry->hostname = NULL;
658 silc_parse_userfqdn(username, &client_entry->username,
659 &client_entry->hostname);
661 if (!client_entry->realname && userinfo)
662 client_entry->realname = strdup(userinfo);
663 if (!client_entry->nickname && nickname) {
664 silc_parse_userfqdn(nickname, &nick, &client_entry->server);
665 client_entry->nickname = strdup(nick);
666 silc_client_nickname_format(client, conn, client_entry);
668 client_entry->mode = mode;
671 /* Remove the old cache entry and create a new one */
672 silc_idcache_del_by_context(conn->client_cache, client_entry);
673 silc_idcache_add(conn->client_cache, nick, client_entry->id,
674 client_entry, 0, NULL);
678 /* Deletes the client entry and frees all memory. */
680 void silc_client_del_client_entry(SilcClient client,
681 SilcClientConnection conn,
682 SilcClientEntry client_entry)
684 SILC_LOG_DEBUG(("Start"));
686 silc_free(client_entry->nickname);
687 silc_free(client_entry->username);
688 silc_free(client_entry->realname);
689 silc_free(client_entry->hostname);
690 silc_free(client_entry->server);
691 silc_free(client_entry->id);
692 silc_free(client_entry->fingerprint);
693 silc_hash_table_free(client_entry->channels);
694 if (client_entry->send_key)
695 silc_cipher_free(client_entry->send_key);
696 if (client_entry->receive_key)
697 silc_cipher_free(client_entry->receive_key);
698 silc_free(client_entry->key);
699 silc_client_ftp_session_free_client(conn, client_entry);
700 if (client_entry->ke)
701 silc_client_abort_key_agreement(client, conn, client_entry);
702 silc_free(client_entry);
705 /* Removes client from the cache by the client entry. */
707 bool silc_client_del_client(SilcClient client, SilcClientConnection conn,
708 SilcClientEntry client_entry)
710 bool ret = silc_idcache_del_by_context(conn->client_cache, client_entry);
712 /* Remove from channels */
713 silc_client_remove_from_channels(client, conn, client_entry);
715 /* Free the client entry data */
716 silc_client_del_client_entry(client, conn, client_entry);
721 /* Add new channel entry to the ID Cache */
723 SilcChannelEntry silc_client_add_channel(SilcClient client,
724 SilcClientConnection conn,
725 const char *channel_name,
727 SilcChannelID *channel_id)
729 SilcChannelEntry channel;
731 SILC_LOG_DEBUG(("Start"));
733 channel = silc_calloc(1, sizeof(*channel));
734 channel->channel_name = strdup(channel_name);
735 channel->id = channel_id;
736 channel->mode = mode;
737 channel->user_list = silc_hash_table_alloc(1, silc_hash_ptr, NULL, NULL,
738 NULL, NULL, NULL, TRUE);
740 /* Put it to the ID cache */
741 if (!silc_idcache_add(conn->channel_cache, channel->channel_name,
742 (void *)channel->id, (void *)channel, 0, NULL)) {
743 silc_free(channel->channel_name);
744 silc_hash_table_free(channel->user_list);
752 /* Foreach callbcak to free all users from the channel when deleting a
755 static void silc_client_del_channel_foreach(void *key, void *context,
758 SilcChannelUser chu = (SilcChannelUser)context;
760 SILC_LOG_DEBUG(("Start"));
762 /* Remove the context from the client's channel hash table as that
763 table and channel's user_list hash table share this same context. */
764 silc_hash_table_del(chu->client->channels, chu->channel);
768 /* Removes channel from the cache by the channel entry. */
770 bool silc_client_del_channel(SilcClient client, SilcClientConnection conn,
771 SilcChannelEntry channel)
773 bool ret = silc_idcache_del_by_context(conn->channel_cache, channel);
775 SILC_LOG_DEBUG(("Start"));
777 /* Free all client entrys from the users list. The silc_hash_table_free
778 will free all the entries so they are not freed at the foreach
780 silc_hash_table_foreach(channel->user_list, silc_client_del_channel_foreach,
782 silc_hash_table_free(channel->user_list);
784 silc_free(channel->channel_name);
785 silc_free(channel->id);
786 silc_free(channel->key);
787 if (channel->channel_key)
788 silc_cipher_free(channel->channel_key);
790 silc_hmac_free(channel->hmac);
791 if (channel->old_channel_key)
792 silc_cipher_free(channel->old_channel_key);
793 if (channel->old_hmac)
794 silc_hmac_free(channel->old_hmac);
795 if (channel->rekey_task)
796 silc_schedule_task_del(conn->client->schedule, channel->rekey_task);
797 silc_client_del_channel_private_keys(client, conn, channel);
802 /* Replaces the channel ID of the `channel' to `new_id'. Returns FALSE
803 if the ID could not be changed. */
805 bool silc_client_replace_channel_id(SilcClient client,
806 SilcClientConnection conn,
807 SilcChannelEntry channel,
808 SilcChannelID *new_id)
813 SILC_LOG_DEBUG(("Old Channel ID id(%s)",
814 silc_id_render(channel->id, SILC_ID_CHANNEL)));
815 SILC_LOG_DEBUG(("New Channel ID id(%s)",
816 silc_id_render(new_id, SILC_ID_CHANNEL)));
818 silc_idcache_del_by_id(conn->channel_cache, channel->id);
819 silc_free(channel->id);
820 channel->id = new_id;
821 return silc_idcache_add(conn->channel_cache, channel->channel_name,
822 (void *)channel->id, (void *)channel, 0, NULL);
826 /* Finds entry for channel by the channel name. Returns the entry or NULL
827 if the entry was not found. It is found only if the client is joined
830 SilcChannelEntry silc_client_get_channel(SilcClient client,
831 SilcClientConnection conn,
834 SilcIDCacheEntry id_cache;
835 SilcChannelEntry entry;
837 SILC_LOG_DEBUG(("Start"));
839 if (!silc_idcache_find_by_name_one(conn->channel_cache, channel,
843 entry = (SilcChannelEntry)id_cache->context;
845 SILC_LOG_DEBUG(("Found"));
850 /* Finds entry for channel by the channel ID. Returns the entry or NULL
851 if the entry was not found. It is found only if the client is joined
854 SilcChannelEntry silc_client_get_channel_by_id(SilcClient client,
855 SilcClientConnection conn,
856 SilcChannelID *channel_id)
858 SilcIDCacheEntry id_cache;
859 SilcChannelEntry entry;
861 SILC_LOG_DEBUG(("Start"));
863 if (!silc_idcache_find_by_id_one(conn->channel_cache, channel_id,
867 entry = (SilcChannelEntry)id_cache->context;
869 SILC_LOG_DEBUG(("Found"));
876 SilcClientConnection conn;
877 SilcChannelID *channel_id;
878 SilcGetChannelCallback completion;
880 } *GetChannelByIDInternal;
882 SILC_CLIENT_CMD_FUNC(get_channel_by_id_callback)
884 GetChannelByIDInternal i = (GetChannelByIDInternal)context;
885 SilcChannelEntry entry;
887 SILC_LOG_DEBUG(("Start"));
889 /* Get the channel */
890 entry = silc_client_get_channel_by_id(i->client, i->conn, i->channel_id);
892 i->completion(i->client, i->conn, &entry, 1, i->context);
894 i->completion(i->client, i->conn, NULL, 0, i->context);
897 silc_free(i->channel_id);
901 /* Resolves channel information from the server by the channel ID. */
903 void silc_client_get_channel_by_id_resolve(SilcClient client,
904 SilcClientConnection conn,
905 SilcChannelID *channel_id,
906 SilcGetChannelCallback completion,
910 GetChannelByIDInternal i = silc_calloc(1, sizeof(*i));
912 SILC_LOG_DEBUG(("Start"));
916 i->channel_id = silc_id_dup(channel_id, SILC_ID_CHANNEL);
917 i->completion = completion;
918 i->context = context;
920 /* Register our own command reply for this command */
921 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
922 silc_client_command_reply_identify_i, 0,
925 /* Send the command */
926 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
927 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
929 1, 5, idp->data, idp->len);
930 silc_buffer_free(idp);
932 /* Add pending callback */
933 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
934 silc_client_command_get_channel_by_id_callback,
938 /* Finds entry for server by the server name. */
940 SilcServerEntry silc_client_get_server(SilcClient client,
941 SilcClientConnection conn,
944 SilcIDCacheEntry id_cache;
945 SilcServerEntry entry;
947 SILC_LOG_DEBUG(("Start"));
949 if (!silc_idcache_find_by_name_one(conn->server_cache, server_name,
953 entry = (SilcServerEntry)id_cache->context;
958 /* Finds entry for server by the server ID. */
960 SilcServerEntry silc_client_get_server_by_id(SilcClient client,
961 SilcClientConnection conn,
962 SilcServerID *server_id)
964 SilcIDCacheEntry id_cache;
965 SilcServerEntry entry;
967 SILC_LOG_DEBUG(("Start"));
969 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
973 entry = (SilcServerEntry)id_cache->context;
978 /* Add new server entry */
980 SilcServerEntry silc_client_add_server(SilcClient client,
981 SilcClientConnection conn,
982 const char *server_name,
983 const char *server_info,
984 SilcServerID *server_id)
986 SilcServerEntry server_entry;
988 SILC_LOG_DEBUG(("Start"));
990 server_entry = silc_calloc(1, sizeof(*server_entry));
991 if (!server_entry || !server_id)
994 server_entry->server_id = server_id;
996 server_entry->server_name = strdup(server_name);
998 server_entry->server_info = strdup(server_info);
1000 /* Add server to cache */
1001 if (!silc_idcache_add(conn->server_cache, server_entry->server_name,
1002 server_entry->server_id, server_entry, 0, NULL)) {
1003 silc_free(server_entry->server_id);
1004 silc_free(server_entry->server_name);
1005 silc_free(server_entry->server_info);
1006 silc_free(server_entry);
1010 return server_entry;
1013 /* Removes server from the cache by the server entry. */
1015 bool silc_client_del_server(SilcClient client, SilcClientConnection conn,
1016 SilcServerEntry server)
1018 bool ret = silc_idcache_del_by_context(conn->server_cache, server);
1019 silc_free(server->server_name);
1020 silc_free(server->server_info);
1021 silc_free(server->server_id);
1026 /* Updates the `server_entry' with the new information sent as argument. */
1028 void silc_client_update_server(SilcClient client,
1029 SilcClientConnection conn,
1030 SilcServerEntry server_entry,
1031 const char *server_name,
1032 const char *server_info)
1034 SILC_LOG_DEBUG(("Start"));
1036 if (server_name && (!server_entry->server_name ||
1037 strcmp(server_entry->server_name, server_name))) {
1039 silc_idcache_del_by_context(conn->server_cache, server_entry);
1040 silc_free(server_entry->server_name);
1041 server_entry->server_name = strdup(server_name);
1042 silc_idcache_add(conn->server_cache, server_entry->server_name,
1043 server_entry->server_id,
1044 server_entry, 0, NULL);
1047 if (server_info && (!server_entry->server_info ||
1048 strcmp(server_entry->server_info, server_info))) {
1049 silc_free(server_entry->server_info);
1050 server_entry->server_info = strdup(server_info);
1054 /* Formats the nickname of the client specified by the `client_entry'.
1055 If the format is specified by the application this will format the
1056 nickname and replace the old nickname in the client entry. If the
1057 format string is not specified then this function has no effect. */
1059 void silc_client_nickname_format(SilcClient client,
1060 SilcClientConnection conn,
1061 SilcClientEntry client_entry)
1064 char *newnick = NULL;
1065 int i, off = 0, len;
1067 SilcClientEntry *clients;
1068 SilcUInt32 clients_count = 0;
1069 SilcClientEntry unformatted = NULL;
1071 SILC_LOG_DEBUG(("Start"));
1073 if (!client->internal->params->nickname_format[0])
1076 if (!client_entry->nickname)
1079 /* Get all clients with same nickname. Do not perform the formatting
1080 if there aren't any clients with same nickname unless the application
1081 is forcing us to do so. */
1082 clients = silc_client_get_clients_local(client, conn,
1083 client_entry->nickname, NULL,
1085 if (!clients && !client->internal->params->nickname_force_format)
1090 for (i = 0; i < clients_count; i++) {
1091 if (clients[i]->valid && clients[i] != client_entry)
1093 if (clients[i]->valid && clients[i] != client_entry &&
1094 !strcmp(clients[i]->nickname, client_entry->nickname))
1097 if (!len || freebase)
1100 cp = client->internal->params->nickname_format;
1110 if (!client_entry->nickname)
1112 len = strlen(client_entry->nickname);
1113 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1114 memcpy(&newnick[off], client_entry->nickname, len);
1118 /* Stripped hostname */
1119 if (!client_entry->hostname)
1121 len = strcspn(client_entry->hostname, ".");
1122 i = strcspn(client_entry->hostname, "-");
1125 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1126 memcpy(&newnick[off], client_entry->hostname, len);
1131 if (!client_entry->hostname)
1133 len = strlen(client_entry->hostname);
1134 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1135 memcpy(&newnick[off], client_entry->hostname, len);
1139 /* Stripped server name */
1140 if (!client_entry->server)
1142 len = strcspn(client_entry->server, ".");
1143 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1144 memcpy(&newnick[off], client_entry->server, len);
1148 /* Full server name */
1149 if (!client_entry->server)
1151 len = strlen(client_entry->server);
1152 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1153 memcpy(&newnick[off], client_entry->server, len);
1157 /* Ascending number */
1162 if (clients_count == 1) {
1163 unformatted = clients[0];
1167 for (i = 0; i < clients_count; i++) {
1168 if (!strncasecmp(clients[i]->nickname, client_entry->nickname,
1169 strlen(clients[i]->nickname)))
1170 unformatted = clients[i];
1171 if (strncasecmp(clients[i]->nickname, newnick, off))
1173 if (strlen(clients[i]->nickname) <= off)
1175 num = atoi(&clients[i]->nickname[off]);
1180 memset(tmp, 0, sizeof(tmp));
1181 snprintf(tmp, sizeof(tmp) - 1, "%d", ++max);
1183 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1184 memcpy(&newnick[off], tmp, len);
1189 /* Some other character in the string */
1190 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
1191 memcpy(&newnick[off], cp, 1);
1199 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
1202 /* If we are changing nickname of our local entry we'll enforce
1203 that we will always get the unformatted nickname. Give our
1204 format number to the one that is not formatted now. */
1205 if (unformatted && client_entry == conn->local_entry)
1206 client_entry = unformatted;
1208 silc_free(client_entry->nickname);
1209 client_entry->nickname = newnick;