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 if (client_entry->send_key)
650 silc_cipher_free(client_entry->send_key);
651 if (client_entry->receive_key)
652 silc_cipher_free(client_entry->receive_key);
653 silc_free(client_entry->key);
654 silc_client_ftp_session_free_client(conn, client_entry);
655 silc_free(client_entry);
658 /* Removes client from the cache by the client entry. */
660 bool silc_client_del_client(SilcClient client, SilcClientConnection conn,
661 SilcClientEntry client_entry)
663 bool ret = silc_idcache_del_by_context(conn->client_cache, client_entry);
664 silc_client_del_client_entry(client, conn, client_entry);
668 /* Removes channel from the cache by the channel entry. */
670 bool silc_client_del_channel(SilcClient client, SilcClientConnection conn,
671 SilcChannelEntry channel)
673 bool ret = silc_idcache_del_by_context(conn->channel_cache, channel);
674 silc_free(channel->channel_name);
675 silc_free(channel->id);
676 silc_free(channel->key);
677 if (channel->channel_key)
678 silc_cipher_free(channel->channel_key);
680 silc_hmac_free(channel->hmac);
681 if (channel->old_channel_key)
682 silc_cipher_free(channel->old_channel_key);
683 if (channel->old_hmac)
684 silc_hmac_free(channel->old_hmac);
685 if (channel->rekey_task)
686 silc_schedule_task_del(conn->client->schedule, channel->rekey_task);
687 silc_client_del_channel_private_keys(client, conn, channel);
692 /* Finds entry for channel by the channel name. Returns the entry or NULL
693 if the entry was not found. It is found only if the client is joined
696 SilcChannelEntry silc_client_get_channel(SilcClient client,
697 SilcClientConnection conn,
700 SilcIDCacheEntry id_cache;
701 SilcChannelEntry entry;
703 SILC_LOG_DEBUG(("Start"));
705 if (!silc_idcache_find_by_name_one(conn->channel_cache, channel,
709 entry = (SilcChannelEntry)id_cache->context;
714 /* Finds entry for channel by the channel ID. Returns the entry or NULL
715 if the entry was not found. It is found only if the client is joined
718 SilcChannelEntry silc_client_get_channel_by_id(SilcClient client,
719 SilcClientConnection conn,
720 SilcChannelID *channel_id)
722 SilcIDCacheEntry id_cache;
723 SilcChannelEntry entry;
725 SILC_LOG_DEBUG(("Start"));
727 if (!silc_idcache_find_by_id_one(conn->channel_cache, channel_id,
731 entry = (SilcChannelEntry)id_cache->context;
738 SilcClientConnection conn;
739 SilcChannelID *channel_id;
740 SilcGetChannelCallback completion;
743 } *GetChannelByIDInternal;
745 SILC_CLIENT_CMD_FUNC(get_channel_by_id_callback)
747 GetChannelByIDInternal i = (GetChannelByIDInternal)context;
748 SilcChannelEntry entry;
750 SILC_LOG_DEBUG(("Start"));
752 /* Get the channel */
753 entry = silc_client_get_channel_by_id(i->client, i->conn,
756 i->completion(i->client, i->conn, &entry, 1, i->context);
761 static void silc_client_get_channel_by_id_destructor(void *context)
763 GetChannelByIDInternal i = (GetChannelByIDInternal)context;
765 if (i->found == FALSE)
766 i->completion(i->client, i->conn, NULL, 0, i->context);
768 silc_free(i->channel_id);
772 /* Resolves channel information from the server by the channel ID. */
774 void silc_client_get_channel_by_id_resolve(SilcClient client,
775 SilcClientConnection conn,
776 SilcChannelID *channel_id,
777 SilcGetChannelCallback completion,
781 GetChannelByIDInternal i = silc_calloc(1, sizeof(*i));
783 SILC_LOG_DEBUG(("Start"));
785 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
786 silc_client_send_command(client, conn, SILC_COMMAND_IDENTIFY,
788 1, 5, idp->data, idp->len);
789 silc_buffer_free(idp);
793 i->channel_id = silc_id_dup(channel_id, SILC_ID_CHANNEL);
794 i->completion = completion;
795 i->context = context;
797 /* Add pending callback */
798 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
800 silc_client_get_channel_by_id_destructor,
801 silc_client_command_get_channel_by_id_callback,
805 /* Find channel entry by ID. This routine is used internally by the library. */
807 SilcChannelEntry silc_idlist_get_channel_by_id(SilcClient client,
808 SilcClientConnection conn,
809 SilcChannelID *channel_id,
813 SilcChannelEntry channel;
815 SILC_LOG_DEBUG(("Start"));
817 channel = silc_client_get_channel_by_id(client, conn, channel_id);
822 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
823 silc_client_send_command(client, conn, SILC_COMMAND_IDENTIFY,
825 1, 5, idp->data, idp->len);
826 silc_buffer_free(idp);
832 /* Finds entry for server by the server name. */
834 SilcServerEntry silc_client_get_server(SilcClient client,
835 SilcClientConnection conn,
838 SilcIDCacheEntry id_cache;
839 SilcServerEntry entry;
841 SILC_LOG_DEBUG(("Start"));
843 if (!silc_idcache_find_by_name_one(conn->server_cache, server_name,
847 entry = (SilcServerEntry)id_cache->context;
852 /* Finds entry for server by the server ID. */
854 SilcServerEntry silc_client_get_server_by_id(SilcClient client,
855 SilcClientConnection conn,
856 SilcServerID *server_id)
858 SilcIDCacheEntry id_cache;
859 SilcServerEntry entry;
861 SILC_LOG_DEBUG(("Start"));
863 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
867 entry = (SilcServerEntry)id_cache->context;
872 /* Removes server from the cache by the server entry. */
874 bool silc_client_del_server(SilcClient client, SilcClientConnection conn,
875 SilcServerEntry server)
877 bool ret = silc_idcache_del_by_context(conn->server_cache, server);
878 silc_free(server->server_name);
879 silc_free(server->server_info);
880 silc_free(server->server_id);
885 /* Formats the nickname of the client specified by the `client_entry'.
886 If the format is specified by the application this will format the
887 nickname and replace the old nickname in the client entry. If the
888 format string is not specified then this function has no effect. */
890 void silc_client_nickname_format(SilcClient client,
891 SilcClientConnection conn,
892 SilcClientEntry client_entry)
895 char *newnick = NULL;
897 SilcClientEntry *clients;
898 uint32 clients_count = 0;
900 SILC_LOG_DEBUG(("Start"));
902 if (!client->params->nickname_format[0])
905 if (!client_entry->nickname)
908 /* Get all clients with same nickname. Do not perform the formatting
909 if there aren't any clients with same nickname unless the application
910 is forcing us to do so. */
911 clients = silc_client_get_clients_local(client, conn,
912 client_entry->nickname, NULL,
914 if (!clients && !client->params->nickname_force_format)
918 for (i = 0; i < clients_count; i++)
919 if (clients[i]->valid)
924 cp = client->params->nickname_format;
934 if (!client_entry->nickname)
936 len = strlen(client_entry->nickname);
937 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
938 memcpy(&newnick[off], client_entry->nickname, len);
942 /* Stripped hostname */
943 if (!client_entry->hostname)
945 len = strcspn(client_entry->hostname, ".");
946 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
947 memcpy(&newnick[off], client_entry->hostname, len);
952 if (!client_entry->hostname)
954 len = strlen(client_entry->hostname);
955 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
956 memcpy(&newnick[off], client_entry->hostname, len);
960 /* Stripped server name */
961 if (!client_entry->server)
963 len = strcspn(client_entry->server, ".");
964 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
965 memcpy(&newnick[off], client_entry->server, len);
969 /* Full server name */
970 if (!client_entry->server)
972 len = strlen(client_entry->server);
973 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
974 memcpy(&newnick[off], client_entry->server, len);
978 /* Ascending number */
983 if (clients_count == 1)
986 for (i = 0; i < clients_count; i++) {
987 if (strncasecmp(clients[i]->nickname, newnick, off))
989 if (strlen(clients[i]->nickname) <= off)
991 num = atoi(&clients[i]->nickname[off]);
996 memset(tmp, 0, sizeof(tmp));
997 snprintf(tmp, sizeof(tmp) - 1, "%d", ++max);
999 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
1000 memcpy(&newnick[off], tmp, len);
1005 /* Some other character in the string */
1006 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
1007 memcpy(&newnick[off], cp, 1);
1015 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
1018 silc_free(client_entry->nickname);
1019 client_entry->nickname = newnick;