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);
222 /* Get the client entry */
223 if (silc_idcache_find_by_id_one_ext(i->conn->client_cache,
226 silc_hash_client_id_compare, NULL,
228 clients = silc_realloc(clients, sizeof(*clients) *
229 (clients_count + 1));
230 clients[clients_count] = (SilcClientEntry)id_cache->context;
235 silc_free(client_id);
236 silc_buffer_pull(client_id_list, idp_len);
240 i->completion(i->client, i->conn, clients, clients_count, i->context);
245 static void silc_client_get_clients_list_destructor(void *context)
247 GetClientsByListInternal i = (GetClientsByListInternal)context;
249 SILC_LOG_DEBUG(("Start"));
251 if (i->found == FALSE)
252 i->completion(i->client, i->conn, NULL, 0, i->context);
254 if (i->client_id_list)
255 silc_buffer_free(i->client_id_list);
259 /* Gets client entries by the list of client ID's `client_id_list'. This
260 always resolves those client ID's it does not know yet from the server
261 so this function might take a while. The `client_id_list' is a list
262 of ID Payloads added one after other. JOIN command reply and USERS
263 command reply for example returns this sort of list. The `completion'
264 will be called after the entries are available. */
266 void silc_client_get_clients_by_list(SilcClient client,
267 SilcClientConnection conn,
269 SilcBuffer client_id_list,
270 SilcGetClientCallback completion,
273 SilcIDCacheEntry id_cache = NULL;
275 unsigned char **res_argv = NULL;
276 uint32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
277 GetClientsByListInternal in;
279 SILC_LOG_DEBUG(("Start"));
281 in = silc_calloc(1, sizeof(*in));
284 in->list_count = list_count;
285 in->client_id_list = silc_buffer_copy(client_id_list);
286 in->completion = completion;
287 in->context = context;
289 for (i = 0; i < list_count; i++) {
291 SilcClientID *client_id;
292 SilcClientEntry entry;
295 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
297 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
301 /* Check if we have this client cached already. */
303 silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
305 silc_hash_client_id_compare, NULL,
308 /* If we don't have the entry or it has incomplete info, then resolve
309 it from the server. */
310 entry = id_cache ? (SilcClientEntry)id_cache->context : NULL;
311 if (!id_cache || !entry->nickname) {
314 if (entry->status & SILC_CLIENT_STATUS_RESOLVING) {
315 entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
316 silc_free(client_id);
317 silc_buffer_pull(client_id_list, idp_len);
321 entry->status |= SILC_CLIENT_STATUS_RESOLVING;
324 /* No we don't have it, query it from the server. Assemble argument
325 table that will be sent fr the IDENTIFY command later. */
326 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
328 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
330 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
332 res_argv[res_argc] = client_id_list->data;
333 res_argv_lens[res_argc] = idp_len;
334 res_argv_types[res_argc] = res_argc + 5;
338 silc_free(client_id);
339 silc_buffer_pull(client_id_list, idp_len);
342 /* Query the client information from server if the list included clients
343 that we don't know about. */
347 /* Send the IDENTIFY command to server */
348 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
349 res_argc, res_argv, res_argv_lens,
350 res_argv_types, ++conn->cmd_ident);
351 silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
352 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
355 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
357 silc_client_get_clients_list_destructor,
358 silc_client_command_get_clients_list_callback,
361 silc_buffer_push(client_id_list, client_id_list->data -
362 client_id_list->head);
363 silc_buffer_free(res_cmd);
365 silc_free(res_argv_lens);
366 silc_free(res_argv_types);
370 silc_buffer_push(client_id_list, client_id_list->data -
371 client_id_list->head);
373 /* We have the clients in cache, get them and call the completion */
374 silc_client_command_get_clients_list_callback((void *)in, NULL);
377 /* The old style function to find client entry. This is used by the
378 library internally. If `query' is TRUE then the client information is
379 requested by the server. The pending command callback must be set
382 SilcClientEntry silc_idlist_get_client(SilcClient client,
383 SilcClientConnection conn,
384 const char *nickname,
388 SilcIDCacheEntry id_cache;
389 SilcIDCacheList list = NULL;
390 SilcClientEntry entry = NULL;
392 SILC_LOG_DEBUG(("Start"));
394 /* Find ID from cache */
395 if (!silc_idcache_find_by_name(conn->client_cache, (char *)nickname,
401 SilcClientCommandContext ctx;
403 SILC_LOG_DEBUG(("Requesting Client ID from server"));
405 /* No ID found. Do query from the server. The query is done by
406 sending simple IDENTIFY command to the server. */
407 ctx = silc_client_command_alloc();
408 ctx->client = client;
410 ctx->command = silc_client_command_find("IDENTIFY");
411 memset(ident, 0, sizeof(ident));
412 snprintf(ident, sizeof(ident), "IDENTIFY %s", nickname);
413 silc_parse_command_line(ident, &ctx->argv, &ctx->argv_lens,
414 &ctx->argv_types, &ctx->argc, 2);
415 ctx->command->cb(ctx, NULL);
418 silc_idcache_list_free(list);
426 /* Take first found cache entry */
427 if (!silc_idcache_list_first(list, &id_cache))
430 entry = (SilcClientEntry)id_cache->context;
432 /* Check multiple cache entries for match */
433 silc_idcache_list_first(list, &id_cache);
435 entry = (SilcClientEntry)id_cache->context;
437 if (strcasecmp(entry->nickname, format)) {
438 if (!silc_idcache_list_next(list, &id_cache)) {
450 /* If match weren't found, request it */
456 silc_idcache_list_free(list);
461 /* Finds entry for client by the client's ID. Returns the entry or NULL
462 if the entry was not found. */
464 SilcClientEntry silc_client_get_client_by_id(SilcClient client,
465 SilcClientConnection conn,
466 SilcClientID *client_id)
468 SilcIDCacheEntry id_cache;
470 SILC_LOG_DEBUG(("Finding client by ID (%s)",
471 silc_id_render(client_id, SILC_ID_CLIENT)));
473 /* Find ID from cache */
474 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
476 silc_hash_client_id_compare, NULL,
480 SILC_LOG_DEBUG(("Found"));
482 return (SilcClientEntry)id_cache->context;
487 SilcClientConnection conn;
488 SilcClientID *client_id;
489 SilcGetClientCallback completion;
492 } *GetClientByIDInternal;
494 SILC_CLIENT_CMD_FUNC(get_client_by_id_callback)
496 GetClientByIDInternal i = (GetClientByIDInternal)context;
497 SilcClientEntry entry;
500 entry = silc_client_get_client_by_id(i->client, i->conn,
503 i->completion(i->client, i->conn, &entry, 1, i->context);
508 static void silc_client_get_client_by_id_destructor(void *context)
510 GetClientByIDInternal i = (GetClientByIDInternal)context;
512 if (i->found == FALSE)
513 i->completion(i->client, i->conn, NULL, 0, i->context);
516 silc_free(i->client_id);
520 /* Same as above but will always resolve the information from the server.
521 Use this only if you know that you don't have the entry and the only
522 thing you know about the client is its ID. */
524 void silc_client_get_client_by_id_resolve(SilcClient client,
525 SilcClientConnection conn,
526 SilcClientID *client_id,
527 SilcGetClientCallback completion,
531 GetClientByIDInternal i = silc_calloc(1, sizeof(*i));
533 SILC_LOG_DEBUG(("Start"));
535 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
536 silc_client_send_command(client, conn, SILC_COMMAND_WHOIS,
538 1, 3, idp->data, idp->len);
539 silc_buffer_free(idp);
543 i->client_id = silc_id_dup(client_id, SILC_ID_CLIENT);
544 i->completion = completion;
545 i->context = context;
547 /* Add pending callback */
548 silc_client_command_pending(conn, SILC_COMMAND_WHOIS,
550 silc_client_get_client_by_id_destructor,
551 silc_client_command_get_client_by_id_callback,
555 /* Creates new client entry and adds it to the ID cache. Returns pointer
559 silc_client_add_client(SilcClient client, SilcClientConnection conn,
560 char *nickname, char *username,
561 char *userinfo, SilcClientID *id, uint32 mode)
563 SilcClientEntry client_entry;
566 SILC_LOG_DEBUG(("Start"));
568 /* Save the client infos */
569 client_entry = silc_calloc(1, sizeof(*client_entry));
570 client_entry->id = id;
571 client_entry->valid = TRUE;
572 silc_parse_userfqdn(nickname, &nick, &client_entry->server);
573 silc_parse_userfqdn(username, &client_entry->username,
574 &client_entry->hostname);
576 client_entry->realname = strdup(userinfo);
577 client_entry->mode = mode;
579 client_entry->nickname = strdup(nick);
581 /* Format the nickname */
582 silc_client_nickname_format(client, conn, client_entry);
584 /* Add client to cache, the non-formatted nickname is saved to cache */
585 if (!silc_idcache_add(conn->client_cache, nick, client_entry->id,
586 (void *)client_entry, FALSE)) {
587 silc_free(client_entry->nickname);
588 silc_free(client_entry->username);
589 silc_free(client_entry->hostname);
590 silc_free(client_entry->server);
591 silc_free(client_entry);
598 /* Updates the `client_entry' with the new information sent as argument. */
600 void silc_client_update_client(SilcClient client,
601 SilcClientConnection conn,
602 SilcClientEntry client_entry,
603 const char *nickname,
604 const char *username,
605 const char *userinfo,
610 SILC_LOG_DEBUG(("Start"));
612 if (!client_entry->username && username)
613 silc_parse_userfqdn(username, &client_entry->username,
614 &client_entry->hostname);
615 if (!client_entry->realname && userinfo)
616 client_entry->realname = strdup(userinfo);
617 if (!client_entry->nickname && nickname) {
618 silc_parse_userfqdn(nickname, &nick, &client_entry->server);
619 client_entry->nickname = strdup(nick);
620 silc_client_nickname_format(client, conn, client_entry);
622 client_entry->mode = mode;
625 /* Remove the old cache entry and create a new one */
626 silc_idcache_del_by_context(conn->client_cache, client_entry);
627 silc_idcache_add(conn->client_cache, nick, client_entry->id,
628 client_entry, FALSE);
632 /* Deletes the client entry and frees all memory. */
634 void silc_client_del_client_entry(SilcClient client,
635 SilcClientConnection conn,
636 SilcClientEntry client_entry)
638 SILC_LOG_DEBUG(("Start"));
640 silc_free(client_entry->nickname);
641 silc_free(client_entry->username);
642 silc_free(client_entry->realname);
643 silc_free(client_entry->server);
644 silc_free(client_entry->id);
645 if (client_entry->send_key)
646 silc_cipher_free(client_entry->send_key);
647 if (client_entry->receive_key)
648 silc_cipher_free(client_entry->receive_key);
649 silc_free(client_entry->key);
650 silc_client_ftp_session_free_client(conn, client_entry);
651 silc_free(client_entry);
654 /* Removes client from the cache by the client entry. */
656 bool silc_client_del_client(SilcClient client, SilcClientConnection conn,
657 SilcClientEntry client_entry)
659 bool ret = silc_idcache_del_by_context(conn->client_cache, client_entry);
660 silc_client_del_client_entry(client, conn, client_entry);
664 /* Removes channel from the cache by the channel entry. */
666 bool silc_client_del_channel(SilcClient client, SilcClientConnection conn,
667 SilcChannelEntry channel)
669 bool ret = silc_idcache_del_by_context(conn->channel_cache, channel);
670 silc_free(channel->channel_name);
671 silc_free(channel->id);
672 silc_free(channel->key);
673 if (channel->channel_key)
674 silc_cipher_free(channel->channel_key);
676 silc_hmac_free(channel->hmac);
677 if (channel->old_channel_key)
678 silc_cipher_free(channel->old_channel_key);
679 if (channel->old_hmac)
680 silc_hmac_free(channel->old_hmac);
681 if (channel->rekey_task)
682 silc_schedule_task_del(conn->client->schedule, channel->rekey_task);
683 silc_client_del_channel_private_keys(client, conn, channel);
688 /* Finds entry for channel by the channel name. Returns the entry or NULL
689 if the entry was not found. It is found only if the client is joined
692 SilcChannelEntry silc_client_get_channel(SilcClient client,
693 SilcClientConnection conn,
696 SilcIDCacheEntry id_cache;
697 SilcChannelEntry entry;
699 SILC_LOG_DEBUG(("Start"));
701 if (!silc_idcache_find_by_name_one(conn->channel_cache, channel,
705 entry = (SilcChannelEntry)id_cache->context;
710 /* Finds entry for channel by the channel ID. Returns the entry or NULL
711 if the entry was not found. It is found only if the client is joined
714 SilcChannelEntry silc_client_get_channel_by_id(SilcClient client,
715 SilcClientConnection conn,
716 SilcChannelID *channel_id)
718 SilcIDCacheEntry id_cache;
719 SilcChannelEntry entry;
721 SILC_LOG_DEBUG(("Start"));
723 if (!silc_idcache_find_by_id_one(conn->channel_cache, channel_id,
727 entry = (SilcChannelEntry)id_cache->context;
734 SilcClientConnection conn;
735 SilcChannelID *channel_id;
736 SilcGetChannelCallback completion;
739 } *GetChannelByIDInternal;
741 SILC_CLIENT_CMD_FUNC(get_channel_by_id_callback)
743 GetChannelByIDInternal i = (GetChannelByIDInternal)context;
744 SilcChannelEntry entry;
746 SILC_LOG_DEBUG(("Start"));
748 /* Get the channel */
749 entry = silc_client_get_channel_by_id(i->client, i->conn,
752 i->completion(i->client, i->conn, &entry, 1, i->context);
757 static void silc_client_get_channel_by_id_destructor(void *context)
759 GetChannelByIDInternal i = (GetChannelByIDInternal)context;
761 if (i->found == FALSE)
762 i->completion(i->client, i->conn, NULL, 0, i->context);
764 silc_free(i->channel_id);
768 /* Resolves channel information from the server by the channel ID. */
770 void silc_client_get_channel_by_id_resolve(SilcClient client,
771 SilcClientConnection conn,
772 SilcChannelID *channel_id,
773 SilcGetChannelCallback completion,
777 GetChannelByIDInternal i = silc_calloc(1, sizeof(*i));
779 SILC_LOG_DEBUG(("Start"));
781 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
782 silc_client_send_command(client, conn, SILC_COMMAND_IDENTIFY,
784 1, 5, idp->data, idp->len);
785 silc_buffer_free(idp);
789 i->channel_id = silc_id_dup(channel_id, SILC_ID_CHANNEL);
790 i->completion = completion;
791 i->context = context;
793 /* Add pending callback */
794 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
796 silc_client_get_channel_by_id_destructor,
797 silc_client_command_get_channel_by_id_callback,
801 /* Find channel entry by ID. This routine is used internally by the library. */
803 SilcChannelEntry silc_idlist_get_channel_by_id(SilcClient client,
804 SilcClientConnection conn,
805 SilcChannelID *channel_id,
809 SilcChannelEntry channel;
811 SILC_LOG_DEBUG(("Start"));
813 channel = silc_client_get_channel_by_id(client, conn, channel_id);
818 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
819 silc_client_send_command(client, conn, SILC_COMMAND_IDENTIFY,
821 1, 5, idp->data, idp->len);
822 silc_buffer_free(idp);
828 /* Finds entry for server by the server name. */
830 SilcServerEntry silc_client_get_server(SilcClient client,
831 SilcClientConnection conn,
834 SilcIDCacheEntry id_cache;
835 SilcServerEntry entry;
837 SILC_LOG_DEBUG(("Start"));
839 if (!silc_idcache_find_by_name_one(conn->server_cache, server_name,
843 entry = (SilcServerEntry)id_cache->context;
848 /* Finds entry for server by the server ID. */
850 SilcServerEntry silc_client_get_server_by_id(SilcClient client,
851 SilcClientConnection conn,
852 SilcServerID *server_id)
854 SilcIDCacheEntry id_cache;
855 SilcServerEntry entry;
857 SILC_LOG_DEBUG(("Start"));
859 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
863 entry = (SilcServerEntry)id_cache->context;
868 /* Removes server from the cache by the server entry. */
870 bool silc_client_del_server(SilcClient client, SilcClientConnection conn,
871 SilcServerEntry server)
873 bool ret = silc_idcache_del_by_context(conn->server_cache, server);
874 silc_free(server->server_name);
875 silc_free(server->server_info);
876 silc_free(server->server_id);
881 /* Formats the nickname of the client specified by the `client_entry'.
882 If the format is specified by the application this will format the
883 nickname and replace the old nickname in the client entry. If the
884 format string is not specified then this function has no effect. */
886 void silc_client_nickname_format(SilcClient client,
887 SilcClientConnection conn,
888 SilcClientEntry client_entry)
891 char *newnick = NULL;
893 SilcClientEntry *clients;
894 uint32 clients_count = 0;
896 SILC_LOG_DEBUG(("Start"));
898 if (!client->params->nickname_format[0])
901 if (!client_entry->nickname)
904 /* Get all clients with same nickname. Do not perform the formatting
905 if there aren't any clients with same nickname unless the application
906 is forcing us to do so. */
907 clients = silc_client_get_clients_local(client, conn,
908 client_entry->nickname, NULL,
910 if (!clients && !client->params->nickname_force_format)
914 for (i = 0; i < clients_count; i++)
915 if (clients[i]->valid)
920 cp = client->params->nickname_format;
930 if (!client_entry->nickname)
932 len = strlen(client_entry->nickname);
933 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
934 memcpy(&newnick[off], client_entry->nickname, len);
938 /* Stripped hostname */
939 if (!client_entry->hostname)
941 len = strcspn(client_entry->hostname, ".");
942 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
943 memcpy(&newnick[off], client_entry->hostname, len);
948 if (!client_entry->hostname)
950 len = strlen(client_entry->hostname);
951 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
952 memcpy(&newnick[off], client_entry->hostname, len);
956 /* Stripped server name */
957 if (!client_entry->server)
959 len = strcspn(client_entry->server, ".");
960 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
961 memcpy(&newnick[off], client_entry->server, len);
965 /* Full server name */
966 if (!client_entry->server)
968 len = strlen(client_entry->server);
969 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
970 memcpy(&newnick[off], client_entry->server, len);
974 /* Ascending number */
979 if (clients_count == 1)
982 for (i = 0; i < clients_count; i++) {
983 if (strncasecmp(clients[i]->nickname, newnick, off))
985 if (strlen(clients[i]->nickname) <= off)
987 num = atoi(&clients[i]->nickname[off]);
992 memset(tmp, 0, sizeof(tmp));
993 snprintf(tmp, sizeof(tmp) - 1, "%d", ++max);
995 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
996 memcpy(&newnick[off], tmp, len);
1001 /* Some other character in the string */
1002 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
1003 memcpy(&newnick[off], cp, 1);
1011 newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
1014 silc_free(client_entry->nickname);
1015 client_entry->nickname = newnick;