5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2001 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);
703 silc_client_del_client_entry(client, conn, client_entry);
707 /* Removes channel from the cache by the channel entry. */
709 bool silc_client_del_channel(SilcClient client, SilcClientConnection conn,
710 SilcChannelEntry channel)
712 bool ret = silc_idcache_del_by_context(conn->channel_cache, channel);
713 silc_free(channel->channel_name);
714 silc_free(channel->id);
715 silc_free(channel->key);
716 if (channel->channel_key)
717 silc_cipher_free(channel->channel_key);
719 silc_hmac_free(channel->hmac);
720 if (channel->old_channel_key)
721 silc_cipher_free(channel->old_channel_key);
722 if (channel->old_hmac)
723 silc_hmac_free(channel->old_hmac);
724 if (channel->rekey_task)
725 silc_schedule_task_del(conn->client->schedule, channel->rekey_task);
726 silc_client_del_channel_private_keys(client, conn, channel);
731 /* Finds entry for channel by the channel name. Returns the entry or NULL
732 if the entry was not found. It is found only if the client is joined
735 SilcChannelEntry silc_client_get_channel(SilcClient client,
736 SilcClientConnection conn,
739 SilcIDCacheEntry id_cache;
740 SilcChannelEntry entry;
742 SILC_LOG_DEBUG(("Start"));
744 if (!silc_idcache_find_by_name_one(conn->channel_cache, channel,
748 entry = (SilcChannelEntry)id_cache->context;
750 SILC_LOG_DEBUG(("Found"));
755 /* Finds entry for channel by the channel ID. Returns the entry or NULL
756 if the entry was not found. It is found only if the client is joined
759 SilcChannelEntry silc_client_get_channel_by_id(SilcClient client,
760 SilcClientConnection conn,
761 SilcChannelID *channel_id)
763 SilcIDCacheEntry id_cache;
764 SilcChannelEntry entry;
766 SILC_LOG_DEBUG(("Start"));
768 if (!silc_idcache_find_by_id_one(conn->channel_cache, channel_id,
772 entry = (SilcChannelEntry)id_cache->context;
774 SILC_LOG_DEBUG(("Found"));
781 SilcClientConnection conn;
782 SilcChannelID *channel_id;
783 SilcGetChannelCallback completion;
786 } *GetChannelByIDInternal;
788 SILC_CLIENT_CMD_FUNC(get_channel_by_id_callback)
790 GetChannelByIDInternal i = (GetChannelByIDInternal)context;
791 SilcChannelEntry entry;
793 SILC_LOG_DEBUG(("Start"));
795 /* Get the channel */
796 entry = silc_client_get_channel_by_id(i->client, i->conn,
799 i->completion(i->client, i->conn, &entry, 1, i->context);
804 static void silc_client_get_channel_by_id_destructor(void *context)
806 GetChannelByIDInternal i = (GetChannelByIDInternal)context;
808 if (i->found == FALSE)
809 i->completion(i->client, i->conn, NULL, 0, i->context);
811 silc_free(i->channel_id);
815 /* Resolves channel information from the server by the channel ID. */
817 void silc_client_get_channel_by_id_resolve(SilcClient client,
818 SilcClientConnection conn,
819 SilcChannelID *channel_id,
820 SilcGetChannelCallback completion,
824 GetChannelByIDInternal i = silc_calloc(1, sizeof(*i));
826 SILC_LOG_DEBUG(("Start"));
830 i->channel_id = silc_id_dup(channel_id, SILC_ID_CHANNEL);
831 i->completion = completion;
832 i->context = context;
834 /* Register our own command reply for this command */
835 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
836 silc_client_command_reply_identify_i, 0,
839 /* Send the command */
840 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
841 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
843 1, 5, idp->data, idp->len);
844 silc_buffer_free(idp);
846 /* Add pending callback */
847 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
848 silc_client_get_channel_by_id_destructor,
849 silc_client_command_get_channel_by_id_callback,
853 /* Find channel entry by ID. This routine is used internally by the library. */
855 SilcChannelEntry silc_idlist_get_channel_by_id(SilcClient client,
856 SilcClientConnection conn,
857 SilcChannelID *channel_id,
861 SilcChannelEntry channel;
863 SILC_LOG_DEBUG(("Start"));
865 channel = silc_client_get_channel_by_id(client, conn, channel_id);
870 /* Register our own command reply for this command */
871 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
872 silc_client_command_reply_identify_i, 0,
875 /* Send the command */
876 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
877 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
879 1, 5, idp->data, idp->len);
880 silc_buffer_free(idp);
886 /* Finds entry for server by the server name. */
888 SilcServerEntry silc_client_get_server(SilcClient client,
889 SilcClientConnection conn,
892 SilcIDCacheEntry id_cache;
893 SilcServerEntry entry;
895 SILC_LOG_DEBUG(("Start"));
897 if (!silc_idcache_find_by_name_one(conn->server_cache, server_name,
901 entry = (SilcServerEntry)id_cache->context;
906 /* Finds entry for server by the server ID. */
908 SilcServerEntry silc_client_get_server_by_id(SilcClient client,
909 SilcClientConnection conn,
910 SilcServerID *server_id)
912 SilcIDCacheEntry id_cache;
913 SilcServerEntry entry;
915 SILC_LOG_DEBUG(("Start"));
917 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
921 entry = (SilcServerEntry)id_cache->context;
926 /* Removes server from the cache by the server entry. */
928 bool silc_client_del_server(SilcClient client, SilcClientConnection conn,
929 SilcServerEntry server)
931 bool ret = silc_idcache_del_by_context(conn->server_cache, server);
932 silc_free(server->server_name);
933 silc_free(server->server_info);
934 silc_free(server->server_id);
939 /* Formats the nickname of the client specified by the `client_entry'.
940 If the format is specified by the application this will format the
941 nickname and replace the old nickname in the client entry. If the
942 format string is not specified then this function has no effect. */
944 void silc_client_nickname_format(SilcClient client,
945 SilcClientConnection conn,
946 SilcClientEntry client_entry)
949 char *newnick = NULL;
951 SilcClientEntry *clients;
952 uint32 clients_count = 0;
954 SILC_LOG_DEBUG(("Start"));
956 if (!client->internal->params->nickname_format[0])
959 if (!client_entry->nickname)
962 /* Get all clients with same nickname. Do not perform the formatting
963 if there aren't any clients with same nickname unless the application
964 is forcing us to do so. */
965 clients = silc_client_get_clients_local(client, conn,
966 client_entry->nickname, NULL,
968 if (!clients && !client->internal->params->nickname_force_format)
972 for (i = 0; i < clients_count; i++)
973 if (clients[i]->valid && clients[i] != client_entry)
978 cp = client->internal->params->nickname_format;
988 if (!client_entry->nickname)
990 len = strlen(client_entry->nickname);
991 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
992 memcpy(&newnick[off], client_entry->nickname, len);
996 /* Stripped hostname */
997 if (!client_entry->hostname)
999 len = strcspn(client_entry->hostname, ".");
1000 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1001 memcpy(&newnick[off], client_entry->hostname, len);
1006 if (!client_entry->hostname)
1008 len = strlen(client_entry->hostname);
1009 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1010 memcpy(&newnick[off], client_entry->hostname, len);
1014 /* Stripped server name */
1015 if (!client_entry->server)
1017 len = strcspn(client_entry->server, ".");
1018 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1019 memcpy(&newnick[off], client_entry->server, len);
1023 /* Full server name */
1024 if (!client_entry->server)
1026 len = strlen(client_entry->server);
1027 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1028 memcpy(&newnick[off], client_entry->server, len);
1032 /* Ascending number */
1037 if (clients_count == 1)
1040 for (i = 0; i < clients_count; i++) {
1041 if (strncasecmp(clients[i]->nickname, newnick, off))
1043 if (strlen(clients[i]->nickname) <= off)
1045 num = atoi(&clients[i]->nickname[off]);
1050 memset(tmp, 0, sizeof(tmp));
1051 snprintf(tmp, sizeof(tmp) - 1, "%d", ++max);
1053 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1054 memcpy(&newnick[off], tmp, len);
1059 /* Some other character in the string */
1060 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
1061 memcpy(&newnick[off], cp, 1);
1069 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
1072 silc_free(client_entry->nickname);
1073 client_entry->nickname = newnick;