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"
25 SilcClientCommandContext cmd;
26 SilcGetClientCallback completion;
33 SILC_CLIENT_CMD_FUNC(get_client_callback)
35 GetClientInternal i = (GetClientInternal)context;
36 SilcClientEntry *clients;
40 clients = silc_client_get_clients_local(i->cmd->client, i->cmd->conn,
41 i->nickname, i->server,
44 i->completion(i->cmd->client, i->cmd->conn, clients,
45 clients_count, i->context);
51 static void silc_client_get_client_destructor(void *context)
53 GetClientInternal i = (GetClientInternal)context;
55 if (i->found == FALSE)
56 i->completion(i->cmd->client, i->cmd->conn, NULL, 0, i->context);
58 silc_client_command_free(i->cmd);
60 silc_free(i->nickname);
66 /* Finds client entry or entries by the `nickname' and `server'. The
67 completion callback will be called when the client entries has been found.
69 Note: this function is always asynchronous and resolves the client
70 information from the server. Thus, if you already know the client
71 information then use the silc_client_get_client_by_id function to
72 get the client entry since this function may be very slow and should
73 be used only to initially get the client entries. */
75 void silc_client_get_clients(SilcClient client,
76 SilcClientConnection conn,
79 SilcGetClientCallback completion,
83 SilcClientCommandContext ctx;
84 GetClientInternal i = silc_calloc(1, sizeof(*i));
86 /* No ID found. Do query from the server. The query is done by
87 sending simple IDENTIFY command to the server. */
88 ctx = silc_client_command_alloc();
91 ctx->command = silc_client_command_find("IDENTIFY");
92 memset(ident, 0, sizeof(ident));
93 snprintf(ident, sizeof(ident), "IDENTIFY %s", nickname);
94 silc_parse_command_line(ident, &ctx->argv, &ctx->argv_lens,
95 &ctx->argv_types, &ctx->argc, 2);
97 i->cmd = silc_client_command_dup(ctx);
98 i->nickname = nickname ? strdup(nickname) : NULL;
99 i->server = server ? strdup(server) : NULL;
100 i->completion = completion;
101 i->context = context;
103 /* Call the command */
104 ctx->command->cb(ctx, NULL);
106 /* Add pending callback */
107 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
109 silc_client_get_client_destructor,
110 silc_client_command_get_client_callback,
114 /* Same as silc_client_get_clients function but does not resolve anything
115 from the server. This checks local cache and returns all matching
116 clients from the local cache. If none was found this returns NULL.
117 The `nickname' is the real nickname of the client, and the `format'
118 is the formatted nickname to find exact match from multiple found
119 entries. The format must be same as given in the SilcClientParams
120 structure to the client library. If the `format' is NULL all found
121 clients by `nickname' are returned. */
123 SilcClientEntry *silc_client_get_clients_local(SilcClient client,
124 SilcClientConnection conn,
125 const char *nickname,
127 uint32 *clients_count)
129 SilcIDCacheEntry id_cache;
130 SilcIDCacheList list = NULL;
131 SilcClientEntry entry, *clients;
135 /* Find ID from cache */
136 if (!silc_idcache_find_by_name(conn->client_cache, (char *)nickname, &list))
139 if (!silc_idcache_list_count(list)) {
140 silc_idcache_list_free(list);
144 clients = silc_calloc(silc_idcache_list_count(list), sizeof(*clients));
145 *clients_count = silc_idcache_list_count(list);
148 /* Take all without any further checking */
149 silc_idcache_list_first(list, &id_cache);
151 clients[i++] = id_cache->context;
153 if (!silc_idcache_list_next(list, &id_cache))
157 /* Check multiple cache entries for match */
158 silc_idcache_list_first(list, &id_cache);
160 entry = (SilcClientEntry)id_cache->context;
161 if (strcasecmp(entry->nickname, format)) {
162 if (!silc_idcache_list_next(list, &id_cache)) {
169 clients[i++] = id_cache->context;
171 if (!silc_idcache_list_next(list, &id_cache))
177 silc_idcache_list_free(list);
191 SilcClientConnection conn;
193 SilcBuffer client_id_list;
194 SilcGetClientCallback completion;
197 } *GetClientsByListInternal;
199 SILC_CLIENT_CMD_FUNC(get_clients_list_callback)
201 GetClientsByListInternal i = (GetClientsByListInternal)context;
202 SilcIDCacheEntry id_cache = NULL;
203 SilcBuffer client_id_list = i->client_id_list;
204 SilcClientEntry *clients = NULL;
205 uint32 clients_count = 0;
208 SILC_LOG_DEBUG(("Start"));
210 for (c = 0; c < i->list_count; c++) {
212 SilcClientID *client_id;
215 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
217 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
221 /* Get the client entry */
222 if (silc_idcache_find_by_id_one_ext(i->conn->client_cache,
225 silc_hash_client_id_compare, NULL,
227 clients = silc_realloc(clients, sizeof(*clients) *
228 (clients_count + 1));
229 clients[clients_count] = (SilcClientEntry)id_cache->context;
234 silc_free(client_id);
235 silc_buffer_pull(client_id_list, idp_len);
239 i->completion(i->client, i->conn, clients, clients_count, i->context);
244 static void silc_client_get_clients_list_destructor(void *context)
246 GetClientsByListInternal i = (GetClientsByListInternal)context;
248 SILC_LOG_DEBUG(("Start"));
250 if (i->found == FALSE)
251 i->completion(i->client, i->conn, NULL, 0, i->context);
253 if (i->client_id_list)
254 silc_buffer_free(i->client_id_list);
258 /* Gets client entries by the list of client ID's `client_id_list'. This
259 always resolves those client ID's it does not know yet from the server
260 so this function might take a while. The `client_id_list' is a list
261 of ID Payloads added one after other. JOIN command reply and USERS
262 command reply for example returns this sort of list. The `completion'
263 will be called after the entries are available. */
265 void silc_client_get_clients_by_list(SilcClient client,
266 SilcClientConnection conn,
268 SilcBuffer client_id_list,
269 SilcGetClientCallback completion,
272 SilcIDCacheEntry id_cache = NULL;
274 unsigned char **res_argv = NULL;
275 uint32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
276 GetClientsByListInternal in;
278 SILC_LOG_DEBUG(("Start"));
280 in = silc_calloc(1, sizeof(*in));
283 in->list_count = list_count;
284 in->client_id_list = silc_buffer_copy(client_id_list);
285 in->completion = completion;
286 in->context = context;
288 for (i = 0; i < list_count; i++) {
290 SilcClientID *client_id;
291 SilcClientEntry entry;
294 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
296 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
300 /* Check if we have this client cached already. */
302 silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
304 silc_hash_client_id_compare, NULL,
307 /* If we don't have the entry or it has incomplete info, then resolve
308 it from the server. */
309 entry = id_cache ? (SilcClientEntry)id_cache->context : NULL;
310 if (!id_cache || !entry->nickname) {
313 if (entry->status & SILC_CLIENT_STATUS_RESOLVING) {
314 silc_free(client_id);
315 silc_buffer_pull(client_id_list, idp_len);
319 entry->status |= SILC_CLIENT_STATUS_RESOLVING;
322 /* No we don't have it, query it from the server. Assemble argument
323 table that will be sent fr the IDENTIFY command later. */
324 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
326 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
328 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
330 res_argv[res_argc] = client_id_list->data;
331 res_argv_lens[res_argc] = idp_len;
332 res_argv_types[res_argc] = res_argc + 5;
336 silc_free(client_id);
337 silc_buffer_pull(client_id_list, idp_len);
340 /* Query the client information from server if the list included clients
341 that we don't know about. */
345 /* Send the IDENTIFY command to server */
346 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
347 res_argc, res_argv, res_argv_lens,
348 res_argv_types, ++conn->cmd_ident);
349 silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
350 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
353 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
355 silc_client_get_clients_list_destructor,
356 silc_client_command_get_clients_list_callback,
359 silc_buffer_push(client_id_list, client_id_list->data -
360 client_id_list->head);
361 silc_buffer_free(res_cmd);
363 silc_free(res_argv_lens);
364 silc_free(res_argv_types);
368 silc_buffer_push(client_id_list, client_id_list->data -
369 client_id_list->head);
371 /* We have the clients in cache, get them and call the completion */
372 silc_client_command_get_clients_list_callback((void *)in, NULL);
375 /* The old style function to find client entry. This is used by the
376 library internally. If `query' is TRUE then the client information is
377 requested by the server. The pending command callback must be set
380 SilcClientEntry silc_idlist_get_client(SilcClient client,
381 SilcClientConnection conn,
382 const char *nickname,
386 SilcIDCacheEntry id_cache;
387 SilcIDCacheList list = NULL;
388 SilcClientEntry entry = NULL;
390 SILC_LOG_DEBUG(("Start"));
392 /* Find ID from cache */
393 if (!silc_idcache_find_by_name(conn->client_cache, (char *)nickname,
399 SilcClientCommandContext ctx;
401 SILC_LOG_DEBUG(("Requesting Client ID from server"));
403 /* No ID found. Do query from the server. The query is done by
404 sending simple IDENTIFY command to the server. */
405 ctx = silc_client_command_alloc();
406 ctx->client = client;
408 ctx->command = silc_client_command_find("IDENTIFY");
409 memset(ident, 0, sizeof(ident));
410 snprintf(ident, sizeof(ident), "IDENTIFY %s", nickname);
411 silc_parse_command_line(ident, &ctx->argv, &ctx->argv_lens,
412 &ctx->argv_types, &ctx->argc, 2);
413 ctx->command->cb(ctx, NULL);
416 silc_idcache_list_free(list);
424 /* Take first found cache entry */
425 if (!silc_idcache_list_first(list, &id_cache))
428 entry = (SilcClientEntry)id_cache->context;
430 /* Check multiple cache entries for match */
431 silc_idcache_list_first(list, &id_cache);
433 entry = (SilcClientEntry)id_cache->context;
435 if (strcasecmp(entry->nickname, format)) {
436 if (!silc_idcache_list_next(list, &id_cache)) {
448 /* If match weren't found, request it */
454 silc_idcache_list_free(list);
459 /* Finds entry for client by the client's ID. Returns the entry or NULL
460 if the entry was not found. */
462 SilcClientEntry silc_client_get_client_by_id(SilcClient client,
463 SilcClientConnection conn,
464 SilcClientID *client_id)
466 SilcIDCacheEntry id_cache;
468 SILC_LOG_DEBUG(("Finding client by ID (%s)",
469 silc_id_render(client_id, SILC_ID_CLIENT)));
471 /* Find ID from cache */
472 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
474 silc_hash_client_id_compare, NULL,
478 SILC_LOG_DEBUG(("Found"));
480 return (SilcClientEntry)id_cache->context;
485 SilcClientConnection conn;
486 SilcClientID *client_id;
487 SilcGetClientCallback completion;
490 } *GetClientByIDInternal;
492 SILC_CLIENT_CMD_FUNC(get_client_by_id_callback)
494 GetClientByIDInternal i = (GetClientByIDInternal)context;
495 SilcClientEntry entry;
498 entry = silc_client_get_client_by_id(i->client, i->conn,
501 i->completion(i->client, i->conn, &entry, 1, i->context);
506 static void silc_client_get_client_by_id_destructor(void *context)
508 GetClientByIDInternal i = (GetClientByIDInternal)context;
510 if (i->found == FALSE)
511 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"));
533 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
534 silc_client_send_command(client, conn, SILC_COMMAND_WHOIS,
536 1, 3, idp->data, idp->len);
537 silc_buffer_free(idp);
541 i->client_id = silc_id_dup(client_id, SILC_ID_CLIENT);
542 i->completion = completion;
543 i->context = context;
545 /* Add pending callback */
546 silc_client_command_pending(conn, SILC_COMMAND_WHOIS,
548 silc_client_get_client_by_id_destructor,
549 silc_client_command_get_client_by_id_callback,
553 /* Creates new client entry and adds it to the ID cache. Returns pointer
557 silc_client_add_client(SilcClient client, SilcClientConnection conn,
558 char *nickname, char *username,
559 char *userinfo, SilcClientID *id, uint32 mode)
561 SilcClientEntry client_entry;
564 SILC_LOG_DEBUG(("Start"));
566 /* Save the client infos */
567 client_entry = silc_calloc(1, sizeof(*client_entry));
568 client_entry->id = id;
569 client_entry->valid = TRUE;
570 silc_parse_userfqdn(nickname, &nick, &client_entry->server);
571 silc_parse_userfqdn(username, &client_entry->username,
572 &client_entry->hostname);
574 client_entry->realname = strdup(userinfo);
575 client_entry->mode = mode;
577 client_entry->nickname = strdup(nick);
579 /* Format the nickname */
580 silc_client_nickname_format(client, conn, client_entry);
582 /* Add client to cache, the non-formatted nickname is saved to cache */
583 if (!silc_idcache_add(conn->client_cache, nick, client_entry->id,
584 (void *)client_entry, FALSE)) {
585 silc_free(client_entry->nickname);
586 silc_free(client_entry->username);
587 silc_free(client_entry->hostname);
588 silc_free(client_entry->server);
589 silc_free(client_entry);
596 /* Updates the `client_entry' with the new information sent as argument. */
598 void silc_client_update_client(SilcClient client,
599 SilcClientConnection conn,
600 SilcClientEntry client_entry,
601 const char *nickname,
602 const char *username,
603 const char *userinfo,
608 SILC_LOG_DEBUG(("Start"));
610 if (!client_entry->username && username)
611 silc_parse_userfqdn(username, &client_entry->username,
612 &client_entry->hostname);
613 if (!client_entry->realname && userinfo)
614 client_entry->realname = strdup(userinfo);
615 if (!client_entry->nickname && nickname) {
616 silc_parse_userfqdn(nickname, &nick, &client_entry->server);
617 client_entry->nickname = strdup(nick);
618 silc_client_nickname_format(client, conn, client_entry);
620 client_entry->mode = mode;
623 /* Remove the old cache entry and create a new one */
624 silc_idcache_del_by_context(conn->client_cache, client_entry);
625 silc_idcache_add(conn->client_cache, nick, client_entry->id,
626 client_entry, FALSE);
630 /* Deletes the client entry and frees all memory. */
632 void silc_client_del_client_entry(SilcClient client,
633 SilcClientEntry client_entry)
635 SILC_LOG_DEBUG(("Start"));
637 silc_free(client_entry->nickname);
638 silc_free(client_entry->username);
639 silc_free(client_entry->realname);
640 silc_free(client_entry->server);
641 silc_free(client_entry->id);
642 if (client_entry->send_key)
643 silc_cipher_free(client_entry->send_key);
644 if (client_entry->receive_key)
645 silc_cipher_free(client_entry->receive_key);
646 silc_free(client_entry->key);
647 silc_free(client_entry);
650 /* Removes client from the cache by the client entry. */
652 bool silc_client_del_client(SilcClient client, SilcClientConnection conn,
653 SilcClientEntry client_entry)
655 bool ret = silc_idcache_del_by_context(conn->client_cache, client_entry);
656 silc_client_del_client_entry(client, client_entry);
660 /* Removes channel from the cache by the channel entry. */
662 bool silc_client_del_channel(SilcClient client, SilcClientConnection conn,
663 SilcChannelEntry channel)
665 bool ret = silc_idcache_del_by_context(conn->channel_cache, channel);
666 silc_free(channel->channel_name);
667 silc_free(channel->id);
668 silc_free(channel->key);
669 if (channel->channel_key)
670 silc_cipher_free(channel->channel_key);
672 silc_hmac_free(channel->hmac);
673 if (channel->old_channel_key)
674 silc_cipher_free(channel->old_channel_key);
675 if (channel->old_hmac)
676 silc_hmac_free(channel->old_hmac);
677 if (channel->rekey_task)
678 silc_schedule_task_del(conn->client->schedule, channel->rekey_task);
679 silc_client_del_channel_private_keys(client, conn, channel);
684 /* Finds entry for channel by the channel name. Returns the entry or NULL
685 if the entry was not found. It is found only if the client is joined
688 SilcChannelEntry silc_client_get_channel(SilcClient client,
689 SilcClientConnection conn,
692 SilcIDCacheEntry id_cache;
693 SilcChannelEntry entry;
695 SILC_LOG_DEBUG(("Start"));
697 if (!silc_idcache_find_by_name_one(conn->channel_cache, channel,
701 entry = (SilcChannelEntry)id_cache->context;
706 /* Finds entry for channel by the channel ID. Returns the entry or NULL
707 if the entry was not found. It is found only if the client is joined
710 SilcChannelEntry silc_client_get_channel_by_id(SilcClient client,
711 SilcClientConnection conn,
712 SilcChannelID *channel_id)
714 SilcIDCacheEntry id_cache;
715 SilcChannelEntry entry;
717 SILC_LOG_DEBUG(("Start"));
719 if (!silc_idcache_find_by_id_one(conn->channel_cache, channel_id,
723 entry = (SilcChannelEntry)id_cache->context;
730 SilcClientConnection conn;
731 SilcChannelID *channel_id;
732 SilcGetChannelCallback completion;
735 } *GetChannelByIDInternal;
737 SILC_CLIENT_CMD_FUNC(get_channel_by_id_callback)
739 GetChannelByIDInternal i = (GetChannelByIDInternal)context;
740 SilcChannelEntry entry;
742 SILC_LOG_DEBUG(("Start"));
744 /* Get the channel */
745 entry = silc_client_get_channel_by_id(i->client, i->conn,
748 i->completion(i->client, i->conn, &entry, 1, i->context);
753 static void silc_client_get_channel_by_id_destructor(void *context)
755 GetChannelByIDInternal i = (GetChannelByIDInternal)context;
757 if (i->found == FALSE)
758 i->completion(i->client, i->conn, NULL, 0, i->context);
760 silc_free(i->channel_id);
764 /* Resolves channel information from the server by the channel ID. */
766 void silc_client_get_channel_by_id_resolve(SilcClient client,
767 SilcClientConnection conn,
768 SilcChannelID *channel_id,
769 SilcGetChannelCallback completion,
773 GetChannelByIDInternal i = silc_calloc(1, sizeof(*i));
775 SILC_LOG_DEBUG(("Start"));
777 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
778 silc_client_send_command(client, conn, SILC_COMMAND_IDENTIFY,
780 1, 5, idp->data, idp->len);
781 silc_buffer_free(idp);
785 i->channel_id = silc_id_dup(channel_id, SILC_ID_CHANNEL);
786 i->completion = completion;
787 i->context = context;
789 /* Add pending callback */
790 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
792 silc_client_get_channel_by_id_destructor,
793 silc_client_command_get_channel_by_id_callback,
797 /* Find channel entry by ID. This routine is used internally by the library. */
799 SilcChannelEntry silc_idlist_get_channel_by_id(SilcClient client,
800 SilcClientConnection conn,
801 SilcChannelID *channel_id,
805 SilcChannelEntry channel;
807 SILC_LOG_DEBUG(("Start"));
809 channel = silc_client_get_channel_by_id(client, conn, channel_id);
814 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
815 silc_client_send_command(client, conn, SILC_COMMAND_IDENTIFY,
817 1, 5, idp->data, idp->len);
818 silc_buffer_free(idp);
824 /* Finds entry for server by the server name. */
826 SilcServerEntry silc_client_get_server(SilcClient client,
827 SilcClientConnection conn,
830 SilcIDCacheEntry id_cache;
831 SilcServerEntry entry;
833 SILC_LOG_DEBUG(("Start"));
835 if (!silc_idcache_find_by_name_one(conn->server_cache, server_name,
839 entry = (SilcServerEntry)id_cache->context;
844 /* Finds entry for server by the server ID. */
846 SilcServerEntry silc_client_get_server_by_id(SilcClient client,
847 SilcClientConnection conn,
848 SilcServerID *server_id)
850 SilcIDCacheEntry id_cache;
851 SilcServerEntry entry;
853 SILC_LOG_DEBUG(("Start"));
855 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
859 entry = (SilcServerEntry)id_cache->context;
864 /* Removes server from the cache by the server entry. */
866 bool silc_client_del_server(SilcClient client, SilcClientConnection conn,
867 SilcServerEntry server)
869 bool ret = silc_idcache_del_by_context(conn->server_cache, server);
870 silc_free(server->server_name);
871 silc_free(server->server_info);
872 silc_free(server->server_id);
877 /* Formats the nickname of the client specified by the `client_entry'.
878 If the format is specified by the application this will format the
879 nickname and replace the old nickname in the client entry. If the
880 format string is not specified then this function has no effect. */
882 void silc_client_nickname_format(SilcClient client,
883 SilcClientConnection conn,
884 SilcClientEntry client_entry)
887 char *newnick = NULL;
889 SilcClientEntry *clients;
890 uint32 clients_count = 0;
892 SILC_LOG_DEBUG(("Start"));
894 if (!client->params->nickname_format[0])
897 if (!client_entry->nickname)
900 /* Get all clients with same nickname. Do not perform the formatting
901 if there aren't any clients with same nickname unless the application
902 is forcing us to do so. */
903 clients = silc_client_get_clients_local(client, conn,
904 client_entry->nickname, NULL,
906 if (!clients && !client->params->nickname_force_format)
910 for (i = 0; i < clients_count; i++)
911 if (clients[i]->valid)
916 cp = client->params->nickname_format;
926 if (!client_entry->nickname)
928 len = strlen(client_entry->nickname);
929 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
930 memcpy(&newnick[off], client_entry->nickname, len);
934 /* Stripped hostname */
935 if (!client_entry->hostname)
937 len = strcspn(client_entry->hostname, ".");
938 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
939 memcpy(&newnick[off], client_entry->hostname, len);
944 if (!client_entry->hostname)
946 len = strlen(client_entry->hostname);
947 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
948 memcpy(&newnick[off], client_entry->hostname, len);
952 /* Stripped server name */
953 if (!client_entry->server)
955 len = strcspn(client_entry->server, ".");
956 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
957 memcpy(&newnick[off], client_entry->server, len);
961 /* Full server name */
962 if (!client_entry->server)
964 len = strlen(client_entry->server);
965 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
966 memcpy(&newnick[off], client_entry->server, len);
970 /* Ascending number */
975 if (clients_count == 1)
978 for (i = 0; i < clients_count; i++) {
979 if (strncasecmp(clients[i]->nickname, newnick, off))
981 if (strlen(clients[i]->nickname) <= off)
983 num = atoi(&clients[i]->nickname[off]);
988 memset(tmp, 0, sizeof(tmp));
989 snprintf(tmp, sizeof(tmp) - 1, "%d", ++max);
991 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
992 memcpy(&newnick[off], tmp, len);
997 /* Some other character in the string */
998 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
999 memcpy(&newnick[off], cp, 1);
1007 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
1010 silc_free(client_entry->nickname);
1011 client_entry->nickname = newnick;