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 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
315 silc_free(client_id);
316 silc_buffer_pull(client_id_list, idp_len);
320 entry->status |= SILC_CLIENT_STATUS_RESOLVING;
323 /* No we don't have it, query it from the server. Assemble argument
324 table that will be sent fr the IDENTIFY command later. */
325 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
327 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
329 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
331 res_argv[res_argc] = client_id_list->data;
332 res_argv_lens[res_argc] = idp_len;
333 res_argv_types[res_argc] = res_argc + 5;
337 silc_free(client_id);
338 silc_buffer_pull(client_id_list, idp_len);
341 /* Query the client information from server if the list included clients
342 that we don't know about. */
346 /* Send the IDENTIFY command to server */
347 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
348 res_argc, res_argv, res_argv_lens,
349 res_argv_types, ++conn->cmd_ident);
350 silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
351 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
354 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
356 silc_client_get_clients_list_destructor,
357 silc_client_command_get_clients_list_callback,
360 silc_buffer_push(client_id_list, client_id_list->data -
361 client_id_list->head);
362 silc_buffer_free(res_cmd);
364 silc_free(res_argv_lens);
365 silc_free(res_argv_types);
369 silc_buffer_push(client_id_list, client_id_list->data -
370 client_id_list->head);
372 /* We have the clients in cache, get them and call the completion */
373 silc_client_command_get_clients_list_callback((void *)in, NULL);
376 /* The old style function to find client entry. This is used by the
377 library internally. If `query' is TRUE then the client information is
378 requested by the server. The pending command callback must be set
381 SilcClientEntry silc_idlist_get_client(SilcClient client,
382 SilcClientConnection conn,
383 const char *nickname,
387 SilcIDCacheEntry id_cache;
388 SilcIDCacheList list = NULL;
389 SilcClientEntry entry = NULL;
391 SILC_LOG_DEBUG(("Start"));
393 /* Find ID from cache */
394 if (!silc_idcache_find_by_name(conn->client_cache, (char *)nickname,
400 SilcClientCommandContext ctx;
402 SILC_LOG_DEBUG(("Requesting Client ID from server"));
404 /* No ID found. Do query from the server. The query is done by
405 sending simple IDENTIFY command to the server. */
406 ctx = silc_client_command_alloc();
407 ctx->client = client;
409 ctx->command = silc_client_command_find("IDENTIFY");
410 memset(ident, 0, sizeof(ident));
411 snprintf(ident, sizeof(ident), "IDENTIFY %s", nickname);
412 silc_parse_command_line(ident, &ctx->argv, &ctx->argv_lens,
413 &ctx->argv_types, &ctx->argc, 2);
414 ctx->command->cb(ctx, NULL);
417 silc_idcache_list_free(list);
425 /* Take first found cache entry */
426 if (!silc_idcache_list_first(list, &id_cache))
429 entry = (SilcClientEntry)id_cache->context;
431 /* Check multiple cache entries for match */
432 silc_idcache_list_first(list, &id_cache);
434 entry = (SilcClientEntry)id_cache->context;
436 if (strcasecmp(entry->nickname, format)) {
437 if (!silc_idcache_list_next(list, &id_cache)) {
449 /* If match weren't found, request it */
455 silc_idcache_list_free(list);
460 /* Finds entry for client by the client's ID. Returns the entry or NULL
461 if the entry was not found. */
463 SilcClientEntry silc_client_get_client_by_id(SilcClient client,
464 SilcClientConnection conn,
465 SilcClientID *client_id)
467 SilcIDCacheEntry id_cache;
469 SILC_LOG_DEBUG(("Finding client by ID (%s)",
470 silc_id_render(client_id, SILC_ID_CLIENT)));
472 /* Find ID from cache */
473 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
475 silc_hash_client_id_compare, NULL,
479 SILC_LOG_DEBUG(("Found"));
481 return (SilcClientEntry)id_cache->context;
486 SilcClientConnection conn;
487 SilcClientID *client_id;
488 SilcGetClientCallback completion;
491 } *GetClientByIDInternal;
493 SILC_CLIENT_CMD_FUNC(get_client_by_id_callback)
495 GetClientByIDInternal i = (GetClientByIDInternal)context;
496 SilcClientEntry entry;
499 entry = silc_client_get_client_by_id(i->client, i->conn,
502 i->completion(i->client, i->conn, &entry, 1, i->context);
507 static void silc_client_get_client_by_id_destructor(void *context)
509 GetClientByIDInternal i = (GetClientByIDInternal)context;
511 if (i->found == FALSE)
512 i->completion(i->client, i->conn, NULL, 0, i->context);
515 silc_free(i->client_id);
519 /* Same as above but will always resolve the information from the server.
520 Use this only if you know that you don't have the entry and the only
521 thing you know about the client is its ID. */
523 void silc_client_get_client_by_id_resolve(SilcClient client,
524 SilcClientConnection conn,
525 SilcClientID *client_id,
526 SilcGetClientCallback completion,
530 GetClientByIDInternal i = silc_calloc(1, sizeof(*i));
532 SILC_LOG_DEBUG(("Start"));
534 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
535 silc_client_send_command(client, conn, SILC_COMMAND_WHOIS,
537 1, 3, idp->data, idp->len);
538 silc_buffer_free(idp);
542 i->client_id = silc_id_dup(client_id, SILC_ID_CLIENT);
543 i->completion = completion;
544 i->context = context;
546 /* Add pending callback */
547 silc_client_command_pending(conn, SILC_COMMAND_WHOIS,
549 silc_client_get_client_by_id_destructor,
550 silc_client_command_get_client_by_id_callback,
554 /* Creates new client entry and adds it to the ID cache. Returns pointer
558 silc_client_add_client(SilcClient client, SilcClientConnection conn,
559 char *nickname, char *username,
560 char *userinfo, SilcClientID *id, uint32 mode)
562 SilcClientEntry client_entry;
565 SILC_LOG_DEBUG(("Start"));
567 /* Save the client infos */
568 client_entry = silc_calloc(1, sizeof(*client_entry));
569 client_entry->id = id;
570 client_entry->valid = TRUE;
571 silc_parse_userfqdn(nickname, &nick, &client_entry->server);
572 silc_parse_userfqdn(username, &client_entry->username,
573 &client_entry->hostname);
575 client_entry->realname = strdup(userinfo);
576 client_entry->mode = mode;
578 client_entry->nickname = strdup(nick);
580 /* Format the nickname */
581 silc_client_nickname_format(client, conn, client_entry);
583 /* Add client to cache, the non-formatted nickname is saved to cache */
584 if (!silc_idcache_add(conn->client_cache, nick, client_entry->id,
585 (void *)client_entry, FALSE)) {
586 silc_free(client_entry->nickname);
587 silc_free(client_entry->username);
588 silc_free(client_entry->hostname);
589 silc_free(client_entry->server);
590 silc_free(client_entry);
597 /* Updates the `client_entry' with the new information sent as argument. */
599 void silc_client_update_client(SilcClient client,
600 SilcClientConnection conn,
601 SilcClientEntry client_entry,
602 const char *nickname,
603 const char *username,
604 const char *userinfo,
609 SILC_LOG_DEBUG(("Start"));
611 if (!client_entry->username && username)
612 silc_parse_userfqdn(username, &client_entry->username,
613 &client_entry->hostname);
614 if (!client_entry->realname && userinfo)
615 client_entry->realname = strdup(userinfo);
616 if (!client_entry->nickname && nickname) {
617 silc_parse_userfqdn(nickname, &nick, &client_entry->server);
618 client_entry->nickname = strdup(nick);
619 silc_client_nickname_format(client, conn, client_entry);
621 client_entry->mode = mode;
624 /* Remove the old cache entry and create a new one */
625 silc_idcache_del_by_context(conn->client_cache, client_entry);
626 silc_idcache_add(conn->client_cache, nick, client_entry->id,
627 client_entry, FALSE);
631 /* Deletes the client entry and frees all memory. */
633 void silc_client_del_client_entry(SilcClient client,
634 SilcClientEntry client_entry)
636 SILC_LOG_DEBUG(("Start"));
638 silc_free(client_entry->nickname);
639 silc_free(client_entry->username);
640 silc_free(client_entry->realname);
641 silc_free(client_entry->server);
642 silc_free(client_entry->id);
643 if (client_entry->send_key)
644 silc_cipher_free(client_entry->send_key);
645 if (client_entry->receive_key)
646 silc_cipher_free(client_entry->receive_key);
647 silc_free(client_entry->key);
648 silc_free(client_entry);
651 /* Removes client from the cache by the client entry. */
653 bool silc_client_del_client(SilcClient client, SilcClientConnection conn,
654 SilcClientEntry client_entry)
656 bool ret = silc_idcache_del_by_context(conn->client_cache, client_entry);
657 silc_client_del_client_entry(client, client_entry);
661 /* Removes channel from the cache by the channel entry. */
663 bool silc_client_del_channel(SilcClient client, SilcClientConnection conn,
664 SilcChannelEntry channel)
666 bool ret = silc_idcache_del_by_context(conn->channel_cache, channel);
667 silc_free(channel->channel_name);
668 silc_free(channel->id);
669 silc_free(channel->key);
670 if (channel->channel_key)
671 silc_cipher_free(channel->channel_key);
673 silc_hmac_free(channel->hmac);
674 if (channel->old_channel_key)
675 silc_cipher_free(channel->old_channel_key);
676 if (channel->old_hmac)
677 silc_hmac_free(channel->old_hmac);
678 if (channel->rekey_task)
679 silc_schedule_task_del(conn->client->schedule, channel->rekey_task);
680 silc_client_del_channel_private_keys(client, conn, channel);
685 /* Finds entry for channel by the channel name. Returns the entry or NULL
686 if the entry was not found. It is found only if the client is joined
689 SilcChannelEntry silc_client_get_channel(SilcClient client,
690 SilcClientConnection conn,
693 SilcIDCacheEntry id_cache;
694 SilcChannelEntry entry;
696 SILC_LOG_DEBUG(("Start"));
698 if (!silc_idcache_find_by_name_one(conn->channel_cache, channel,
702 entry = (SilcChannelEntry)id_cache->context;
707 /* Finds entry for channel by the channel ID. Returns the entry or NULL
708 if the entry was not found. It is found only if the client is joined
711 SilcChannelEntry silc_client_get_channel_by_id(SilcClient client,
712 SilcClientConnection conn,
713 SilcChannelID *channel_id)
715 SilcIDCacheEntry id_cache;
716 SilcChannelEntry entry;
718 SILC_LOG_DEBUG(("Start"));
720 if (!silc_idcache_find_by_id_one(conn->channel_cache, channel_id,
724 entry = (SilcChannelEntry)id_cache->context;
731 SilcClientConnection conn;
732 SilcChannelID *channel_id;
733 SilcGetChannelCallback completion;
736 } *GetChannelByIDInternal;
738 SILC_CLIENT_CMD_FUNC(get_channel_by_id_callback)
740 GetChannelByIDInternal i = (GetChannelByIDInternal)context;
741 SilcChannelEntry entry;
743 SILC_LOG_DEBUG(("Start"));
745 /* Get the channel */
746 entry = silc_client_get_channel_by_id(i->client, i->conn,
749 i->completion(i->client, i->conn, &entry, 1, i->context);
754 static void silc_client_get_channel_by_id_destructor(void *context)
756 GetChannelByIDInternal i = (GetChannelByIDInternal)context;
758 if (i->found == FALSE)
759 i->completion(i->client, i->conn, NULL, 0, i->context);
761 silc_free(i->channel_id);
765 /* Resolves channel information from the server by the channel ID. */
767 void silc_client_get_channel_by_id_resolve(SilcClient client,
768 SilcClientConnection conn,
769 SilcChannelID *channel_id,
770 SilcGetChannelCallback completion,
774 GetChannelByIDInternal i = silc_calloc(1, sizeof(*i));
776 SILC_LOG_DEBUG(("Start"));
778 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
779 silc_client_send_command(client, conn, SILC_COMMAND_IDENTIFY,
781 1, 5, idp->data, idp->len);
782 silc_buffer_free(idp);
786 i->channel_id = silc_id_dup(channel_id, SILC_ID_CHANNEL);
787 i->completion = completion;
788 i->context = context;
790 /* Add pending callback */
791 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
793 silc_client_get_channel_by_id_destructor,
794 silc_client_command_get_channel_by_id_callback,
798 /* Find channel entry by ID. This routine is used internally by the library. */
800 SilcChannelEntry silc_idlist_get_channel_by_id(SilcClient client,
801 SilcClientConnection conn,
802 SilcChannelID *channel_id,
806 SilcChannelEntry channel;
808 SILC_LOG_DEBUG(("Start"));
810 channel = silc_client_get_channel_by_id(client, conn, channel_id);
815 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
816 silc_client_send_command(client, conn, SILC_COMMAND_IDENTIFY,
818 1, 5, idp->data, idp->len);
819 silc_buffer_free(idp);
825 /* Finds entry for server by the server name. */
827 SilcServerEntry silc_client_get_server(SilcClient client,
828 SilcClientConnection conn,
831 SilcIDCacheEntry id_cache;
832 SilcServerEntry entry;
834 SILC_LOG_DEBUG(("Start"));
836 if (!silc_idcache_find_by_name_one(conn->server_cache, server_name,
840 entry = (SilcServerEntry)id_cache->context;
845 /* Finds entry for server by the server ID. */
847 SilcServerEntry silc_client_get_server_by_id(SilcClient client,
848 SilcClientConnection conn,
849 SilcServerID *server_id)
851 SilcIDCacheEntry id_cache;
852 SilcServerEntry entry;
854 SILC_LOG_DEBUG(("Start"));
856 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
860 entry = (SilcServerEntry)id_cache->context;
865 /* Removes server from the cache by the server entry. */
867 bool silc_client_del_server(SilcClient client, SilcClientConnection conn,
868 SilcServerEntry server)
870 bool ret = silc_idcache_del_by_context(conn->server_cache, server);
871 silc_free(server->server_name);
872 silc_free(server->server_info);
873 silc_free(server->server_id);
878 /* Formats the nickname of the client specified by the `client_entry'.
879 If the format is specified by the application this will format the
880 nickname and replace the old nickname in the client entry. If the
881 format string is not specified then this function has no effect. */
883 void silc_client_nickname_format(SilcClient client,
884 SilcClientConnection conn,
885 SilcClientEntry client_entry)
888 char *newnick = NULL;
890 SilcClientEntry *clients;
891 uint32 clients_count = 0;
893 SILC_LOG_DEBUG(("Start"));
895 if (!client->params->nickname_format[0])
898 if (!client_entry->nickname)
901 /* Get all clients with same nickname. Do not perform the formatting
902 if there aren't any clients with same nickname unless the application
903 is forcing us to do so. */
904 clients = silc_client_get_clients_local(client, conn,
905 client_entry->nickname, NULL,
907 if (!clients && !client->params->nickname_force_format)
911 for (i = 0; i < clients_count; i++)
912 if (clients[i]->valid)
917 cp = client->params->nickname_format;
927 if (!client_entry->nickname)
929 len = strlen(client_entry->nickname);
930 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
931 memcpy(&newnick[off], client_entry->nickname, len);
935 /* Stripped hostname */
936 if (!client_entry->hostname)
938 len = strcspn(client_entry->hostname, ".");
939 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
940 memcpy(&newnick[off], client_entry->hostname, len);
945 if (!client_entry->hostname)
947 len = strlen(client_entry->hostname);
948 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
949 memcpy(&newnick[off], client_entry->hostname, len);
953 /* Stripped server name */
954 if (!client_entry->server)
956 len = strcspn(client_entry->server, ".");
957 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
958 memcpy(&newnick[off], client_entry->server, len);
962 /* Full server name */
963 if (!client_entry->server)
965 len = strlen(client_entry->server);
966 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
967 memcpy(&newnick[off], client_entry->server, len);
971 /* Ascending number */
976 if (clients_count == 1)
979 for (i = 0; i < clients_count; i++) {
980 if (strncasecmp(clients[i]->nickname, newnick, off))
982 if (strlen(clients[i]->nickname) <= off)
984 num = atoi(&clients[i]->nickname[off]);
989 memset(tmp, 0, sizeof(tmp));
990 snprintf(tmp, sizeof(tmp) - 1, "%d", ++max);
992 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
993 memcpy(&newnick[off], tmp, len);
998 /* Some other character in the string */
999 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
1000 memcpy(&newnick[off], cp, 1);
1008 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
1011 silc_free(client_entry->nickname);
1012 client_entry->nickname = newnick;