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->internal->client_cache,
54 (char *)nickname, &list))
57 if (!silc_idcache_list_count(list)) {
58 silc_idcache_list_free(list);
62 clients = silc_calloc(silc_idcache_list_count(list), sizeof(*clients));
63 *clients_count = silc_idcache_list_count(list);
66 /* Take all without any further checking */
67 silc_idcache_list_first(list, &id_cache);
69 clients[i++] = id_cache->context;
71 if (!silc_idcache_list_next(list, &id_cache))
75 /* Check multiple cache entries for match */
76 silc_idcache_list_first(list, &id_cache);
78 entry = (SilcClientEntry)id_cache->context;
79 if (strcasecmp(entry->nickname, format)) {
80 if (!silc_idcache_list_next(list, &id_cache)) {
87 clients[i++] = id_cache->context;
89 if (!silc_idcache_list_next(list, &id_cache))
95 silc_idcache_list_free(list);
108 /******************************************************************************
110 Client Resolving from Server
112 ******************************************************************************/
116 SilcClientConnection conn;
117 SilcGetClientCallback completion;
121 } *GetClientInternal;
123 SILC_CLIENT_CMD_FUNC(get_client_callback)
125 GetClientInternal i = (GetClientInternal)context;
126 SilcClientEntry *clients;
127 SilcUInt32 clients_count;
129 /* Get the clients */
130 clients = silc_client_get_clients_local(i->client, i->conn,
131 i->nickname, i->server,
134 i->completion(i->client, i->conn, clients, clients_count, i->context);
137 i->completion(i->client, i->conn, NULL, 0, i->context);
140 silc_free(i->nickname);
141 silc_free(i->server);
145 /* Finds client entry or entries by the `nickname' and `server'. The
146 completion callback will be called when the client entries has been found.
148 Note: this function is always asynchronous and resolves the client
149 information from the server. Thus, if you already know the client
150 information then use the silc_client_get_client_by_id function to
151 get the client entry since this function may be very slow and should
152 be used only to initially get the client entries. */
154 void silc_client_get_clients(SilcClient client,
155 SilcClientConnection conn,
156 const char *nickname,
158 SilcGetClientCallback completion,
168 i = silc_calloc(1, sizeof(*i));
171 i->nickname = strdup(nickname);
172 i->server = server ? strdup(server) : NULL;
173 i->completion = completion;
174 i->context = context;
176 if (nickname && server) {
177 len = strlen(nickname) + strlen(server) + 3;
178 userhost = silc_calloc(len, sizeof(*userhost));
179 silc_strncat(userhost, len, nickname, strlen(nickname));
180 silc_strncat(userhost, len, "@", 1);
181 silc_strncat(userhost, len, server, strlen(server));
183 userhost = silc_memdup(nickname, strlen(nickname));
186 /* Register our own command reply for this command */
187 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
188 silc_client_command_reply_identify_i, 0,
191 /* Send the command */
192 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
193 conn->cmd_ident, 1, 1, userhost,
196 /* Add pending callback */
197 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
198 silc_client_command_get_client_callback,
204 /* The old style function to find client entry. This is used by the
205 library internally. If `query' is TRUE then the client information is
206 requested by the server. The pending command callback must be set
208 /* XXX This function should be removed */
210 SilcClientEntry silc_idlist_get_client(SilcClient client,
211 SilcClientConnection conn,
212 const char *nickname,
216 SilcIDCacheEntry id_cache;
217 SilcIDCacheList list = NULL;
218 SilcClientEntry entry = NULL;
220 SILC_LOG_DEBUG(("Start"));
222 /* Find ID from cache */
223 if (!silc_idcache_find_by_name(conn->internal->client_cache,
224 (char *)nickname, &list)) {
228 SILC_LOG_DEBUG(("Requesting Client ID from server"));
230 /* Register our own command reply for this command */
231 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
232 silc_client_command_reply_identify_i, 0,
235 /* Send the command */
236 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
237 conn->cmd_ident, 1, 1, nickname,
241 silc_idcache_list_free(list);
249 /* Take first found cache entry */
250 if (!silc_idcache_list_first(list, &id_cache))
253 entry = (SilcClientEntry)id_cache->context;
255 /* Check multiple cache entries for match */
256 silc_idcache_list_first(list, &id_cache);
258 entry = (SilcClientEntry)id_cache->context;
260 if (strcasecmp(entry->nickname, format)) {
261 if (!silc_idcache_list_next(list, &id_cache)) {
273 /* If match weren't found, request it */
279 silc_idcache_list_free(list);
287 SilcClientConnection conn;
288 SilcUInt32 list_count;
289 SilcBuffer client_id_list;
290 SilcGetClientCallback completion;
293 } *GetClientsByListInternal;
295 SILC_CLIENT_CMD_FUNC(get_clients_list_callback)
297 GetClientsByListInternal i = (GetClientsByListInternal)context;
298 SilcIDCacheEntry id_cache = NULL;
299 SilcBuffer client_id_list = i->client_id_list;
300 SilcClientEntry *clients = NULL;
301 SilcUInt32 clients_count = 0;
305 SILC_LOG_DEBUG(("Start"));
313 SILC_LOG_DEBUG(("Resolved all clients"));
315 for (c = 0; c < i->list_count; c++) {
317 SilcClientID *client_id;
320 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
322 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
324 silc_buffer_pull(client_id_list, idp_len);
328 /* Get the client entry */
329 if (silc_idcache_find_by_id_one_ext(i->conn->internal->client_cache,
332 silc_hash_client_id_compare, NULL,
334 clients = silc_realloc(clients, sizeof(*clients) *
335 (clients_count + 1));
336 clients[clients_count] = (SilcClientEntry)id_cache->context;
341 silc_free(client_id);
342 silc_buffer_pull(client_id_list, idp_len);
346 i->completion(i->client, i->conn, clients, clients_count, i->context);
349 i->completion(i->client, i->conn, NULL, 0, i->context);
352 if (i->client_id_list)
353 silc_buffer_free(i->client_id_list);
357 /* Gets client entries by the list of client ID's `client_id_list'. This
358 always resolves those client ID's it does not know yet from the server
359 so this function might take a while. The `client_id_list' is a list
360 of ID Payloads added one after other. JOIN command reply and USERS
361 command reply for example returns this sort of list. The `completion'
362 will be called after the entries are available. */
364 void silc_client_get_clients_by_list(SilcClient client,
365 SilcClientConnection conn,
366 SilcUInt32 list_count,
367 SilcBuffer client_id_list,
368 SilcGetClientCallback completion,
371 SilcIDCacheEntry id_cache = NULL;
373 unsigned char **res_argv = NULL;
374 SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
375 GetClientsByListInternal in;
376 bool wait_res = FALSE;
378 SILC_LOG_DEBUG(("Start"));
380 in = silc_calloc(1, sizeof(*in));
383 in->list_count = list_count;
384 in->client_id_list = silc_buffer_copy(client_id_list);
385 in->completion = completion;
386 in->context = context;
388 for (i = 0; i < list_count; i++) {
390 SilcClientID *client_id;
391 SilcClientEntry entry;
395 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
397 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
399 silc_buffer_pull(client_id_list, idp_len);
403 /* Check if we have this client cached already. */
405 silc_idcache_find_by_id_one_ext(conn->internal->client_cache,
406 (void *)client_id, NULL, NULL,
407 silc_hash_client_id_compare, NULL,
410 /* If we don't have the entry or it has incomplete info, then resolve
411 it from the server. */
412 if (!ret || !((SilcClientEntry)id_cache->context)->nickname) {
413 entry = ret ? (SilcClientEntry)id_cache->context : NULL;
416 if (entry->status & SILC_CLIENT_STATUS_RESOLVING) {
417 /* Attach to this resolving and wait until it finishes */
418 silc_client_command_pending(
419 conn, SILC_COMMAND_NONE,
420 entry->resolve_cmd_ident,
421 silc_client_command_get_clients_list_callback,
426 silc_free(client_id);
427 silc_buffer_pull(client_id_list, idp_len);
431 entry->status |= SILC_CLIENT_STATUS_RESOLVING;
432 entry->resolve_cmd_ident = conn->cmd_ident + 1;
435 /* No we don't have it, query it from the server. Assemble argument
436 table that will be sent for the IDENTIFY command later. */
437 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
439 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
441 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
443 res_argv[res_argc] = client_id_list->data;
444 res_argv_lens[res_argc] = idp_len;
445 res_argv_types[res_argc] = res_argc + 5;
449 silc_free(client_id);
450 silc_buffer_pull(client_id_list, idp_len);
453 silc_buffer_push(client_id_list, client_id_list->data -
454 client_id_list->head);
456 /* Query the client information from server if the list included clients
457 that we don't know about. */
461 /* Send the IDENTIFY command to server */
462 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
463 res_argc, res_argv, res_argv_lens,
464 res_argv_types, ++conn->cmd_ident);
465 silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
466 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
469 /* Register our own command reply for this command */
470 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
471 silc_client_command_reply_identify_i, 0,
474 /* Process the applications request after reply has been received */
475 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
476 silc_client_command_get_clients_list_callback,
480 silc_buffer_free(res_cmd);
482 silc_free(res_argv_lens);
483 silc_free(res_argv_types);
490 /* We have the clients in cache, get them and call the completion */
491 silc_client_command_get_clients_list_callback((void *)in, NULL);
494 /* Finds entry for client by the client's ID. Returns the entry or NULL
495 if the entry was not found. */
497 SilcClientEntry silc_client_get_client_by_id(SilcClient client,
498 SilcClientConnection conn,
499 SilcClientID *client_id)
501 SilcIDCacheEntry id_cache;
503 SILC_LOG_DEBUG(("Finding client by ID (%s)",
504 silc_id_render(client_id, SILC_ID_CLIENT)));
506 /* Find ID from cache */
507 if (!silc_idcache_find_by_id_one_ext(conn->internal->client_cache,
508 (void *)client_id, NULL, NULL,
509 silc_hash_client_id_compare, NULL,
513 SILC_LOG_DEBUG(("Found"));
515 return (SilcClientEntry)id_cache->context;
520 SilcClientConnection conn;
521 SilcClientID *client_id;
522 SilcGetClientCallback completion;
524 } *GetClientByIDInternal;
526 SILC_CLIENT_CMD_FUNC(get_client_by_id_callback)
528 GetClientByIDInternal i = (GetClientByIDInternal)context;
529 SilcClientEntry entry;
532 entry = silc_client_get_client_by_id(i->client, i->conn, i->client_id);
535 i->completion(i->client, i->conn, &entry, 1, i->context);
538 i->completion(i->client, i->conn, NULL, 0, i->context);
541 silc_free(i->client_id);
545 /* Same as above but will always resolve the information from the server.
546 Use this only if you know that you don't have the entry and the only
547 thing you know about the client is its ID. */
549 void silc_client_get_client_by_id_resolve(SilcClient client,
550 SilcClientConnection conn,
551 SilcClientID *client_id,
552 SilcBuffer attributes,
553 SilcGetClientCallback completion,
557 GetClientByIDInternal i = silc_calloc(1, sizeof(*i));
559 SILC_LOG_DEBUG(("Start"));
563 i->client_id = silc_id_dup(client_id, SILC_ID_CLIENT);
564 i->completion = completion;
565 i->context = context;
567 /* Register our own command reply for this command */
568 silc_client_command_register(client, SILC_COMMAND_WHOIS, NULL, NULL,
569 silc_client_command_reply_whois_i, 0,
572 /* Send the command */
573 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
574 silc_client_command_send(client, conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
575 2, 3, attributes ? attributes->data : NULL,
576 attributes ? attributes->len : 0,
577 4, idp->data, idp->len);
578 silc_buffer_free(idp);
580 /* Add pending callback */
581 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
582 silc_client_command_get_client_by_id_callback,
587 /******************************************************************************
589 Client, Channel and Server entry manipulation
591 ******************************************************************************/
594 /* Creates new client entry and adds it to the ID cache. Returns pointer
598 silc_client_add_client(SilcClient client, SilcClientConnection conn,
599 char *nickname, char *username,
600 char *userinfo, SilcClientID *id, SilcUInt32 mode)
602 SilcClientEntry client_entry;
605 SILC_LOG_DEBUG(("Start"));
607 /* Save the client infos */
608 client_entry = silc_calloc(1, sizeof(*client_entry));
609 client_entry->id = id;
610 client_entry->valid = TRUE;
611 silc_parse_userfqdn(nickname, &nick, &client_entry->server);
612 silc_parse_userfqdn(username, &client_entry->username,
613 &client_entry->hostname);
615 client_entry->realname = strdup(userinfo);
616 client_entry->mode = mode;
618 client_entry->nickname = strdup(nick);
619 client_entry->channels = silc_hash_table_alloc(1, silc_hash_ptr, NULL, NULL,
620 NULL, NULL, NULL, TRUE);
622 /* Format the nickname */
623 silc_client_nickname_format(client, conn, client_entry);
625 /* Add client to cache, the non-formatted nickname is saved to cache */
626 if (!silc_idcache_add(conn->internal->client_cache, nick, client_entry->id,
627 (void *)client_entry, 0, NULL)) {
628 silc_free(client_entry->nickname);
629 silc_free(client_entry->username);
630 silc_free(client_entry->hostname);
631 silc_free(client_entry->server);
632 silc_hash_table_free(client_entry->channels);
633 silc_free(client_entry);
640 /* Updates the `client_entry' with the new information sent as argument. */
642 void silc_client_update_client(SilcClient client,
643 SilcClientConnection conn,
644 SilcClientEntry client_entry,
645 const char *nickname,
646 const char *username,
647 const char *userinfo,
652 SILC_LOG_DEBUG(("Start"));
654 if ((!client_entry->username || !client_entry->hostname) && username) {
655 silc_free(client_entry->username);
656 silc_free(client_entry->hostname);
657 client_entry->username = NULL;
658 client_entry->hostname = NULL;
659 silc_parse_userfqdn(username, &client_entry->username,
660 &client_entry->hostname);
662 if (!client_entry->realname && userinfo)
663 client_entry->realname = strdup(userinfo);
664 if (!client_entry->nickname && nickname) {
665 silc_parse_userfqdn(nickname, &nick, &client_entry->server);
666 client_entry->nickname = strdup(nick);
667 silc_client_nickname_format(client, conn, client_entry);
669 client_entry->mode = mode;
672 /* Remove the old cache entry and create a new one */
673 silc_idcache_del_by_context(conn->internal->client_cache, client_entry);
674 silc_idcache_add(conn->internal->client_cache, nick, client_entry->id,
675 client_entry, 0, NULL);
679 /* Deletes the client entry and frees all memory. */
681 void silc_client_del_client_entry(SilcClient client,
682 SilcClientConnection conn,
683 SilcClientEntry client_entry)
685 SILC_LOG_DEBUG(("Start"));
687 silc_free(client_entry->nickname);
688 silc_free(client_entry->username);
689 silc_free(client_entry->realname);
690 silc_free(client_entry->hostname);
691 silc_free(client_entry->server);
692 silc_free(client_entry->id);
693 silc_free(client_entry->fingerprint);
694 silc_hash_table_free(client_entry->channels);
695 if (client_entry->send_key)
696 silc_cipher_free(client_entry->send_key);
697 if (client_entry->receive_key)
698 silc_cipher_free(client_entry->receive_key);
699 silc_free(client_entry->key);
700 silc_client_ftp_session_free_client(conn, client_entry);
701 if (client_entry->ke)
702 silc_client_abort_key_agreement(client, conn, client_entry);
703 silc_free(client_entry);
706 /* Removes client from the cache by the client entry. */
708 bool silc_client_del_client(SilcClient client, SilcClientConnection conn,
709 SilcClientEntry client_entry)
711 bool ret = silc_idcache_del_by_context(conn->internal->client_cache,
714 /* Remove from channels */
715 silc_client_remove_from_channels(client, conn, client_entry);
717 /* Free the client entry data */
718 silc_client_del_client_entry(client, conn, client_entry);
723 /* Add new channel entry to the ID Cache */
725 SilcChannelEntry silc_client_add_channel(SilcClient client,
726 SilcClientConnection conn,
727 const char *channel_name,
729 SilcChannelID *channel_id)
731 SilcChannelEntry channel;
733 SILC_LOG_DEBUG(("Start"));
735 channel = silc_calloc(1, sizeof(*channel));
736 channel->channel_name = strdup(channel_name);
737 channel->id = channel_id;
738 channel->mode = mode;
739 channel->user_list = silc_hash_table_alloc(1, silc_hash_ptr, NULL, NULL,
740 NULL, NULL, NULL, TRUE);
742 /* Put it to the ID cache */
743 if (!silc_idcache_add(conn->internal->channel_cache, channel->channel_name,
744 (void *)channel->id, (void *)channel, 0, NULL)) {
745 silc_free(channel->channel_name);
746 silc_hash_table_free(channel->user_list);
754 /* Foreach callbcak to free all users from the channel when deleting a
757 static void silc_client_del_channel_foreach(void *key, void *context,
760 SilcChannelUser chu = (SilcChannelUser)context;
762 SILC_LOG_DEBUG(("Start"));
764 /* Remove the context from the client's channel hash table as that
765 table and channel's user_list hash table share this same context. */
766 silc_hash_table_del(chu->client->channels, chu->channel);
770 /* Removes channel from the cache by the channel entry. */
772 bool silc_client_del_channel(SilcClient client, SilcClientConnection conn,
773 SilcChannelEntry channel)
775 bool ret = silc_idcache_del_by_context(conn->internal->channel_cache,
778 SILC_LOG_DEBUG(("Start"));
780 /* Free all client entrys from the users list. The silc_hash_table_free
781 will free all the entries so they are not freed at the foreach
783 silc_hash_table_foreach(channel->user_list, silc_client_del_channel_foreach,
785 silc_hash_table_free(channel->user_list);
787 silc_free(channel->channel_name);
788 silc_free(channel->id);
789 silc_free(channel->key);
790 if (channel->channel_key)
791 silc_cipher_free(channel->channel_key);
793 silc_hmac_free(channel->hmac);
794 if (channel->old_channel_key)
795 silc_cipher_free(channel->old_channel_key);
796 if (channel->old_hmac)
797 silc_hmac_free(channel->old_hmac);
798 if (channel->rekey_task)
799 silc_schedule_task_del(conn->client->schedule, channel->rekey_task);
800 silc_client_del_channel_private_keys(client, conn, channel);
805 /* Replaces the channel ID of the `channel' to `new_id'. Returns FALSE
806 if the ID could not be changed. */
808 bool silc_client_replace_channel_id(SilcClient client,
809 SilcClientConnection conn,
810 SilcChannelEntry channel,
811 SilcChannelID *new_id)
816 SILC_LOG_DEBUG(("Old Channel ID id(%s)",
817 silc_id_render(channel->id, SILC_ID_CHANNEL)));
818 SILC_LOG_DEBUG(("New Channel ID id(%s)",
819 silc_id_render(new_id, SILC_ID_CHANNEL)));
821 silc_idcache_del_by_id(conn->internal->channel_cache, channel->id);
822 silc_free(channel->id);
823 channel->id = new_id;
824 return silc_idcache_add(conn->internal->channel_cache,
825 channel->channel_name,
826 (void *)channel->id, (void *)channel, 0, NULL);
830 /* Finds entry for channel by the channel name. 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(SilcClient client,
835 SilcClientConnection conn,
838 SilcIDCacheEntry id_cache;
839 SilcChannelEntry entry;
841 SILC_LOG_DEBUG(("Start"));
843 if (!silc_idcache_find_by_name_one(conn->internal->channel_cache, channel,
847 entry = (SilcChannelEntry)id_cache->context;
849 SILC_LOG_DEBUG(("Found"));
854 /* Finds entry for channel by the channel ID. Returns the entry or NULL
855 if the entry was not found. It is found only if the client is joined
858 SilcChannelEntry silc_client_get_channel_by_id(SilcClient client,
859 SilcClientConnection conn,
860 SilcChannelID *channel_id)
862 SilcIDCacheEntry id_cache;
863 SilcChannelEntry entry;
865 SILC_LOG_DEBUG(("Start"));
867 if (!silc_idcache_find_by_id_one(conn->internal->channel_cache, channel_id,
871 entry = (SilcChannelEntry)id_cache->context;
873 SILC_LOG_DEBUG(("Found"));
880 SilcClientConnection conn;
881 SilcChannelID *channel_id;
882 SilcGetChannelCallback completion;
884 } *GetChannelByIDInternal;
886 SILC_CLIENT_CMD_FUNC(get_channel_by_id_callback)
888 GetChannelByIDInternal i = (GetChannelByIDInternal)context;
889 SilcChannelEntry entry;
891 SILC_LOG_DEBUG(("Start"));
893 /* Get the channel */
894 entry = silc_client_get_channel_by_id(i->client, i->conn, i->channel_id);
896 i->completion(i->client, i->conn, &entry, 1, i->context);
898 i->completion(i->client, i->conn, NULL, 0, i->context);
901 silc_free(i->channel_id);
905 /* Resolves channel information from the server by the channel ID. */
907 void silc_client_get_channel_by_id_resolve(SilcClient client,
908 SilcClientConnection conn,
909 SilcChannelID *channel_id,
910 SilcGetChannelCallback completion,
914 GetChannelByIDInternal i = silc_calloc(1, sizeof(*i));
916 SILC_LOG_DEBUG(("Start"));
920 i->channel_id = silc_id_dup(channel_id, SILC_ID_CHANNEL);
921 i->completion = completion;
922 i->context = context;
924 /* Register our own command reply for this command */
925 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
926 silc_client_command_reply_identify_i, 0,
929 /* Send the command */
930 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
931 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
933 1, 5, idp->data, idp->len);
934 silc_buffer_free(idp);
936 /* Add pending callback */
937 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
938 silc_client_command_get_channel_by_id_callback,
942 /* Finds entry for server by the server name. */
944 SilcServerEntry silc_client_get_server(SilcClient client,
945 SilcClientConnection conn,
948 SilcIDCacheEntry id_cache;
949 SilcServerEntry entry;
951 SILC_LOG_DEBUG(("Start"));
953 if (!silc_idcache_find_by_name_one(conn->internal->server_cache,
954 server_name, &id_cache))
957 entry = (SilcServerEntry)id_cache->context;
962 /* Finds entry for server by the server ID. */
964 SilcServerEntry silc_client_get_server_by_id(SilcClient client,
965 SilcClientConnection conn,
966 SilcServerID *server_id)
968 SilcIDCacheEntry id_cache;
969 SilcServerEntry entry;
971 SILC_LOG_DEBUG(("Start"));
973 if (!silc_idcache_find_by_id_one(conn->internal->server_cache,
974 (void *)server_id, &id_cache))
977 entry = (SilcServerEntry)id_cache->context;
982 /* Add new server entry */
984 SilcServerEntry silc_client_add_server(SilcClient client,
985 SilcClientConnection conn,
986 const char *server_name,
987 const char *server_info,
988 SilcServerID *server_id)
990 SilcServerEntry server_entry;
992 SILC_LOG_DEBUG(("Start"));
994 server_entry = silc_calloc(1, sizeof(*server_entry));
995 if (!server_entry || !server_id)
998 server_entry->server_id = server_id;
1000 server_entry->server_name = strdup(server_name);
1002 server_entry->server_info = strdup(server_info);
1004 /* Add server to cache */
1005 if (!silc_idcache_add(conn->internal->server_cache,
1006 server_entry->server_name,
1007 server_entry->server_id, server_entry, 0, NULL)) {
1008 silc_free(server_entry->server_id);
1009 silc_free(server_entry->server_name);
1010 silc_free(server_entry->server_info);
1011 silc_free(server_entry);
1015 return server_entry;
1018 /* Removes server from the cache by the server entry. */
1020 bool silc_client_del_server(SilcClient client, SilcClientConnection conn,
1021 SilcServerEntry server)
1023 bool ret = silc_idcache_del_by_context(conn->internal->server_cache, server);
1024 silc_free(server->server_name);
1025 silc_free(server->server_info);
1026 silc_free(server->server_id);
1031 /* Updates the `server_entry' with the new information sent as argument. */
1033 void silc_client_update_server(SilcClient client,
1034 SilcClientConnection conn,
1035 SilcServerEntry server_entry,
1036 const char *server_name,
1037 const char *server_info)
1039 SILC_LOG_DEBUG(("Start"));
1041 if (server_name && (!server_entry->server_name ||
1042 strcmp(server_entry->server_name, server_name))) {
1044 silc_idcache_del_by_context(conn->internal->server_cache, server_entry);
1045 silc_free(server_entry->server_name);
1046 server_entry->server_name = strdup(server_name);
1047 silc_idcache_add(conn->internal->server_cache, server_entry->server_name,
1048 server_entry->server_id,
1049 server_entry, 0, NULL);
1052 if (server_info && (!server_entry->server_info ||
1053 strcmp(server_entry->server_info, server_info))) {
1054 silc_free(server_entry->server_info);
1055 server_entry->server_info = strdup(server_info);
1059 /* Formats the nickname of the client specified by the `client_entry'.
1060 If the format is specified by the application this will format the
1061 nickname and replace the old nickname in the client entry. If the
1062 format string is not specified then this function has no effect. */
1064 void silc_client_nickname_format(SilcClient client,
1065 SilcClientConnection conn,
1066 SilcClientEntry client_entry)
1069 char *newnick = NULL;
1070 int i, off = 0, len;
1072 SilcClientEntry *clients;
1073 SilcUInt32 clients_count = 0;
1074 SilcClientEntry unformatted = NULL;
1076 SILC_LOG_DEBUG(("Start"));
1078 if (!client->internal->params->nickname_format[0])
1081 if (!client_entry->nickname)
1084 /* Get all clients with same nickname. Do not perform the formatting
1085 if there aren't any clients with same nickname unless the application
1086 is forcing us to do so. */
1087 clients = silc_client_get_clients_local(client, conn,
1088 client_entry->nickname, NULL,
1090 if (!clients && !client->internal->params->nickname_force_format)
1095 for (i = 0; i < clients_count; i++) {
1096 if (clients[i]->valid && clients[i] != client_entry)
1098 if (clients[i]->valid && clients[i] != client_entry &&
1099 !strcmp(clients[i]->nickname, client_entry->nickname))
1102 if (!len || freebase)
1105 cp = client->internal->params->nickname_format;
1115 if (!client_entry->nickname)
1117 len = strlen(client_entry->nickname);
1118 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1119 memcpy(&newnick[off], client_entry->nickname, len);
1123 /* Stripped hostname */
1124 if (!client_entry->hostname)
1126 len = strcspn(client_entry->hostname, ".");
1127 i = strcspn(client_entry->hostname, "-");
1130 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1131 memcpy(&newnick[off], client_entry->hostname, len);
1136 if (!client_entry->hostname)
1138 len = strlen(client_entry->hostname);
1139 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1140 memcpy(&newnick[off], client_entry->hostname, len);
1144 /* Stripped server name */
1145 if (!client_entry->server)
1147 len = strcspn(client_entry->server, ".");
1148 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1149 memcpy(&newnick[off], client_entry->server, len);
1153 /* Full server name */
1154 if (!client_entry->server)
1156 len = strlen(client_entry->server);
1157 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1158 memcpy(&newnick[off], client_entry->server, len);
1162 /* Ascending number */
1167 if (clients_count == 1) {
1168 unformatted = clients[0];
1172 for (i = 0; i < clients_count; i++) {
1173 if (!strncasecmp(clients[i]->nickname, client_entry->nickname,
1174 strlen(clients[i]->nickname)))
1175 unformatted = clients[i];
1176 if (strncasecmp(clients[i]->nickname, newnick, off))
1178 if (strlen(clients[i]->nickname) <= off)
1180 num = atoi(&clients[i]->nickname[off]);
1185 memset(tmp, 0, sizeof(tmp));
1186 snprintf(tmp, sizeof(tmp) - 1, "%d", ++max);
1188 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1189 memcpy(&newnick[off], tmp, len);
1194 /* Some other character in the string */
1195 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
1196 memcpy(&newnick[off], cp, 1);
1204 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
1207 /* If we are changing nickname of our local entry we'll enforce
1208 that we will always get the unformatted nickname. Give our
1209 format number to the one that is not formatted now. */
1210 if (unformatted && client_entry == conn->local_entry)
1211 client_entry = unformatted;
1213 silc_free(client_entry->nickname);
1214 client_entry->nickname = newnick;