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;
120 } *GetClientInternal;
122 SILC_CLIENT_CMD_FUNC(get_client_callback)
124 GetClientInternal i = (GetClientInternal)context;
125 SilcClientEntry *clients;
126 uint32 clients_count;
128 /* Get the clients */
129 clients = silc_client_get_clients_local(i->client, i->conn,
130 i->nickname, i->server,
133 i->completion(i->client, i->conn, clients, clients_count, i->context);
136 i->completion(i->client, i->conn, NULL, 0, i->context);
139 silc_free(i->nickname);
140 silc_free(i->server);
144 /* Finds client entry or entries by the `nickname' and `server'. The
145 completion callback will be called when the client entries has been found.
147 Note: this function is always asynchronous and resolves the client
148 information from the server. Thus, if you already know the client
149 information then use the silc_client_get_client_by_id function to
150 get the client entry since this function may be very slow and should
151 be used only to initially get the client entries. */
153 void silc_client_get_clients(SilcClient client,
154 SilcClientConnection conn,
155 const char *nickname,
157 SilcGetClientCallback completion,
166 i = silc_calloc(1, sizeof(*i));
169 i->nickname = strdup(nickname);
170 i->server = server ? strdup(server) : NULL;
171 i->completion = completion;
172 i->context = context;
174 if (nickname && server) {
175 userhost = silc_calloc(strlen(nickname) + strlen(server) + 2,
177 strncat(userhost, nickname, strlen(nickname));
178 strncat(userhost, "@", 1);
179 strncat(userhost, server, strlen(server));
181 userhost = strdup(nickname);
184 /* Register our own command reply for this command */
185 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
186 silc_client_command_reply_identify_i, 0,
189 /* Send the command */
190 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
191 conn->cmd_ident, 1, 1, userhost,
194 /* Add pending callback */
195 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
196 silc_client_command_get_client_callback,
202 /* The old style function to find client entry. This is used by the
203 library internally. If `query' is TRUE then the client information is
204 requested by the server. The pending command callback must be set
206 /* XXX This function should be removed */
208 SilcClientEntry silc_idlist_get_client(SilcClient client,
209 SilcClientConnection conn,
210 const char *nickname,
214 SilcIDCacheEntry id_cache;
215 SilcIDCacheList list = NULL;
216 SilcClientEntry entry = NULL;
218 SILC_LOG_DEBUG(("Start"));
220 /* Find ID from cache */
221 if (!silc_idcache_find_by_name(conn->client_cache, (char *)nickname,
226 SILC_LOG_DEBUG(("Requesting Client ID from server"));
228 /* Register our own command reply for this command */
229 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
230 silc_client_command_reply_identify_i, 0,
233 /* Send the command */
234 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
235 conn->cmd_ident, 1, 1, nickname,
239 silc_idcache_list_free(list);
247 /* Take first found cache entry */
248 if (!silc_idcache_list_first(list, &id_cache))
251 entry = (SilcClientEntry)id_cache->context;
253 /* Check multiple cache entries for match */
254 silc_idcache_list_first(list, &id_cache);
256 entry = (SilcClientEntry)id_cache->context;
258 if (strcasecmp(entry->nickname, format)) {
259 if (!silc_idcache_list_next(list, &id_cache)) {
271 /* If match weren't found, request it */
277 silc_idcache_list_free(list);
285 SilcClientConnection conn;
287 SilcBuffer client_id_list;
288 SilcGetClientCallback completion;
290 } *GetClientsByListInternal;
292 SILC_CLIENT_CMD_FUNC(get_clients_list_callback)
294 GetClientsByListInternal i = (GetClientsByListInternal)context;
295 SilcIDCacheEntry id_cache = NULL;
296 SilcBuffer client_id_list = i->client_id_list;
297 SilcClientEntry *clients = NULL;
298 uint32 clients_count = 0;
302 SILC_LOG_DEBUG(("Start"));
304 for (c = 0; c < i->list_count; c++) {
306 SilcClientID *client_id;
309 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
311 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
313 silc_buffer_pull(client_id_list, idp_len);
317 /* Get the client entry */
318 if (silc_idcache_find_by_id_one_ext(i->conn->client_cache,
321 silc_hash_client_id_compare, NULL,
323 clients = silc_realloc(clients, sizeof(*clients) *
324 (clients_count + 1));
325 clients[clients_count] = (SilcClientEntry)id_cache->context;
330 silc_free(client_id);
331 silc_buffer_pull(client_id_list, idp_len);
335 i->completion(i->client, i->conn, clients, clients_count, i->context);
338 i->completion(i->client, i->conn, NULL, 0, i->context);
341 if (i->client_id_list)
342 silc_buffer_free(i->client_id_list);
346 /* Gets client entries by the list of client ID's `client_id_list'. This
347 always resolves those client ID's it does not know yet from the server
348 so this function might take a while. The `client_id_list' is a list
349 of ID Payloads added one after other. JOIN command reply and USERS
350 command reply for example returns this sort of list. The `completion'
351 will be called after the entries are available. */
353 void silc_client_get_clients_by_list(SilcClient client,
354 SilcClientConnection conn,
356 SilcBuffer client_id_list,
357 SilcGetClientCallback completion,
360 SilcIDCacheEntry id_cache = NULL;
362 unsigned char **res_argv = NULL;
363 uint32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
364 GetClientsByListInternal in;
366 SILC_LOG_DEBUG(("Start"));
368 in = silc_calloc(1, sizeof(*in));
371 in->list_count = list_count;
372 in->client_id_list = silc_buffer_copy(client_id_list);
373 in->completion = completion;
374 in->context = context;
376 for (i = 0; i < list_count; i++) {
378 SilcClientID *client_id;
379 SilcClientEntry entry;
382 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
384 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
386 silc_buffer_pull(client_id_list, idp_len);
390 /* Check if we have this client cached already. */
392 silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
394 silc_hash_client_id_compare, NULL,
397 /* If we don't have the entry or it has incomplete info, then resolve
398 it from the server. */
399 entry = id_cache ? (SilcClientEntry)id_cache->context : NULL;
400 if (!id_cache || !entry->nickname) {
403 if (entry->status & SILC_CLIENT_STATUS_RESOLVING) {
404 entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
405 silc_free(client_id);
406 silc_buffer_pull(client_id_list, idp_len);
410 entry->status |= SILC_CLIENT_STATUS_RESOLVING;
413 /* No we don't have it, query it from the server. Assemble argument
414 table that will be sent fr the IDENTIFY command later. */
415 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
417 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
419 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
421 res_argv[res_argc] = client_id_list->data;
422 res_argv_lens[res_argc] = idp_len;
423 res_argv_types[res_argc] = res_argc + 5;
427 silc_free(client_id);
428 silc_buffer_pull(client_id_list, idp_len);
431 /* Query the client information from server if the list included clients
432 that we don't know about. */
436 /* Send the IDENTIFY command to server */
437 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
438 res_argc, res_argv, res_argv_lens,
439 res_argv_types, ++conn->cmd_ident);
440 silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
441 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
444 /* Register our own command reply for this command */
445 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
446 silc_client_command_reply_identify_i, 0,
449 /* Process the applications request after reply has been received */
450 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
451 silc_client_command_get_clients_list_callback,
454 silc_buffer_push(client_id_list, client_id_list->data -
455 client_id_list->head);
456 silc_buffer_free(res_cmd);
458 silc_free(res_argv_lens);
459 silc_free(res_argv_types);
463 silc_buffer_push(client_id_list, client_id_list->data -
464 client_id_list->head);
466 /* We have the clients in cache, get them and call the completion */
467 silc_client_command_get_clients_list_callback((void *)in, NULL);
470 /* Finds entry for client by the client's ID. Returns the entry or NULL
471 if the entry was not found. */
473 SilcClientEntry silc_client_get_client_by_id(SilcClient client,
474 SilcClientConnection conn,
475 SilcClientID *client_id)
477 SilcIDCacheEntry id_cache;
479 SILC_LOG_DEBUG(("Finding client by ID (%s)",
480 silc_id_render(client_id, SILC_ID_CLIENT)));
482 /* Find ID from cache */
483 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
485 silc_hash_client_id_compare, NULL,
489 SILC_LOG_DEBUG(("Found"));
491 return (SilcClientEntry)id_cache->context;
496 SilcClientConnection conn;
497 SilcClientID *client_id;
498 SilcGetClientCallback completion;
500 } *GetClientByIDInternal;
502 SILC_CLIENT_CMD_FUNC(get_client_by_id_callback)
504 GetClientByIDInternal i = (GetClientByIDInternal)context;
505 SilcClientEntry entry;
508 entry = silc_client_get_client_by_id(i->client, i->conn, i->client_id);
510 i->completion(i->client, i->conn, &entry, 1, i->context);
512 i->completion(i->client, i->conn, NULL, 0, i->context);
514 silc_free(i->client_id);
518 /* Same as above but will always resolve the information from the server.
519 Use this only if you know that you don't have the entry and the only
520 thing you know about the client is its ID. */
522 void silc_client_get_client_by_id_resolve(SilcClient client,
523 SilcClientConnection conn,
524 SilcClientID *client_id,
525 SilcGetClientCallback completion,
529 GetClientByIDInternal i = silc_calloc(1, sizeof(*i));
531 SILC_LOG_DEBUG(("Start"));
535 i->client_id = silc_id_dup(client_id, SILC_ID_CLIENT);
536 i->completion = completion;
537 i->context = context;
539 /* Register our own command reply for this command */
540 silc_client_command_register(client, SILC_COMMAND_WHOIS, NULL, NULL,
541 silc_client_command_reply_whois_i, 0,
544 /* Send the command */
545 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
546 silc_client_command_send(client, conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
547 1, 3, idp->data, idp->len);
548 silc_buffer_free(idp);
550 /* Add pending callback */
551 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
552 silc_client_command_get_client_by_id_callback,
557 /******************************************************************************
559 Client, Channel and Server entry manipulation
561 ******************************************************************************/
564 /* Creates new client entry and adds it to the ID cache. Returns pointer
568 silc_client_add_client(SilcClient client, SilcClientConnection conn,
569 char *nickname, char *username,
570 char *userinfo, SilcClientID *id, uint32 mode)
572 SilcClientEntry client_entry;
575 SILC_LOG_DEBUG(("Start"));
577 /* Save the client infos */
578 client_entry = silc_calloc(1, sizeof(*client_entry));
579 client_entry->id = id;
580 client_entry->valid = TRUE;
581 silc_parse_userfqdn(nickname, &nick, &client_entry->server);
582 silc_parse_userfqdn(username, &client_entry->username,
583 &client_entry->hostname);
585 client_entry->realname = strdup(userinfo);
586 client_entry->mode = mode;
588 client_entry->nickname = strdup(nick);
590 /* Format the nickname */
591 silc_client_nickname_format(client, conn, client_entry);
593 /* Add client to cache, the non-formatted nickname is saved to cache */
594 if (!silc_idcache_add(conn->client_cache, nick, client_entry->id,
595 (void *)client_entry, 0, NULL)) {
596 silc_free(client_entry->nickname);
597 silc_free(client_entry->username);
598 silc_free(client_entry->hostname);
599 silc_free(client_entry->server);
600 silc_free(client_entry);
607 /* Updates the `client_entry' with the new information sent as argument. */
609 void silc_client_update_client(SilcClient client,
610 SilcClientConnection conn,
611 SilcClientEntry client_entry,
612 const char *nickname,
613 const char *username,
614 const char *userinfo,
619 SILC_LOG_DEBUG(("Start"));
621 if (!client_entry->username && username)
622 silc_parse_userfqdn(username, &client_entry->username,
623 &client_entry->hostname);
624 if (!client_entry->realname && userinfo)
625 client_entry->realname = strdup(userinfo);
626 if (!client_entry->nickname && nickname) {
627 silc_parse_userfqdn(nickname, &nick, &client_entry->server);
628 client_entry->nickname = strdup(nick);
629 silc_client_nickname_format(client, conn, client_entry);
631 client_entry->mode = mode;
634 /* Remove the old cache entry and create a new one */
635 silc_idcache_del_by_context(conn->client_cache, client_entry);
636 silc_idcache_add(conn->client_cache, nick, client_entry->id,
637 client_entry, 0, NULL);
641 /* Deletes the client entry and frees all memory. */
643 void silc_client_del_client_entry(SilcClient client,
644 SilcClientConnection conn,
645 SilcClientEntry client_entry)
647 SILC_LOG_DEBUG(("Start"));
649 silc_free(client_entry->nickname);
650 silc_free(client_entry->username);
651 silc_free(client_entry->realname);
652 silc_free(client_entry->hostname);
653 silc_free(client_entry->server);
654 silc_free(client_entry->id);
655 silc_free(client_entry->fingerprint);
656 if (client_entry->send_key)
657 silc_cipher_free(client_entry->send_key);
658 if (client_entry->receive_key)
659 silc_cipher_free(client_entry->receive_key);
660 silc_free(client_entry->key);
661 silc_client_ftp_session_free_client(conn, client_entry);
662 if (client_entry->ke)
663 silc_client_abort_key_agreement(client, conn, client_entry);
664 silc_free(client_entry);
667 /* Removes client from the cache by the client entry. */
669 bool silc_client_del_client(SilcClient client, SilcClientConnection conn,
670 SilcClientEntry client_entry)
672 bool ret = silc_idcache_del_by_context(conn->client_cache, client_entry);
674 /* Remove from channels */
675 silc_client_remove_from_channels(client, conn, client_entry);
677 /* Free the client entry data */
678 silc_client_del_client_entry(client, conn, client_entry);
683 /* Removes channel from the cache by the channel entry. */
685 bool silc_client_del_channel(SilcClient client, SilcClientConnection conn,
686 SilcChannelEntry channel)
688 bool ret = silc_idcache_del_by_context(conn->channel_cache, channel);
689 silc_free(channel->channel_name);
690 silc_free(channel->id);
691 silc_free(channel->key);
692 if (channel->channel_key)
693 silc_cipher_free(channel->channel_key);
695 silc_hmac_free(channel->hmac);
696 if (channel->old_channel_key)
697 silc_cipher_free(channel->old_channel_key);
698 if (channel->old_hmac)
699 silc_hmac_free(channel->old_hmac);
700 if (channel->rekey_task)
701 silc_schedule_task_del(conn->client->schedule, channel->rekey_task);
702 silc_client_del_channel_private_keys(client, conn, channel);
707 /* Finds entry for channel by the channel name. Returns the entry or NULL
708 if the entry was not found. It is found only if the client is joined
711 SilcChannelEntry silc_client_get_channel(SilcClient client,
712 SilcClientConnection conn,
715 SilcIDCacheEntry id_cache;
716 SilcChannelEntry entry;
718 SILC_LOG_DEBUG(("Start"));
720 if (!silc_idcache_find_by_name_one(conn->channel_cache, channel,
724 entry = (SilcChannelEntry)id_cache->context;
726 SILC_LOG_DEBUG(("Found"));
731 /* Finds entry for channel by the channel ID. 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_by_id(SilcClient client,
736 SilcClientConnection conn,
737 SilcChannelID *channel_id)
739 SilcIDCacheEntry id_cache;
740 SilcChannelEntry entry;
742 SILC_LOG_DEBUG(("Start"));
744 if (!silc_idcache_find_by_id_one(conn->channel_cache, channel_id,
748 entry = (SilcChannelEntry)id_cache->context;
750 SILC_LOG_DEBUG(("Found"));
757 SilcClientConnection conn;
758 SilcChannelID *channel_id;
759 SilcGetChannelCallback completion;
761 } *GetChannelByIDInternal;
763 SILC_CLIENT_CMD_FUNC(get_channel_by_id_callback)
765 GetChannelByIDInternal i = (GetChannelByIDInternal)context;
766 SilcChannelEntry entry;
768 SILC_LOG_DEBUG(("Start"));
770 /* Get the channel */
771 entry = silc_client_get_channel_by_id(i->client, i->conn, i->channel_id);
773 i->completion(i->client, i->conn, &entry, 1, i->context);
775 i->completion(i->client, i->conn, NULL, 0, i->context);
778 silc_free(i->channel_id);
782 /* Resolves channel information from the server by the channel ID. */
784 void silc_client_get_channel_by_id_resolve(SilcClient client,
785 SilcClientConnection conn,
786 SilcChannelID *channel_id,
787 SilcGetChannelCallback completion,
791 GetChannelByIDInternal i = silc_calloc(1, sizeof(*i));
793 SILC_LOG_DEBUG(("Start"));
797 i->channel_id = silc_id_dup(channel_id, SILC_ID_CHANNEL);
798 i->completion = completion;
799 i->context = context;
801 /* Register our own command reply for this command */
802 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
803 silc_client_command_reply_identify_i, 0,
806 /* Send the command */
807 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
808 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
810 1, 5, idp->data, idp->len);
811 silc_buffer_free(idp);
813 /* Add pending callback */
814 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
815 silc_client_command_get_channel_by_id_callback,
819 /* Find channel entry by ID. This routine is used internally by the library. */
821 SilcChannelEntry silc_idlist_get_channel_by_id(SilcClient client,
822 SilcClientConnection conn,
823 SilcChannelID *channel_id,
827 SilcChannelEntry channel;
829 SILC_LOG_DEBUG(("Start"));
831 channel = silc_client_get_channel_by_id(client, conn, channel_id);
836 /* Register our own command reply for this command */
837 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
838 silc_client_command_reply_identify_i, 0,
841 /* Send the command */
842 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
843 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
845 1, 5, idp->data, idp->len);
846 silc_buffer_free(idp);
852 /* Finds entry for server by the server name. */
854 SilcServerEntry silc_client_get_server(SilcClient client,
855 SilcClientConnection conn,
858 SilcIDCacheEntry id_cache;
859 SilcServerEntry entry;
861 SILC_LOG_DEBUG(("Start"));
863 if (!silc_idcache_find_by_name_one(conn->server_cache, server_name,
867 entry = (SilcServerEntry)id_cache->context;
872 /* Finds entry for server by the server ID. */
874 SilcServerEntry silc_client_get_server_by_id(SilcClient client,
875 SilcClientConnection conn,
876 SilcServerID *server_id)
878 SilcIDCacheEntry id_cache;
879 SilcServerEntry entry;
881 SILC_LOG_DEBUG(("Start"));
883 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
887 entry = (SilcServerEntry)id_cache->context;
892 /* Removes server from the cache by the server entry. */
894 bool silc_client_del_server(SilcClient client, SilcClientConnection conn,
895 SilcServerEntry server)
897 bool ret = silc_idcache_del_by_context(conn->server_cache, server);
898 silc_free(server->server_name);
899 silc_free(server->server_info);
900 silc_free(server->server_id);
905 /* Formats the nickname of the client specified by the `client_entry'.
906 If the format is specified by the application this will format the
907 nickname and replace the old nickname in the client entry. If the
908 format string is not specified then this function has no effect. */
910 void silc_client_nickname_format(SilcClient client,
911 SilcClientConnection conn,
912 SilcClientEntry client_entry)
915 char *newnick = NULL;
917 SilcClientEntry *clients;
918 uint32 clients_count = 0;
919 SilcClientEntry unformatted = NULL;
921 SILC_LOG_DEBUG(("Start"));
923 if (!client->internal->params->nickname_format[0])
926 if (!client_entry->nickname)
929 /* Get all clients with same nickname. Do not perform the formatting
930 if there aren't any clients with same nickname unless the application
931 is forcing us to do so. */
932 clients = silc_client_get_clients_local(client, conn,
933 client_entry->nickname, NULL,
935 if (!clients && !client->internal->params->nickname_force_format)
939 for (i = 0; i < clients_count; i++)
940 if (clients[i]->valid && clients[i] != client_entry)
945 cp = client->internal->params->nickname_format;
955 if (!client_entry->nickname)
957 len = strlen(client_entry->nickname);
958 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
959 memcpy(&newnick[off], client_entry->nickname, len);
963 /* Stripped hostname */
964 if (!client_entry->hostname)
966 len = strcspn(client_entry->hostname, ".");
967 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
968 memcpy(&newnick[off], client_entry->hostname, len);
973 if (!client_entry->hostname)
975 len = strlen(client_entry->hostname);
976 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
977 memcpy(&newnick[off], client_entry->hostname, len);
981 /* Stripped server name */
982 if (!client_entry->server)
984 len = strcspn(client_entry->server, ".");
985 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
986 memcpy(&newnick[off], client_entry->server, len);
990 /* Full server name */
991 if (!client_entry->server)
993 len = strlen(client_entry->server);
994 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
995 memcpy(&newnick[off], client_entry->server, len);
999 /* Ascending number */
1004 if (clients_count == 1) {
1005 unformatted = clients[0];
1009 for (i = 0; i < clients_count; i++) {
1010 if (!strncasecmp(clients[i]->nickname, client_entry->nickname,
1011 strlen(clients[i]->nickname)))
1012 unformatted = clients[i];
1013 if (strncasecmp(clients[i]->nickname, newnick, off))
1015 if (strlen(clients[i]->nickname) <= off)
1017 num = atoi(&clients[i]->nickname[off]);
1022 memset(tmp, 0, sizeof(tmp));
1023 snprintf(tmp, sizeof(tmp) - 1, "%d", ++max);
1025 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1026 memcpy(&newnick[off], tmp, len);
1031 /* Some other character in the string */
1032 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
1033 memcpy(&newnick[off], cp, 1);
1041 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
1044 /* If we are changing nickname of our local entry we'll enforce
1045 that we will always get the unformatted nickname. Give our
1046 format number to the one that is not formatted now. */
1047 if (unformatted && client_entry == conn->local_entry)
1048 client_entry = unformatted;
1050 silc_free(client_entry->nickname);
1051 client_entry->nickname = newnick;