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"
26 SilcClientCommandContext cmd;
27 SilcGetClientCallback completion;
34 SILC_CLIENT_CMD_FUNC(get_client_callback)
36 GetClientInternal i = (GetClientInternal)context;
37 SilcClientEntry *clients;
41 clients = silc_client_get_clients_local(i->cmd->client, i->cmd->conn,
42 i->nickname, i->server,
45 i->completion(i->cmd->client, i->cmd->conn, clients,
46 clients_count, i->context);
52 static void silc_client_get_client_destructor(void *context)
54 GetClientInternal i = (GetClientInternal)context;
56 if (i->found == FALSE)
57 i->completion(i->cmd->client, i->cmd->conn, NULL, 0, i->context);
59 silc_client_command_free(i->cmd);
61 silc_free(i->nickname);
67 /* Finds client entry or entries by the `nickname' and `server'. The
68 completion callback will be called when the client entries has been found.
70 Note: this function is always asynchronous and resolves the client
71 information from the server. Thus, if you already know the client
72 information then use the silc_client_get_client_by_id function to
73 get the client entry since this function may be very slow and should
74 be used only to initially get the client entries. */
76 void silc_client_get_clients(SilcClient client,
77 SilcClientConnection conn,
80 SilcGetClientCallback completion,
84 SilcClientCommandContext ctx;
85 GetClientInternal i = silc_calloc(1, sizeof(*i));
87 /* No ID found. Do query from the server. The query is done by
88 sending simple IDENTIFY command to the server. */
89 ctx = silc_client_command_alloc();
92 ctx->command = silc_client_command_find("IDENTIFY");
93 memset(ident, 0, sizeof(ident));
94 snprintf(ident, sizeof(ident), "IDENTIFY %s", nickname);
95 silc_parse_command_line(ident, &ctx->argv, &ctx->argv_lens,
96 &ctx->argv_types, &ctx->argc, 2);
98 i->cmd = silc_client_command_dup(ctx);
99 i->nickname = nickname ? strdup(nickname) : NULL;
100 i->server = server ? strdup(server) : NULL;
101 i->completion = completion;
102 i->context = context;
104 /* Call the command */
105 ctx->command->cb(ctx, NULL);
107 /* Add pending callback */
108 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
110 silc_client_get_client_destructor,
111 silc_client_command_get_client_callback,
115 /* Same as silc_client_get_clients function but does not resolve anything
116 from the server. This checks local cache and returns all matching
117 clients from the local cache. If none was found this returns NULL.
118 The `nickname' is the real nickname of the client, and the `format'
119 is the formatted nickname to find exact match from multiple found
120 entries. The format must be same as given in the SilcClientParams
121 structure to the client library. If the `format' is NULL all found
122 clients by `nickname' are returned. */
124 SilcClientEntry *silc_client_get_clients_local(SilcClient client,
125 SilcClientConnection conn,
126 const char *nickname,
128 uint32 *clients_count)
130 SilcIDCacheEntry id_cache;
131 SilcIDCacheList list = NULL;
132 SilcClientEntry entry, *clients;
136 /* Find ID from cache */
137 if (!silc_idcache_find_by_name(conn->client_cache, (char *)nickname, &list))
140 if (!silc_idcache_list_count(list)) {
141 silc_idcache_list_free(list);
145 clients = silc_calloc(silc_idcache_list_count(list), sizeof(*clients));
146 *clients_count = silc_idcache_list_count(list);
149 /* Take all without any further checking */
150 silc_idcache_list_first(list, &id_cache);
152 clients[i++] = id_cache->context;
154 if (!silc_idcache_list_next(list, &id_cache))
158 /* Check multiple cache entries for match */
159 silc_idcache_list_first(list, &id_cache);
161 entry = (SilcClientEntry)id_cache->context;
162 if (strcasecmp(entry->nickname, format)) {
163 if (!silc_idcache_list_next(list, &id_cache)) {
170 clients[i++] = id_cache->context;
172 if (!silc_idcache_list_next(list, &id_cache))
178 silc_idcache_list_free(list);
192 SilcClientConnection conn;
194 SilcBuffer client_id_list;
195 SilcGetClientCallback completion;
198 } *GetClientsByListInternal;
200 SILC_CLIENT_CMD_FUNC(get_clients_list_callback)
202 GetClientsByListInternal i = (GetClientsByListInternal)context;
203 SilcIDCacheEntry id_cache = NULL;
204 SilcBuffer client_id_list = i->client_id_list;
205 SilcClientEntry *clients = NULL;
206 uint32 clients_count = 0;
209 SILC_LOG_DEBUG(("Start"));
211 for (c = 0; c < i->list_count; c++) {
213 SilcClientID *client_id;
216 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
218 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
220 silc_buffer_pull(client_id_list, idp_len);
224 /* Get the client entry */
225 if (silc_idcache_find_by_id_one_ext(i->conn->client_cache,
228 silc_hash_client_id_compare, NULL,
230 clients = silc_realloc(clients, sizeof(*clients) *
231 (clients_count + 1));
232 clients[clients_count] = (SilcClientEntry)id_cache->context;
237 silc_free(client_id);
238 silc_buffer_pull(client_id_list, idp_len);
242 i->completion(i->client, i->conn, clients, clients_count, i->context);
247 static void silc_client_get_clients_list_destructor(void *context)
249 GetClientsByListInternal i = (GetClientsByListInternal)context;
251 SILC_LOG_DEBUG(("Start"));
253 if (i->found == FALSE)
254 i->completion(i->client, i->conn, NULL, 0, i->context);
256 if (i->client_id_list)
257 silc_buffer_free(i->client_id_list);
261 /* Gets client entries by the list of client ID's `client_id_list'. This
262 always resolves those client ID's it does not know yet from the server
263 so this function might take a while. The `client_id_list' is a list
264 of ID Payloads added one after other. JOIN command reply and USERS
265 command reply for example returns this sort of list. The `completion'
266 will be called after the entries are available. */
268 void silc_client_get_clients_by_list(SilcClient client,
269 SilcClientConnection conn,
271 SilcBuffer client_id_list,
272 SilcGetClientCallback completion,
275 SilcIDCacheEntry id_cache = NULL;
277 unsigned char **res_argv = NULL;
278 uint32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
279 GetClientsByListInternal in;
281 SILC_LOG_DEBUG(("Start"));
283 in = silc_calloc(1, sizeof(*in));
286 in->list_count = list_count;
287 in->client_id_list = silc_buffer_copy(client_id_list);
288 in->completion = completion;
289 in->context = context;
291 for (i = 0; i < list_count; i++) {
293 SilcClientID *client_id;
294 SilcClientEntry entry;
297 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
299 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
301 silc_buffer_pull(client_id_list, idp_len);
305 /* Check if we have this client cached already. */
307 silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
309 silc_hash_client_id_compare, NULL,
312 /* If we don't have the entry or it has incomplete info, then resolve
313 it from the server. */
314 entry = id_cache ? (SilcClientEntry)id_cache->context : NULL;
315 if (!id_cache || !entry->nickname) {
318 if (entry->status & SILC_CLIENT_STATUS_RESOLVING) {
319 entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
320 silc_free(client_id);
321 silc_buffer_pull(client_id_list, idp_len);
325 entry->status |= SILC_CLIENT_STATUS_RESOLVING;
328 /* No we don't have it, query it from the server. Assemble argument
329 table that will be sent fr the IDENTIFY command later. */
330 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
332 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
334 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
336 res_argv[res_argc] = client_id_list->data;
337 res_argv_lens[res_argc] = idp_len;
338 res_argv_types[res_argc] = res_argc + 5;
342 silc_free(client_id);
343 silc_buffer_pull(client_id_list, idp_len);
346 /* Query the client information from server if the list included clients
347 that we don't know about. */
351 /* Send the IDENTIFY command to server */
352 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
353 res_argc, res_argv, res_argv_lens,
354 res_argv_types, ++conn->cmd_ident);
355 silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
356 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
359 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
361 silc_client_get_clients_list_destructor,
362 silc_client_command_get_clients_list_callback,
365 silc_buffer_push(client_id_list, client_id_list->data -
366 client_id_list->head);
367 silc_buffer_free(res_cmd);
369 silc_free(res_argv_lens);
370 silc_free(res_argv_types);
374 silc_buffer_push(client_id_list, client_id_list->data -
375 client_id_list->head);
377 /* We have the clients in cache, get them and call the completion */
378 silc_client_command_get_clients_list_callback((void *)in, NULL);
381 /* The old style function to find client entry. This is used by the
382 library internally. If `query' is TRUE then the client information is
383 requested by the server. The pending command callback must be set
386 SilcClientEntry silc_idlist_get_client(SilcClient client,
387 SilcClientConnection conn,
388 const char *nickname,
392 SilcIDCacheEntry id_cache;
393 SilcIDCacheList list = NULL;
394 SilcClientEntry entry = NULL;
396 SILC_LOG_DEBUG(("Start"));
398 /* Find ID from cache */
399 if (!silc_idcache_find_by_name(conn->client_cache, (char *)nickname,
405 SilcClientCommandContext ctx;
407 SILC_LOG_DEBUG(("Requesting Client ID from server"));
409 /* No ID found. Do query from the server. The query is done by
410 sending simple IDENTIFY command to the server. */
411 ctx = silc_client_command_alloc();
412 ctx->client = client;
414 ctx->command = silc_client_command_find("IDENTIFY");
415 memset(ident, 0, sizeof(ident));
416 snprintf(ident, sizeof(ident), "IDENTIFY %s", nickname);
417 silc_parse_command_line(ident, &ctx->argv, &ctx->argv_lens,
418 &ctx->argv_types, &ctx->argc, 2);
419 ctx->command->cb(ctx, NULL);
422 silc_idcache_list_free(list);
430 /* Take first found cache entry */
431 if (!silc_idcache_list_first(list, &id_cache))
434 entry = (SilcClientEntry)id_cache->context;
436 /* Check multiple cache entries for match */
437 silc_idcache_list_first(list, &id_cache);
439 entry = (SilcClientEntry)id_cache->context;
441 if (strcasecmp(entry->nickname, format)) {
442 if (!silc_idcache_list_next(list, &id_cache)) {
454 /* If match weren't found, request it */
460 silc_idcache_list_free(list);
465 /* Finds entry for client by the client's ID. Returns the entry or NULL
466 if the entry was not found. */
468 SilcClientEntry silc_client_get_client_by_id(SilcClient client,
469 SilcClientConnection conn,
470 SilcClientID *client_id)
472 SilcIDCacheEntry id_cache;
474 SILC_LOG_DEBUG(("Finding client by ID (%s)",
475 silc_id_render(client_id, SILC_ID_CLIENT)));
477 /* Find ID from cache */
478 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
480 silc_hash_client_id_compare, NULL,
484 SILC_LOG_DEBUG(("Found"));
486 return (SilcClientEntry)id_cache->context;
491 SilcClientConnection conn;
492 SilcClientID *client_id;
493 SilcGetClientCallback completion;
496 } *GetClientByIDInternal;
498 SILC_CLIENT_CMD_FUNC(get_client_by_id_callback)
500 GetClientByIDInternal i = (GetClientByIDInternal)context;
501 SilcClientEntry entry;
504 entry = silc_client_get_client_by_id(i->client, i->conn,
507 i->completion(i->client, i->conn, &entry, 1, i->context);
512 static void silc_client_get_client_by_id_destructor(void *context)
514 GetClientByIDInternal i = (GetClientByIDInternal)context;
516 if (i->found == FALSE)
517 i->completion(i->client, i->conn, NULL, 0, i->context);
520 silc_free(i->client_id);
524 /* Same as above but will always resolve the information from the server.
525 Use this only if you know that you don't have the entry and the only
526 thing you know about the client is its ID. */
528 void silc_client_get_client_by_id_resolve(SilcClient client,
529 SilcClientConnection conn,
530 SilcClientID *client_id,
531 SilcGetClientCallback completion,
535 GetClientByIDInternal i = silc_calloc(1, sizeof(*i));
537 SILC_LOG_DEBUG(("Start"));
539 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
540 silc_client_send_command(client, conn, SILC_COMMAND_WHOIS,
542 1, 3, idp->data, idp->len);
543 silc_buffer_free(idp);
547 i->client_id = silc_id_dup(client_id, SILC_ID_CLIENT);
548 i->completion = completion;
549 i->context = context;
551 /* Add pending callback */
552 silc_client_command_pending(conn, SILC_COMMAND_WHOIS,
554 silc_client_get_client_by_id_destructor,
555 silc_client_command_get_client_by_id_callback,
559 /* Creates new client entry and adds it to the ID cache. Returns pointer
563 silc_client_add_client(SilcClient client, SilcClientConnection conn,
564 char *nickname, char *username,
565 char *userinfo, SilcClientID *id, uint32 mode)
567 SilcClientEntry client_entry;
570 SILC_LOG_DEBUG(("Start"));
572 /* Save the client infos */
573 client_entry = silc_calloc(1, sizeof(*client_entry));
574 client_entry->id = id;
575 client_entry->valid = TRUE;
576 silc_parse_userfqdn(nickname, &nick, &client_entry->server);
577 silc_parse_userfqdn(username, &client_entry->username,
578 &client_entry->hostname);
580 client_entry->realname = strdup(userinfo);
581 client_entry->mode = mode;
583 client_entry->nickname = strdup(nick);
585 /* Format the nickname */
586 silc_client_nickname_format(client, conn, client_entry);
588 /* Add client to cache, the non-formatted nickname is saved to cache */
589 if (!silc_idcache_add(conn->client_cache, nick, client_entry->id,
590 (void *)client_entry, 0, NULL)) {
591 silc_free(client_entry->nickname);
592 silc_free(client_entry->username);
593 silc_free(client_entry->hostname);
594 silc_free(client_entry->server);
595 silc_free(client_entry);
602 /* Updates the `client_entry' with the new information sent as argument. */
604 void silc_client_update_client(SilcClient client,
605 SilcClientConnection conn,
606 SilcClientEntry client_entry,
607 const char *nickname,
608 const char *username,
609 const char *userinfo,
614 SILC_LOG_DEBUG(("Start"));
616 if (!client_entry->username && username)
617 silc_parse_userfqdn(username, &client_entry->username,
618 &client_entry->hostname);
619 if (!client_entry->realname && userinfo)
620 client_entry->realname = strdup(userinfo);
621 if (!client_entry->nickname && nickname) {
622 silc_parse_userfqdn(nickname, &nick, &client_entry->server);
623 client_entry->nickname = strdup(nick);
624 silc_client_nickname_format(client, conn, client_entry);
626 client_entry->mode = mode;
629 /* Remove the old cache entry and create a new one */
630 silc_idcache_del_by_context(conn->client_cache, client_entry);
631 silc_idcache_add(conn->client_cache, nick, client_entry->id,
632 client_entry, 0, NULL);
636 /* Deletes the client entry and frees all memory. */
638 void silc_client_del_client_entry(SilcClient client,
639 SilcClientConnection conn,
640 SilcClientEntry client_entry)
642 SILC_LOG_DEBUG(("Start"));
644 silc_free(client_entry->nickname);
645 silc_free(client_entry->username);
646 silc_free(client_entry->realname);
647 silc_free(client_entry->server);
648 silc_free(client_entry->id);
649 silc_free(client_entry->fingerprint);
650 if (client_entry->send_key)
651 silc_cipher_free(client_entry->send_key);
652 if (client_entry->receive_key)
653 silc_cipher_free(client_entry->receive_key);
654 silc_free(client_entry->key);
655 silc_client_ftp_session_free_client(conn, client_entry);
656 if (client_entry->ke)
657 silc_client_abort_key_agreement(client, conn, client_entry);
658 silc_free(client_entry);
661 /* Removes client from the cache by the client entry. */
663 bool silc_client_del_client(SilcClient client, SilcClientConnection conn,
664 SilcClientEntry client_entry)
666 bool ret = silc_idcache_del_by_context(conn->client_cache, client_entry);
667 silc_client_del_client_entry(client, conn, client_entry);
671 /* Removes channel from the cache by the channel entry. */
673 bool silc_client_del_channel(SilcClient client, SilcClientConnection conn,
674 SilcChannelEntry channel)
676 bool ret = silc_idcache_del_by_context(conn->channel_cache, channel);
677 silc_free(channel->channel_name);
678 silc_free(channel->id);
679 silc_free(channel->key);
680 if (channel->channel_key)
681 silc_cipher_free(channel->channel_key);
683 silc_hmac_free(channel->hmac);
684 if (channel->old_channel_key)
685 silc_cipher_free(channel->old_channel_key);
686 if (channel->old_hmac)
687 silc_hmac_free(channel->old_hmac);
688 if (channel->rekey_task)
689 silc_schedule_task_del(conn->client->schedule, channel->rekey_task);
690 silc_client_del_channel_private_keys(client, conn, channel);
695 /* Finds entry for channel by the channel name. Returns the entry or NULL
696 if the entry was not found. It is found only if the client is joined
699 SilcChannelEntry silc_client_get_channel(SilcClient client,
700 SilcClientConnection conn,
703 SilcIDCacheEntry id_cache;
704 SilcChannelEntry entry;
706 SILC_LOG_DEBUG(("Start"));
708 if (!silc_idcache_find_by_name_one(conn->channel_cache, channel,
712 entry = (SilcChannelEntry)id_cache->context;
717 /* Finds entry for channel by the channel ID. Returns the entry or NULL
718 if the entry was not found. It is found only if the client is joined
721 SilcChannelEntry silc_client_get_channel_by_id(SilcClient client,
722 SilcClientConnection conn,
723 SilcChannelID *channel_id)
725 SilcIDCacheEntry id_cache;
726 SilcChannelEntry entry;
728 SILC_LOG_DEBUG(("Start"));
730 if (!silc_idcache_find_by_id_one(conn->channel_cache, channel_id,
734 entry = (SilcChannelEntry)id_cache->context;
741 SilcClientConnection conn;
742 SilcChannelID *channel_id;
743 SilcGetChannelCallback completion;
746 } *GetChannelByIDInternal;
748 SILC_CLIENT_CMD_FUNC(get_channel_by_id_callback)
750 GetChannelByIDInternal i = (GetChannelByIDInternal)context;
751 SilcChannelEntry entry;
753 SILC_LOG_DEBUG(("Start"));
755 /* Get the channel */
756 entry = silc_client_get_channel_by_id(i->client, i->conn,
759 i->completion(i->client, i->conn, &entry, 1, i->context);
764 static void silc_client_get_channel_by_id_destructor(void *context)
766 GetChannelByIDInternal i = (GetChannelByIDInternal)context;
768 if (i->found == FALSE)
769 i->completion(i->client, i->conn, NULL, 0, i->context);
771 silc_free(i->channel_id);
775 /* Resolves channel information from the server by the channel ID. */
777 void silc_client_get_channel_by_id_resolve(SilcClient client,
778 SilcClientConnection conn,
779 SilcChannelID *channel_id,
780 SilcGetChannelCallback completion,
784 GetChannelByIDInternal i = silc_calloc(1, sizeof(*i));
786 SILC_LOG_DEBUG(("Start"));
788 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
789 silc_client_send_command(client, conn, SILC_COMMAND_IDENTIFY,
791 1, 5, idp->data, idp->len);
792 silc_buffer_free(idp);
796 i->channel_id = silc_id_dup(channel_id, SILC_ID_CHANNEL);
797 i->completion = completion;
798 i->context = context;
800 /* Add pending callback */
801 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
803 silc_client_get_channel_by_id_destructor,
804 silc_client_command_get_channel_by_id_callback,
808 /* Find channel entry by ID. This routine is used internally by the library. */
810 SilcChannelEntry silc_idlist_get_channel_by_id(SilcClient client,
811 SilcClientConnection conn,
812 SilcChannelID *channel_id,
816 SilcChannelEntry channel;
818 SILC_LOG_DEBUG(("Start"));
820 channel = silc_client_get_channel_by_id(client, conn, channel_id);
825 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
826 silc_client_send_command(client, conn, SILC_COMMAND_IDENTIFY,
828 1, 5, idp->data, idp->len);
829 silc_buffer_free(idp);
835 /* Finds entry for server by the server name. */
837 SilcServerEntry silc_client_get_server(SilcClient client,
838 SilcClientConnection conn,
841 SilcIDCacheEntry id_cache;
842 SilcServerEntry entry;
844 SILC_LOG_DEBUG(("Start"));
846 if (!silc_idcache_find_by_name_one(conn->server_cache, server_name,
850 entry = (SilcServerEntry)id_cache->context;
855 /* Finds entry for server by the server ID. */
857 SilcServerEntry silc_client_get_server_by_id(SilcClient client,
858 SilcClientConnection conn,
859 SilcServerID *server_id)
861 SilcIDCacheEntry id_cache;
862 SilcServerEntry entry;
864 SILC_LOG_DEBUG(("Start"));
866 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
870 entry = (SilcServerEntry)id_cache->context;
875 /* Removes server from the cache by the server entry. */
877 bool silc_client_del_server(SilcClient client, SilcClientConnection conn,
878 SilcServerEntry server)
880 bool ret = silc_idcache_del_by_context(conn->server_cache, server);
881 silc_free(server->server_name);
882 silc_free(server->server_info);
883 silc_free(server->server_id);
888 /* Formats the nickname of the client specified by the `client_entry'.
889 If the format is specified by the application this will format the
890 nickname and replace the old nickname in the client entry. If the
891 format string is not specified then this function has no effect. */
893 void silc_client_nickname_format(SilcClient client,
894 SilcClientConnection conn,
895 SilcClientEntry client_entry)
898 char *newnick = NULL;
900 SilcClientEntry *clients;
901 uint32 clients_count = 0;
903 SILC_LOG_DEBUG(("Start"));
905 if (!client->params->nickname_format[0])
908 if (!client_entry->nickname)
911 /* Get all clients with same nickname. Do not perform the formatting
912 if there aren't any clients with same nickname unless the application
913 is forcing us to do so. */
914 clients = silc_client_get_clients_local(client, conn,
915 client_entry->nickname, NULL,
917 if (!clients && !client->params->nickname_force_format)
921 for (i = 0; i < clients_count; i++)
922 if (clients[i]->valid && clients[i] != client_entry)
927 cp = client->params->nickname_format;
937 if (!client_entry->nickname)
939 len = strlen(client_entry->nickname);
940 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
941 memcpy(&newnick[off], client_entry->nickname, len);
945 /* Stripped hostname */
946 if (!client_entry->hostname)
948 len = strcspn(client_entry->hostname, ".");
949 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
950 memcpy(&newnick[off], client_entry->hostname, len);
955 if (!client_entry->hostname)
957 len = strlen(client_entry->hostname);
958 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
959 memcpy(&newnick[off], client_entry->hostname, len);
963 /* Stripped server name */
964 if (!client_entry->server)
966 len = strcspn(client_entry->server, ".");
967 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
968 memcpy(&newnick[off], client_entry->server, len);
972 /* Full server name */
973 if (!client_entry->server)
975 len = strlen(client_entry->server);
976 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
977 memcpy(&newnick[off], client_entry->server, len);
981 /* Ascending number */
986 if (clients_count == 1)
989 for (i = 0; i < clients_count; i++) {
990 if (strncasecmp(clients[i]->nickname, newnick, off))
992 if (strlen(clients[i]->nickname) <= off)
994 num = atoi(&clients[i]->nickname[off]);
999 memset(tmp, 0, sizeof(tmp));
1000 snprintf(tmp, sizeof(tmp) - 1, "%d", ++max);
1002 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1003 memcpy(&newnick[off], tmp, len);
1008 /* Some other character in the string */
1009 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
1010 memcpy(&newnick[off], cp, 1);
1018 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
1021 silc_free(client_entry->nickname);
1022 client_entry->nickname = newnick;