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, FALSE)) {
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, FALSE);
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 silc_free(client_entry);
659 /* Removes client from the cache by the client entry. */
661 bool silc_client_del_client(SilcClient client, SilcClientConnection conn,
662 SilcClientEntry client_entry)
664 bool ret = silc_idcache_del_by_context(conn->client_cache, client_entry);
665 silc_client_del_client_entry(client, conn, client_entry);
669 /* Removes channel from the cache by the channel entry. */
671 bool silc_client_del_channel(SilcClient client, SilcClientConnection conn,
672 SilcChannelEntry channel)
674 bool ret = silc_idcache_del_by_context(conn->channel_cache, channel);
675 silc_free(channel->channel_name);
676 silc_free(channel->id);
677 silc_free(channel->key);
678 if (channel->channel_key)
679 silc_cipher_free(channel->channel_key);
681 silc_hmac_free(channel->hmac);
682 if (channel->old_channel_key)
683 silc_cipher_free(channel->old_channel_key);
684 if (channel->old_hmac)
685 silc_hmac_free(channel->old_hmac);
686 if (channel->rekey_task)
687 silc_schedule_task_del(conn->client->schedule, channel->rekey_task);
688 silc_client_del_channel_private_keys(client, conn, channel);
693 /* Finds entry for channel by the channel name. Returns the entry or NULL
694 if the entry was not found. It is found only if the client is joined
697 SilcChannelEntry silc_client_get_channel(SilcClient client,
698 SilcClientConnection conn,
701 SilcIDCacheEntry id_cache;
702 SilcChannelEntry entry;
704 SILC_LOG_DEBUG(("Start"));
706 if (!silc_idcache_find_by_name_one(conn->channel_cache, channel,
710 entry = (SilcChannelEntry)id_cache->context;
715 /* Finds entry for channel by the channel ID. Returns the entry or NULL
716 if the entry was not found. It is found only if the client is joined
719 SilcChannelEntry silc_client_get_channel_by_id(SilcClient client,
720 SilcClientConnection conn,
721 SilcChannelID *channel_id)
723 SilcIDCacheEntry id_cache;
724 SilcChannelEntry entry;
726 SILC_LOG_DEBUG(("Start"));
728 if (!silc_idcache_find_by_id_one(conn->channel_cache, channel_id,
732 entry = (SilcChannelEntry)id_cache->context;
739 SilcClientConnection conn;
740 SilcChannelID *channel_id;
741 SilcGetChannelCallback completion;
744 } *GetChannelByIDInternal;
746 SILC_CLIENT_CMD_FUNC(get_channel_by_id_callback)
748 GetChannelByIDInternal i = (GetChannelByIDInternal)context;
749 SilcChannelEntry entry;
751 SILC_LOG_DEBUG(("Start"));
753 /* Get the channel */
754 entry = silc_client_get_channel_by_id(i->client, i->conn,
757 i->completion(i->client, i->conn, &entry, 1, i->context);
762 static void silc_client_get_channel_by_id_destructor(void *context)
764 GetChannelByIDInternal i = (GetChannelByIDInternal)context;
766 if (i->found == FALSE)
767 i->completion(i->client, i->conn, NULL, 0, i->context);
769 silc_free(i->channel_id);
773 /* Resolves channel information from the server by the channel ID. */
775 void silc_client_get_channel_by_id_resolve(SilcClient client,
776 SilcClientConnection conn,
777 SilcChannelID *channel_id,
778 SilcGetChannelCallback completion,
782 GetChannelByIDInternal i = silc_calloc(1, sizeof(*i));
784 SILC_LOG_DEBUG(("Start"));
786 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
787 silc_client_send_command(client, conn, SILC_COMMAND_IDENTIFY,
789 1, 5, idp->data, idp->len);
790 silc_buffer_free(idp);
794 i->channel_id = silc_id_dup(channel_id, SILC_ID_CHANNEL);
795 i->completion = completion;
796 i->context = context;
798 /* Add pending callback */
799 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
801 silc_client_get_channel_by_id_destructor,
802 silc_client_command_get_channel_by_id_callback,
806 /* Find channel entry by ID. This routine is used internally by the library. */
808 SilcChannelEntry silc_idlist_get_channel_by_id(SilcClient client,
809 SilcClientConnection conn,
810 SilcChannelID *channel_id,
814 SilcChannelEntry channel;
816 SILC_LOG_DEBUG(("Start"));
818 channel = silc_client_get_channel_by_id(client, conn, channel_id);
823 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
824 silc_client_send_command(client, conn, SILC_COMMAND_IDENTIFY,
826 1, 5, idp->data, idp->len);
827 silc_buffer_free(idp);
833 /* Finds entry for server by the server name. */
835 SilcServerEntry silc_client_get_server(SilcClient client,
836 SilcClientConnection conn,
839 SilcIDCacheEntry id_cache;
840 SilcServerEntry entry;
842 SILC_LOG_DEBUG(("Start"));
844 if (!silc_idcache_find_by_name_one(conn->server_cache, server_name,
848 entry = (SilcServerEntry)id_cache->context;
853 /* Finds entry for server by the server ID. */
855 SilcServerEntry silc_client_get_server_by_id(SilcClient client,
856 SilcClientConnection conn,
857 SilcServerID *server_id)
859 SilcIDCacheEntry id_cache;
860 SilcServerEntry entry;
862 SILC_LOG_DEBUG(("Start"));
864 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
868 entry = (SilcServerEntry)id_cache->context;
873 /* Removes server from the cache by the server entry. */
875 bool silc_client_del_server(SilcClient client, SilcClientConnection conn,
876 SilcServerEntry server)
878 bool ret = silc_idcache_del_by_context(conn->server_cache, server);
879 silc_free(server->server_name);
880 silc_free(server->server_info);
881 silc_free(server->server_id);
886 /* Formats the nickname of the client specified by the `client_entry'.
887 If the format is specified by the application this will format the
888 nickname and replace the old nickname in the client entry. If the
889 format string is not specified then this function has no effect. */
891 void silc_client_nickname_format(SilcClient client,
892 SilcClientConnection conn,
893 SilcClientEntry client_entry)
896 char *newnick = NULL;
898 SilcClientEntry *clients;
899 uint32 clients_count = 0;
901 SILC_LOG_DEBUG(("Start"));
903 if (!client->params->nickname_format[0])
906 if (!client_entry->nickname)
909 /* Get all clients with same nickname. Do not perform the formatting
910 if there aren't any clients with same nickname unless the application
911 is forcing us to do so. */
912 clients = silc_client_get_clients_local(client, conn,
913 client_entry->nickname, NULL,
915 if (!clients && !client->params->nickname_force_format)
919 for (i = 0; i < clients_count; i++)
920 if (clients[i]->valid)
925 cp = client->params->nickname_format;
935 if (!client_entry->nickname)
937 len = strlen(client_entry->nickname);
938 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
939 memcpy(&newnick[off], client_entry->nickname, len);
943 /* Stripped hostname */
944 if (!client_entry->hostname)
946 len = strcspn(client_entry->hostname, ".");
947 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
948 memcpy(&newnick[off], client_entry->hostname, len);
953 if (!client_entry->hostname)
955 len = strlen(client_entry->hostname);
956 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
957 memcpy(&newnick[off], client_entry->hostname, len);
961 /* Stripped server name */
962 if (!client_entry->server)
964 len = strcspn(client_entry->server, ".");
965 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
966 memcpy(&newnick[off], client_entry->server, len);
970 /* Full server name */
971 if (!client_entry->server)
973 len = strlen(client_entry->server);
974 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
975 memcpy(&newnick[off], client_entry->server, len);
979 /* Ascending number */
984 if (clients_count == 1)
987 for (i = 0; i < clients_count; i++) {
988 if (strncasecmp(clients[i]->nickname, newnick, off))
990 if (strlen(clients[i]->nickname) <= off)
992 num = atoi(&clients[i]->nickname[off]);
997 memset(tmp, 0, sizeof(tmp));
998 snprintf(tmp, sizeof(tmp) - 1, "%d", ++max);
1000 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1001 memcpy(&newnick[off], tmp, len);
1006 /* Some other character in the string */
1007 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
1008 memcpy(&newnick[off], cp, 1);
1016 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
1019 silc_free(client_entry->nickname);
1020 client_entry->nickname = newnick;