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; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
22 #include "clientlibincludes.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 uint32 *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;
121 } *GetClientInternal;
123 SILC_CLIENT_CMD_FUNC(get_client_callback)
125 GetClientInternal i = (GetClientInternal)context;
126 SilcClientEntry *clients;
127 uint32 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,
135 clients_count, i->context);
141 static void silc_client_get_client_destructor(void *context)
143 GetClientInternal i = (GetClientInternal)context;
145 if (i->found == FALSE)
146 i->completion(i->client, i->conn, NULL, 0, i->context);
148 silc_free(i->nickname);
149 silc_free(i->server);
153 /* Finds client entry or entries by the `nickname' and `server'. The
154 completion callback will be called when the client entries has been found.
156 Note: this function is always asynchronous and resolves the client
157 information from the server. Thus, if you already know the client
158 information then use the silc_client_get_client_by_id function to
159 get the client entry since this function may be very slow and should
160 be used only to initially get the client entries. */
162 void silc_client_get_clients(SilcClient client,
163 SilcClientConnection conn,
164 const char *nickname,
166 SilcGetClientCallback completion,
175 i = silc_calloc(1, sizeof(*i));
178 i->nickname = strdup(nickname);
179 i->server = server ? strdup(server) : NULL;
180 i->completion = completion;
181 i->context = context;
183 if (nickname && server) {
184 userhost = silc_calloc(strlen(nickname) + strlen(server) + 2,
186 strncat(userhost, nickname, strlen(nickname));
187 strncat(userhost, "@", 1);
188 strncat(userhost, server, strlen(server));
190 userhost = strdup(nickname);
193 /* Register our own command reply for this command */
194 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
195 silc_client_command_reply_identify_i, 0,
198 /* Send the command */
199 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
200 conn->cmd_ident, 1, 1, userhost,
203 /* Add pending callback */
204 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
205 silc_client_get_client_destructor,
206 silc_client_command_get_client_callback,
212 /* The old style function to find client entry. This is used by the
213 library internally. If `query' is TRUE then the client information is
214 requested by the server. The pending command callback must be set
216 /* XXX This function should be removed */
218 SilcClientEntry silc_idlist_get_client(SilcClient client,
219 SilcClientConnection conn,
220 const char *nickname,
224 SilcIDCacheEntry id_cache;
225 SilcIDCacheList list = NULL;
226 SilcClientEntry entry = NULL;
228 SILC_LOG_DEBUG(("Start"));
230 /* Find ID from cache */
231 if (!silc_idcache_find_by_name(conn->client_cache, (char *)nickname,
236 SILC_LOG_DEBUG(("Requesting Client ID from server"));
238 /* Register our own command reply for this command */
239 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
240 silc_client_command_reply_identify_i, 0,
243 /* Send the command */
244 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
245 conn->cmd_ident, 1, 1, nickname,
249 silc_idcache_list_free(list);
257 /* Take first found cache entry */
258 if (!silc_idcache_list_first(list, &id_cache))
261 entry = (SilcClientEntry)id_cache->context;
263 /* Check multiple cache entries for match */
264 silc_idcache_list_first(list, &id_cache);
266 entry = (SilcClientEntry)id_cache->context;
268 if (strcasecmp(entry->nickname, format)) {
269 if (!silc_idcache_list_next(list, &id_cache)) {
281 /* If match weren't found, request it */
287 silc_idcache_list_free(list);
295 SilcClientConnection conn;
297 SilcBuffer client_id_list;
298 SilcGetClientCallback completion;
301 } *GetClientsByListInternal;
303 SILC_CLIENT_CMD_FUNC(get_clients_list_callback)
305 GetClientsByListInternal i = (GetClientsByListInternal)context;
306 SilcIDCacheEntry id_cache = NULL;
307 SilcBuffer client_id_list = i->client_id_list;
308 SilcClientEntry *clients = NULL;
309 uint32 clients_count = 0;
312 SILC_LOG_DEBUG(("Start"));
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);
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);
350 static void silc_client_get_clients_list_destructor(void *context)
352 GetClientsByListInternal i = (GetClientsByListInternal)context;
354 SILC_LOG_DEBUG(("Start"));
356 if (i->found == FALSE)
357 i->completion(i->client, i->conn, NULL, 0, i->context);
359 if (i->client_id_list)
360 silc_buffer_free(i->client_id_list);
364 /* Gets client entries by the list of client ID's `client_id_list'. This
365 always resolves those client ID's it does not know yet from the server
366 so this function might take a while. The `client_id_list' is a list
367 of ID Payloads added one after other. JOIN command reply and USERS
368 command reply for example returns this sort of list. The `completion'
369 will be called after the entries are available. */
371 void silc_client_get_clients_by_list(SilcClient client,
372 SilcClientConnection conn,
374 SilcBuffer client_id_list,
375 SilcGetClientCallback completion,
378 SilcIDCacheEntry id_cache = NULL;
380 unsigned char **res_argv = NULL;
381 uint32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
382 GetClientsByListInternal in;
384 SILC_LOG_DEBUG(("Start"));
386 in = silc_calloc(1, sizeof(*in));
389 in->list_count = list_count;
390 in->client_id_list = silc_buffer_copy(client_id_list);
391 in->completion = completion;
392 in->context = context;
394 for (i = 0; i < list_count; i++) {
396 SilcClientID *client_id;
397 SilcClientEntry entry;
400 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
402 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
404 silc_buffer_pull(client_id_list, idp_len);
408 /* Check if we have this client cached already. */
410 silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
412 silc_hash_client_id_compare, NULL,
415 /* If we don't have the entry or it has incomplete info, then resolve
416 it from the server. */
417 entry = id_cache ? (SilcClientEntry)id_cache->context : NULL;
418 if (!id_cache || !entry->nickname) {
421 if (entry->status & SILC_CLIENT_STATUS_RESOLVING) {
422 entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
423 silc_free(client_id);
424 silc_buffer_pull(client_id_list, idp_len);
428 entry->status |= SILC_CLIENT_STATUS_RESOLVING;
431 /* No we don't have it, query it from the server. Assemble argument
432 table that will be sent fr the IDENTIFY command later. */
433 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
435 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
437 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
439 res_argv[res_argc] = client_id_list->data;
440 res_argv_lens[res_argc] = idp_len;
441 res_argv_types[res_argc] = res_argc + 5;
445 silc_free(client_id);
446 silc_buffer_pull(client_id_list, idp_len);
449 /* Query the client information from server if the list included clients
450 that we don't know about. */
454 /* Send the IDENTIFY command to server */
455 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
456 res_argc, res_argv, res_argv_lens,
457 res_argv_types, ++conn->cmd_ident);
458 silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
459 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
462 /* Register our own command reply for this command */
463 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
464 silc_client_command_reply_identify_i, 0,
467 /* Process the applications request after reply has been received */
468 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
469 silc_client_get_clients_list_destructor,
470 silc_client_command_get_clients_list_callback,
473 silc_buffer_push(client_id_list, client_id_list->data -
474 client_id_list->head);
475 silc_buffer_free(res_cmd);
477 silc_free(res_argv_lens);
478 silc_free(res_argv_types);
482 silc_buffer_push(client_id_list, client_id_list->data -
483 client_id_list->head);
485 /* We have the clients in cache, get them and call the completion */
486 silc_client_command_get_clients_list_callback((void *)in, NULL);
489 /* Finds entry for client by the client's ID. Returns the entry or NULL
490 if the entry was not found. */
492 SilcClientEntry silc_client_get_client_by_id(SilcClient client,
493 SilcClientConnection conn,
494 SilcClientID *client_id)
496 SilcIDCacheEntry id_cache;
498 SILC_LOG_DEBUG(("Finding client by ID (%s)",
499 silc_id_render(client_id, SILC_ID_CLIENT)));
501 /* Find ID from cache */
502 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
504 silc_hash_client_id_compare, NULL,
508 SILC_LOG_DEBUG(("Found"));
510 return (SilcClientEntry)id_cache->context;
515 SilcClientConnection conn;
516 SilcClientID *client_id;
517 SilcGetClientCallback completion;
520 } *GetClientByIDInternal;
522 SILC_CLIENT_CMD_FUNC(get_client_by_id_callback)
524 GetClientByIDInternal i = (GetClientByIDInternal)context;
525 SilcClientEntry entry;
528 entry = silc_client_get_client_by_id(i->client, i->conn,
531 i->completion(i->client, i->conn, &entry, 1, i->context);
536 static void silc_client_get_client_by_id_destructor(void *context)
538 GetClientByIDInternal i = (GetClientByIDInternal)context;
540 if (i->found == FALSE)
541 i->completion(i->client, i->conn, NULL, 0, i->context);
544 silc_free(i->client_id);
548 /* Same as above but will always resolve the information from the server.
549 Use this only if you know that you don't have the entry and the only
550 thing you know about the client is its ID. */
552 void silc_client_get_client_by_id_resolve(SilcClient client,
553 SilcClientConnection conn,
554 SilcClientID *client_id,
555 SilcGetClientCallback completion,
559 GetClientByIDInternal i = silc_calloc(1, sizeof(*i));
561 SILC_LOG_DEBUG(("Start"));
565 i->client_id = silc_id_dup(client_id, SILC_ID_CLIENT);
566 i->completion = completion;
567 i->context = context;
569 /* Register our own command reply for this command */
570 silc_client_command_register(client, SILC_COMMAND_WHOIS, NULL, NULL,
571 silc_client_command_reply_whois_i, 0,
574 /* Send the command */
575 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
576 silc_client_command_send(client, conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
577 1, 3, 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_get_client_by_id_destructor,
583 silc_client_command_get_client_by_id_callback,
588 /******************************************************************************
590 Client, Channel and Server entry manipulation
592 ******************************************************************************/
595 /* Creates new client entry and adds it to the ID cache. Returns pointer
599 silc_client_add_client(SilcClient client, SilcClientConnection conn,
600 char *nickname, char *username,
601 char *userinfo, SilcClientID *id, uint32 mode)
603 SilcClientEntry client_entry;
606 SILC_LOG_DEBUG(("Start"));
608 /* Save the client infos */
609 client_entry = silc_calloc(1, sizeof(*client_entry));
610 client_entry->id = id;
611 client_entry->valid = TRUE;
612 silc_parse_userfqdn(nickname, &nick, &client_entry->server);
613 silc_parse_userfqdn(username, &client_entry->username,
614 &client_entry->hostname);
616 client_entry->realname = strdup(userinfo);
617 client_entry->mode = mode;
619 client_entry->nickname = strdup(nick);
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_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 && username)
653 silc_parse_userfqdn(username, &client_entry->username,
654 &client_entry->hostname);
655 if (!client_entry->realname && userinfo)
656 client_entry->realname = strdup(userinfo);
657 if (!client_entry->nickname && nickname) {
658 silc_parse_userfqdn(nickname, &nick, &client_entry->server);
659 client_entry->nickname = strdup(nick);
660 silc_client_nickname_format(client, conn, client_entry);
662 client_entry->mode = mode;
665 /* Remove the old cache entry and create a new one */
666 silc_idcache_del_by_context(conn->client_cache, client_entry);
667 silc_idcache_add(conn->client_cache, nick, client_entry->id,
668 client_entry, 0, NULL);
672 /* Deletes the client entry and frees all memory. */
674 void silc_client_del_client_entry(SilcClient client,
675 SilcClientConnection conn,
676 SilcClientEntry client_entry)
678 SILC_LOG_DEBUG(("Start"));
680 silc_free(client_entry->nickname);
681 silc_free(client_entry->username);
682 silc_free(client_entry->realname);
683 silc_free(client_entry->server);
684 silc_free(client_entry->id);
685 silc_free(client_entry->fingerprint);
686 if (client_entry->send_key)
687 silc_cipher_free(client_entry->send_key);
688 if (client_entry->receive_key)
689 silc_cipher_free(client_entry->receive_key);
690 silc_free(client_entry->key);
691 silc_client_ftp_session_free_client(conn, client_entry);
692 if (client_entry->ke)
693 silc_client_abort_key_agreement(client, conn, client_entry);
694 silc_free(client_entry);
697 /* Removes client from the cache by the client entry. */
699 bool silc_client_del_client(SilcClient client, SilcClientConnection conn,
700 SilcClientEntry client_entry)
702 bool ret = silc_idcache_del_by_context(conn->client_cache, client_entry);
704 /* Remove from channels */
705 silc_client_remove_from_channels(client, conn, client_entry);
707 /* Free the client entry data */
708 silc_client_del_client_entry(client, conn, client_entry);
713 /* Removes channel from the cache by the channel entry. */
715 bool silc_client_del_channel(SilcClient client, SilcClientConnection conn,
716 SilcChannelEntry channel)
718 bool ret = silc_idcache_del_by_context(conn->channel_cache, channel);
719 silc_free(channel->channel_name);
720 silc_free(channel->id);
721 silc_free(channel->key);
722 if (channel->channel_key)
723 silc_cipher_free(channel->channel_key);
725 silc_hmac_free(channel->hmac);
726 if (channel->old_channel_key)
727 silc_cipher_free(channel->old_channel_key);
728 if (channel->old_hmac)
729 silc_hmac_free(channel->old_hmac);
730 if (channel->rekey_task)
731 silc_schedule_task_del(conn->client->schedule, channel->rekey_task);
732 silc_client_del_channel_private_keys(client, conn, channel);
737 /* Finds entry for channel by the channel name. Returns the entry or NULL
738 if the entry was not found. It is found only if the client is joined
741 SilcChannelEntry silc_client_get_channel(SilcClient client,
742 SilcClientConnection conn,
745 SilcIDCacheEntry id_cache;
746 SilcChannelEntry entry;
748 SILC_LOG_DEBUG(("Start"));
750 if (!silc_idcache_find_by_name_one(conn->channel_cache, channel,
754 entry = (SilcChannelEntry)id_cache->context;
756 SILC_LOG_DEBUG(("Found"));
761 /* Finds entry for channel by the channel ID. Returns the entry or NULL
762 if the entry was not found. It is found only if the client is joined
765 SilcChannelEntry silc_client_get_channel_by_id(SilcClient client,
766 SilcClientConnection conn,
767 SilcChannelID *channel_id)
769 SilcIDCacheEntry id_cache;
770 SilcChannelEntry entry;
772 SILC_LOG_DEBUG(("Start"));
774 if (!silc_idcache_find_by_id_one(conn->channel_cache, channel_id,
778 entry = (SilcChannelEntry)id_cache->context;
780 SILC_LOG_DEBUG(("Found"));
787 SilcClientConnection conn;
788 SilcChannelID *channel_id;
789 SilcGetChannelCallback completion;
792 } *GetChannelByIDInternal;
794 SILC_CLIENT_CMD_FUNC(get_channel_by_id_callback)
796 GetChannelByIDInternal i = (GetChannelByIDInternal)context;
797 SilcChannelEntry entry;
799 SILC_LOG_DEBUG(("Start"));
801 /* Get the channel */
802 entry = silc_client_get_channel_by_id(i->client, i->conn,
805 i->completion(i->client, i->conn, &entry, 1, i->context);
810 static void silc_client_get_channel_by_id_destructor(void *context)
812 GetChannelByIDInternal i = (GetChannelByIDInternal)context;
814 if (i->found == FALSE)
815 i->completion(i->client, i->conn, NULL, 0, i->context);
817 silc_free(i->channel_id);
821 /* Resolves channel information from the server by the channel ID. */
823 void silc_client_get_channel_by_id_resolve(SilcClient client,
824 SilcClientConnection conn,
825 SilcChannelID *channel_id,
826 SilcGetChannelCallback completion,
830 GetChannelByIDInternal i = silc_calloc(1, sizeof(*i));
832 SILC_LOG_DEBUG(("Start"));
836 i->channel_id = silc_id_dup(channel_id, SILC_ID_CHANNEL);
837 i->completion = completion;
838 i->context = context;
840 /* Register our own command reply for this command */
841 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
842 silc_client_command_reply_identify_i, 0,
845 /* Send the command */
846 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
847 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
849 1, 5, idp->data, idp->len);
850 silc_buffer_free(idp);
852 /* Add pending callback */
853 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
854 silc_client_get_channel_by_id_destructor,
855 silc_client_command_get_channel_by_id_callback,
859 /* Find channel entry by ID. This routine is used internally by the library. */
861 SilcChannelEntry silc_idlist_get_channel_by_id(SilcClient client,
862 SilcClientConnection conn,
863 SilcChannelID *channel_id,
867 SilcChannelEntry channel;
869 SILC_LOG_DEBUG(("Start"));
871 channel = silc_client_get_channel_by_id(client, conn, channel_id);
876 /* Register our own command reply for this command */
877 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
878 silc_client_command_reply_identify_i, 0,
881 /* Send the command */
882 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
883 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
885 1, 5, idp->data, idp->len);
886 silc_buffer_free(idp);
892 /* Finds entry for server by the server name. */
894 SilcServerEntry silc_client_get_server(SilcClient client,
895 SilcClientConnection conn,
898 SilcIDCacheEntry id_cache;
899 SilcServerEntry entry;
901 SILC_LOG_DEBUG(("Start"));
903 if (!silc_idcache_find_by_name_one(conn->server_cache, server_name,
907 entry = (SilcServerEntry)id_cache->context;
912 /* Finds entry for server by the server ID. */
914 SilcServerEntry silc_client_get_server_by_id(SilcClient client,
915 SilcClientConnection conn,
916 SilcServerID *server_id)
918 SilcIDCacheEntry id_cache;
919 SilcServerEntry entry;
921 SILC_LOG_DEBUG(("Start"));
923 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
927 entry = (SilcServerEntry)id_cache->context;
932 /* Removes server from the cache by the server entry. */
934 bool silc_client_del_server(SilcClient client, SilcClientConnection conn,
935 SilcServerEntry server)
937 bool ret = silc_idcache_del_by_context(conn->server_cache, server);
938 silc_free(server->server_name);
939 silc_free(server->server_info);
940 silc_free(server->server_id);
945 /* Formats the nickname of the client specified by the `client_entry'.
946 If the format is specified by the application this will format the
947 nickname and replace the old nickname in the client entry. If the
948 format string is not specified then this function has no effect. */
950 void silc_client_nickname_format(SilcClient client,
951 SilcClientConnection conn,
952 SilcClientEntry client_entry)
955 char *newnick = NULL;
957 SilcClientEntry *clients;
958 uint32 clients_count = 0;
960 SILC_LOG_DEBUG(("Start"));
962 if (!client->internal->params->nickname_format[0])
965 if (!client_entry->nickname)
968 /* Get all clients with same nickname. Do not perform the formatting
969 if there aren't any clients with same nickname unless the application
970 is forcing us to do so. */
971 clients = silc_client_get_clients_local(client, conn,
972 client_entry->nickname, NULL,
974 if (!clients && !client->internal->params->nickname_force_format)
978 for (i = 0; i < clients_count; i++)
979 if (clients[i]->valid && clients[i] != client_entry)
984 cp = client->internal->params->nickname_format;
994 if (!client_entry->nickname)
996 len = strlen(client_entry->nickname);
997 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
998 memcpy(&newnick[off], client_entry->nickname, len);
1002 /* Stripped hostname */
1003 if (!client_entry->hostname)
1005 len = strcspn(client_entry->hostname, ".");
1006 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1007 memcpy(&newnick[off], client_entry->hostname, len);
1012 if (!client_entry->hostname)
1014 len = strlen(client_entry->hostname);
1015 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1016 memcpy(&newnick[off], client_entry->hostname, len);
1020 /* Stripped server name */
1021 if (!client_entry->server)
1023 len = strcspn(client_entry->server, ".");
1024 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1025 memcpy(&newnick[off], client_entry->server, len);
1029 /* Full server name */
1030 if (!client_entry->server)
1032 len = strlen(client_entry->server);
1033 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1034 memcpy(&newnick[off], client_entry->server, len);
1038 /* Ascending number */
1043 if (clients_count == 1)
1046 for (i = 0; i < clients_count; i++) {
1047 if (strncasecmp(clients[i]->nickname, newnick, off))
1049 if (strlen(clients[i]->nickname) <= off)
1051 num = atoi(&clients[i]->nickname[off]);
1056 memset(tmp, 0, sizeof(tmp));
1057 snprintf(tmp, sizeof(tmp) - 1, "%d", ++max);
1059 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1060 memcpy(&newnick[off], tmp, len);
1065 /* Some other character in the string */
1066 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
1067 memcpy(&newnick[off], cp, 1);
1075 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
1078 silc_free(client_entry->nickname);
1079 client_entry->nickname = newnick;