5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2001 - 2006 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; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
22 #include "silcclient.h"
23 #include "client_internal.h"
25 /************************ Client Searching Locally **************************/
27 /* Finds entry for client by the client's ID. Returns the entry or NULL
28 if the entry was not found. */
30 SilcClientEntry silc_client_get_client_by_id(SilcClient client,
31 SilcClientConnection conn,
32 SilcClientID *client_id)
34 SilcIDCacheEntry id_cache;
35 SilcClientEntry client_entry;
37 if (!client || !conn || !client_id)
40 SILC_LOG_DEBUG(("Finding client by ID (%s)",
41 silc_id_render(client_id, SILC_ID_CLIENT)));
43 silc_mutex_lock(conn->internal->lock);
45 /* Find ID from cache */
46 if (!silc_idcache_find_by_id_one(conn->internal->client_cache, client_id,
48 silc_mutex_unlock(conn->internal->lock);
52 client_entry = id_cache->context;
55 silc_client_ref_client(client, conn, client_entry);
56 silc_mutex_unlock(conn->internal->lock);
58 SILC_LOG_DEBUG(("Found"));
63 /* Finds clients by nickname from local cache. */
65 SilcDList silc_client_get_clients_local(SilcClient client,
66 SilcClientConnection conn,
70 SilcIDCacheEntry id_cache;
73 SilcClientEntry entry;
76 if (!client || !conn || !nickname)
79 SILC_LOG_DEBUG(("Find clients by nickname %s", nickname));
81 /* Normalize nickname for search */
82 nicknamec = silc_identifier_check(nickname, strlen(nickname),
83 SILC_STRING_UTF8, 128, NULL);
87 clients = silc_dlist_init();
93 silc_mutex_lock(conn->internal->lock);
96 silc_list_init(list, struct SilcIDCacheEntryStruct, next);
97 if (!silc_idcache_find_by_name(conn->internal->client_cache, nicknamec,
99 silc_mutex_unlock(conn->internal->lock);
100 silc_free(nicknamec);
101 silc_dlist_uninit(clients);
106 /* Take all without any further checking */
107 silc_list_start(list);
108 while ((id_cache = silc_list_get(list))) {
109 silc_client_ref_client(client, conn, id_cache->context);
110 silc_dlist_add(clients, id_cache->context);
113 /* Check multiple cache entries for exact match */
114 silc_list_start(list);
115 while ((id_cache = silc_list_get(list))) {
116 entry = id_cache->context;
117 if (silc_utf8_strcasecmp(entry->nickname, format)) {
118 silc_client_ref_client(client, conn, entry);
119 silc_dlist_add(clients, entry);
124 silc_mutex_unlock(conn->internal->lock);
126 silc_dlist_start(clients);
128 silc_free(nicknamec);
132 /********************** Client Resolving from Server ************************/
134 /* Resolving context */
137 SilcGetClientCallback completion;
139 } *SilcClientGetClientInternal;
141 /* Resolving command callback */
143 static SilcBool silc_client_get_clients_cb(SilcClient client,
144 SilcClientConnection conn,
151 SilcClientGetClientInternal i = context;
152 SilcClientEntry client_entry;
154 if (error != SILC_STATUS_OK) {
155 SILC_LOG_DEBUG(("Resolving failed: %s", silc_get_status_message(error)));
157 i->completion(client, conn, error, NULL, i->context);
161 /* Add the returned client to list */
163 client_entry = va_arg(ap, SilcClientEntry);
164 silc_client_ref_client(client, conn, client_entry);
165 silc_dlist_add(i->clients, client_entry);
166 client_entry->internal.resolve_cmd_ident = 0;
169 if (status == SILC_STATUS_OK || status == SILC_STATUS_LIST_END) {
170 /* Deliver the clients to the caller */
172 SILC_LOG_DEBUG(("Resolved %d clients", silc_dlist_count(i->clients)));
173 silc_dlist_start(i->clients);
174 i->completion(client, conn, SILC_STATUS_OK, i->clients, i->context);
182 silc_client_list_free(client, conn, i->clients);
187 /* Resolves client information from server by the client ID. */
190 silc_client_get_client_by_id_resolve(SilcClient client,
191 SilcClientConnection conn,
192 SilcClientID *client_id,
193 SilcBuffer attributes,
194 SilcGetClientCallback completion,
197 SilcClientGetClientInternal i;
198 SilcClientEntry client_entry;
200 SilcUInt16 cmd_ident;
202 if (!client || !conn | !client_id)
205 SILC_LOG_DEBUG(("Resolve client by ID (%s)",
206 silc_id_render(client_id, SILC_ID_CLIENT)));
208 i = silc_calloc(1, sizeof(*i));
211 i->completion = completion;
212 i->context = context;
213 i->clients = silc_dlist_init();
219 /* Attach to resolving, if on going */
220 client_entry = silc_client_get_client_by_id(client, conn, client_id);
221 if (client_entry && client_entry->internal.resolve_cmd_ident) {
222 SILC_LOG_DEBUG(("Attach to existing resolving"));
223 silc_client_unref_client(client, conn, client_entry);
224 silc_client_command_pending(conn, SILC_COMMAND_NONE,
225 client_entry->internal.resolve_cmd_ident,
226 silc_client_get_clients_cb, i);
227 return client_entry->internal.resolve_cmd_ident;
230 /* Send the command */
231 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
232 cmd_ident = silc_client_command_send(client, conn, SILC_COMMAND_WHOIS,
233 silc_client_get_clients_cb, i,
234 2, 3, silc_buffer_datalen(attributes),
235 4, silc_buffer_datalen(idp));
236 if (!cmd_ident && completion)
237 completion(client, conn, SILC_STATUS_ERR_RESOURCE_LIMIT, NULL, context);
239 if (client_entry && cmd_ident)
240 client_entry->internal.resolve_cmd_ident = cmd_ident;
242 silc_client_unref_client(client, conn, client_entry);
243 silc_buffer_free(idp);
248 /* Finds client entry or entries by the `nickname' and `server'. The
249 completion callback will be called when the client entries has been
250 found. Used internally by the library. */
252 static SilcUInt16 silc_client_get_clients_i(SilcClient client,
253 SilcClientConnection conn,
255 const char *nickname,
257 SilcBuffer attributes,
258 SilcGetClientCallback completion,
261 SilcClientGetClientInternal i;
262 char userhost[768 + 1];
265 SILC_LOG_DEBUG(("Resolve client by %s command",
266 silc_get_command_name(command)));
268 if (!client || !conn)
270 if (!nickname && !attributes)
273 i = silc_calloc(1, sizeof(*i));
276 i->clients = silc_dlist_init();
281 i->completion = completion;
282 i->context = context;
284 memset(userhost, 0, sizeof(userhost));
285 if (nickname && server) {
286 len = strlen(nickname) + strlen(server) + 3;
287 silc_strncat(userhost, len, nickname, strlen(nickname));
288 silc_strncat(userhost, len, "@", 1);
289 silc_strncat(userhost, len, server, strlen(server));
290 } else if (nickname) {
291 silc_strncat(userhost, sizeof(userhost) - 1, nickname, strlen(nickname));
294 /* Send the command */
295 if (command == SILC_COMMAND_IDENTIFY)
296 return silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
297 silc_client_get_clients_cb, i,
298 1, 1, userhost, strlen(userhost));
299 return silc_client_command_send(client, conn, SILC_COMMAND_WHOIS,
300 silc_client_get_clients_cb, i,
301 2, 1, userhost, strlen(userhost),
302 3, silc_buffer_datalen(attributes));
305 /* Get clients from server with IDENTIFY command */
307 SilcUInt16 silc_client_get_clients(SilcClient client,
308 SilcClientConnection conn,
309 const char *nickname,
311 SilcGetClientCallback completion,
314 return silc_client_get_clients_i(client, conn, SILC_COMMAND_IDENTIFY,
315 nickname, server, NULL,
316 completion, context);
319 /* Get clients from server with WHOIS command */
321 SilcUInt16 silc_client_get_clients_whois(SilcClient client,
322 SilcClientConnection conn,
323 const char *nickname,
325 SilcBuffer attributes,
326 SilcGetClientCallback completion,
329 return silc_client_get_clients_i(client, conn, SILC_COMMAND_WHOIS,
330 nickname, server, attributes,
331 completion, context);
334 /* ID list resolving context */
336 SilcGetClientCallback completion;
338 SilcBuffer client_id_list;
339 SilcUInt32 list_count;
340 } *GetClientsByListInternal;
342 static SilcBool silc_client_get_clients_list_cb(SilcClient client,
343 SilcClientConnection conn,
350 GetClientsByListInternal i = context;
351 SilcClientEntry client_entry;
357 /* Process the list after all replies have been received */
358 if (status != SILC_STATUS_OK && !SILC_STATUS_IS_ERROR(status) &&
359 status != SILC_STATUS_LIST_END)
362 SILC_LOG_DEBUG(("Resolved all clients"));
364 clients = silc_dlist_init();
366 status = SILC_STATUS_ERR_RESOURCE_LIMIT;
370 for (c = 0; c < i->list_count; c++) {
372 SILC_GET16_MSB(idp_len, i->client_id_list->data + 2);
374 if (!silc_id_payload_parse_id(i->client_id_list->data, idp_len, &id)) {
375 status = SILC_STATUS_ERR_BAD_CLIENT_ID;
379 /* Get client entry */
380 client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
382 silc_dlist_add(clients, client_entry);
384 if (!silc_buffer_pull(i->client_id_list, idp_len)) {
385 status = SILC_STATUS_ERR_BAD_CLIENT_ID;
390 silc_dlist_start(clients);
391 status = SILC_STATUS_OK;
393 i->completion(client, conn, status, clients, i->context);
396 if (status != SILC_STATUS_OK && i->completion)
397 i->completion(client, conn, status, NULL, i->context);
399 silc_client_list_free(client, conn, clients);
400 silc_buffer_free(i->client_id_list);
406 /* Gets client entries by the list of client ID's `client_id_list'. This
407 always resolves those client ID's it does not know yet from the server
408 so this function might take a while. The `client_id_list' is a list
409 of ID Payloads added one after other. JOIN command reply and USERS
410 command reply for example returns this sort of list. The `completion'
411 will be called after the entries are available. */
413 SilcUInt16 silc_client_get_clients_by_list(SilcClient client,
414 SilcClientConnection conn,
415 SilcUInt32 list_count,
416 SilcBuffer client_id_list,
417 SilcGetClientCallback completion,
420 GetClientsByListInternal in;
421 SilcClientEntry entry;
422 unsigned char **res_argv = NULL;
423 SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
424 SilcUInt16 idp_len, cmd_ident;
428 SILC_LOG_DEBUG(("Resolve clients from Client ID list"));
430 if (!client || !conn || !client_id_list)
433 in = silc_calloc(1, sizeof(*in));
436 in->completion = completion;
437 in->context = context;
438 in->list_count = list_count;
439 in->client_id_list = silc_buffer_copy(client_id_list);
440 if (!in->client_id_list)
443 for (i = 0; i < list_count; i++) {
445 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
447 if (!silc_id_payload_parse_id(client_id_list->data, idp_len, &id))
450 /* Check if we have this client cached already. If we don't have the
451 entry or it has incomplete info, then resolve it from the server. */
452 entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
453 if (!entry || !entry->nickname[0] || !entry->username[0] ||
456 res_argv = silc_calloc(list_count, sizeof(*res_argv));
457 res_argv_lens = silc_calloc(list_count, sizeof(*res_argv_lens));
458 res_argv_types = silc_calloc(list_count, sizeof(*res_argv_types));
459 if (!res_argv || !res_argv_lens || !res_argv_types) {
460 silc_client_unref_client(client, conn, entry);
465 res_argv[res_argc] = client_id_list->data;
466 res_argv_lens[res_argc] = idp_len;
467 res_argv_types[res_argc] = res_argc + 4;
470 silc_client_unref_client(client, conn, entry);
472 if (!silc_buffer_pull(client_id_list, idp_len))
475 silc_buffer_start(client_id_list);
477 /* Query the unknown client information from server */
479 cmd_ident = silc_client_command_send_argv(client,
480 conn, SILC_COMMAND_WHOIS,
481 silc_client_get_clients_list_cb,
482 in, res_argc, res_argv,
486 silc_free(res_argv_lens);
487 silc_free(res_argv_types);
491 /* We have the clients in cache, get them and call the completion */
492 silc_client_get_clients_list_cb(client, conn, SILC_COMMAND_WHOIS,
493 SILC_STATUS_OK, SILC_STATUS_OK, in, NULL);
497 silc_buffer_free(in->client_id_list);
500 silc_free(res_argv_lens);
501 silc_free(res_argv_types);
508 SilcClientConnection conn;
509 SilcChannelID channel_id;
510 SilcGetClientCallback completion;
513 } *GetClientsByChannelInternal;
515 SILC_CLIENT_CMD_FUNC(get_clients_by_channel_cb)
517 GetClientsByChannelInternal i = context;
518 SilcClientEntry *clients = NULL;
519 SilcUInt32 clients_count = 0;
520 SilcBool found = FALSE;
521 SilcChannelEntry channel;
522 SilcHashTableList htl;
531 channel = silc_client_get_channel_by_id(i->client, i->conn, &i->channel_id);
532 if (channel && !silc_hash_table_count(channel->user_list)) {
533 clients = silc_calloc(silc_hash_table_count(channel->user_list),
535 silc_hash_table_list(channel->user_list, &htl);
536 while (silc_hash_table_get(&htl, NULL, (void *)&chu))
537 clients[clients_count++] = chu->client;
538 silc_hash_table_list_reset(&htl);
543 i->completion(i->client, i->conn, clients, clients_count, i->context);
546 i->completion(i->client, i->conn, NULL, 0, i->context);
552 /* Gets client entries by the channel entry indicated by `channel'. Thus,
553 it resolves the clients currently on that channel. */
555 void silc_client_get_clients_by_channel(SilcClient client,
556 SilcClientConnection conn,
557 SilcChannelEntry channel,
558 SilcGetClientCallback completion,
561 GetClientsByChannelInternal in;
562 SilcHashTableList htl;
564 SilcClientEntry entry;
565 unsigned char **res_argv = NULL;
566 SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
568 SilcBool wait_res = FALSE;
570 assert(client && conn && channel);
572 SILC_LOG_DEBUG(("Start"));
574 in = silc_calloc(1, sizeof(*in));
577 in->channel_id = *channel->id;
578 in->completion = completion;
579 in->context = context;
581 /* If user list does not exist, send USERS command. */
582 if (!channel->user_list || !silc_hash_table_count(channel->user_list)) {
583 SILC_LOG_DEBUG(("Sending USERS"));
584 silc_client_command_register(client, SILC_COMMAND_USERS, NULL, NULL,
585 silc_client_command_reply_users_i, 0,
587 silc_client_command_send(client, conn, SILC_COMMAND_USERS,
588 conn->cmd_ident, 1, 2, channel->channel_name,
589 strlen(channel->channel_name));
590 silc_client_command_pending(conn, SILC_COMMAND_USERS, conn->cmd_ident,
591 silc_client_command_get_clients_by_channel_cb,
596 silc_hash_table_list(channel->user_list, &htl);
597 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
600 /* If the entry has incomplete info, then resolve it from the server. */
601 if (!entry->nickname[0] || !entry->realname) {
602 if (entry->status & SILC_CLIENT_STATUS_RESOLVING) {
603 /* Attach to this resolving and wait until it finishes */
604 silc_client_command_pending(
605 conn, SILC_COMMAND_NONE,
606 entry->resolve_cmd_ident,
607 silc_client_command_get_clients_by_channel_cb,
613 entry->status |= SILC_CLIENT_STATUS_RESOLVING;
614 entry->resolve_cmd_ident = conn->cmd_ident + 1;
616 idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
618 /* No we don't have it, query it from the server. Assemble argument
619 table that will be sent for the WHOIS command later. */
620 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
622 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
624 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
626 res_argv[res_argc] = silc_memdup(idp->data, idp->len);
627 res_argv_lens[res_argc] = idp->len;
628 res_argv_types[res_argc] = res_argc + 4;
631 silc_buffer_free(idp);
634 silc_hash_table_list_reset(&htl);
636 /* Query the client information from server if the list included clients
637 that we don't know about. */
641 /* Send the WHOIS command to server */
642 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
643 res_argc, res_argv, res_argv_lens,
644 res_argv_types, ++conn->cmd_ident);
645 silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
646 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
649 /* Register our own command reply for this command */
650 silc_client_command_register(client, SILC_COMMAND_WHOIS, NULL, NULL,
651 silc_client_command_reply_whois_i, 0,
654 /* Process the applications request after reply has been received */
655 silc_client_command_pending(
656 conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
657 silc_client_command_get_clients_by_channel_cb,
661 silc_buffer_free(res_cmd);
663 silc_free(res_argv_lens);
664 silc_free(res_argv_types);
671 /* We have the clients in cache, get them and call the completion */
672 silc_client_command_get_clients_by_channel_cb((void *)in, NULL);
677 /************************** Client Entry Routines ***************************/
679 /* Creates new client entry and adds it to the ID cache. Returns pointer
682 SilcClientEntry silc_client_add_client(SilcClient client,
683 SilcClientConnection conn,
684 char *nickname, char *username,
685 char *userinfo, SilcClientID *id,
688 SilcClientEntry client_entry;
691 SILC_LOG_DEBUG(("Adding new client entry"));
693 /* Save the client infos */
694 client_entry = silc_calloc(1, sizeof(*client_entry));
698 silc_atomic_init8(&client_entry->internal.refcnt, 0);
699 client_entry->id = *id;
700 client_entry->internal.valid = TRUE;
701 client_entry->mode = mode;
702 client_entry->realname = userinfo ? strdup(userinfo) : NULL;
703 silc_parse_userfqdn(nickname, client_entry->nickname,
704 sizeof(client_entry->nickname),
705 client_entry->server,
706 sizeof(client_entry->server));
707 silc_parse_userfqdn(username, client_entry->username,
708 sizeof(client_entry->username),
709 client_entry->hostname,
710 sizeof(client_entry->hostname));
711 client_entry->channels = silc_hash_table_alloc(1, silc_hash_ptr, NULL, NULL,
712 NULL, NULL, NULL, TRUE);
713 if (!client_entry->channels) {
714 silc_free(client_entry->realname);
715 silc_free(client_entry);
719 /* Normalize nickname */
720 if (client_entry->nickname[0]) {
721 nick = silc_identifier_check(client_entry->nickname,
722 strlen(client_entry->nickname),
723 SILC_STRING_UTF8, 128, NULL);
725 silc_free(client_entry->realname);
726 silc_hash_table_free(client_entry->channels);
727 silc_free(client_entry);
732 /* Format the nickname */
733 silc_client_nickname_format(client, conn, client_entry, FALSE);
735 silc_mutex_lock(conn->internal->lock);
737 /* Add client to cache, the normalized nickname is saved to cache */
738 if (!silc_idcache_add(conn->internal->client_cache, nick,
739 &client_entry->id, client_entry)) {
741 silc_free(client_entry->realname);
742 silc_hash_table_free(client_entry->channels);
743 silc_free(client_entry);
744 silc_mutex_unlock(conn->internal->lock);
748 client_entry->nickname_normalized = nick;
750 silc_mutex_unlock(conn->internal->lock);
751 silc_client_ref_client(client, conn, client_entry);
753 SILC_LOG_DEBUG(("Added %p", client_entry));
758 /* Updates the `client_entry' with the new information sent as argument. */
760 void silc_client_update_client(SilcClient client,
761 SilcClientConnection conn,
762 SilcClientEntry client_entry,
763 const char *nickname,
764 const char *username,
765 const char *userinfo,
770 SILC_LOG_DEBUG(("Update client entry"));
772 if (!client_entry->realname && userinfo)
773 client_entry->realname = strdup(userinfo);
774 if ((!client_entry->username[0] || !client_entry->hostname[0]) && username)
775 silc_parse_userfqdn(username, client_entry->username,
776 sizeof(client_entry->username),
777 client_entry->hostname,
778 sizeof(client_entry->username));
779 if (!client_entry->nickname[0] && nickname) {
780 silc_parse_userfqdn(nickname, client_entry->nickname,
781 sizeof(client_entry->nickname),
782 client_entry->server,
783 sizeof(client_entry->server));
785 /* Normalize nickname */
786 nick = silc_identifier_check(client_entry->nickname,
787 strlen(client_entry->nickname),
788 SILC_STRING_UTF8, 128, NULL);
792 /* Format nickname */
793 silc_client_nickname_format(client, conn, client_entry,
794 client_entry == conn->local_entry);
796 /* Update cache entry */
797 silc_mutex_lock(conn->internal->lock);
798 silc_idcache_update_by_context(conn->internal->client_cache,
799 client_entry, NULL, nick, TRUE);
800 silc_mutex_unlock(conn->internal->lock);
801 client_entry->nickname_normalized = nick;
803 client_entry->mode = mode;
806 /* Change a client's nickname */
808 SilcBool silc_client_change_nickname(SilcClient client,
809 SilcClientConnection conn,
810 SilcClientEntry client_entry,
811 const char *new_nick,
812 SilcClientID *new_id,
813 const unsigned char *idp,
818 SILC_LOG_DEBUG(("Change nickname %s to %s", client_entry->nickname,
821 /* Normalize nickname */
822 tmp = silc_identifier_check(new_nick, strlen(new_nick),
823 SILC_STRING_UTF8, 128, NULL);
827 /* Update the client entry */
828 silc_mutex_lock(conn->internal->lock);
829 if (!silc_idcache_update_by_context(conn->internal->client_cache,
830 client_entry, new_id, tmp, TRUE)) {
832 silc_mutex_unlock(conn->internal->lock);
835 silc_mutex_unlock(conn->internal->lock);
837 memset(client_entry->nickname, 0, sizeof(client_entry->nickname));
838 memcpy(client_entry->nickname, new_nick, strlen(new_nick));
839 client_entry->nickname_normalized = tmp;
840 silc_client_nickname_format(client, conn, client_entry,
841 client_entry == conn->local_entry);
843 /* For my client entry, update ID and set new ID to packet stream */
844 if (client_entry == conn->local_entry) {
845 if (idp && idp_len) {
846 silc_buffer_enlarge(conn->internal->local_idp, idp_len);
847 silc_buffer_put(conn->internal->local_idp, idp, idp_len);
850 silc_packet_set_ids(conn->stream, SILC_ID_CLIENT, conn->local_id,
857 /* Deletes the client entry and frees all memory. */
859 void silc_client_del_client_entry(SilcClient client,
860 SilcClientConnection conn,
861 SilcClientEntry client_entry)
863 silc_free(client_entry->realname);
864 silc_free(client_entry->nickname_normalized);
865 silc_free(client_entry->internal.key);
866 if (client_entry->public_key)
867 silc_pkcs_public_key_free(client_entry->public_key);
868 silc_hash_table_free(client_entry->channels);
869 if (client_entry->internal.send_key)
870 silc_cipher_free(client_entry->internal.send_key);
871 if (client_entry->internal.receive_key)
872 silc_cipher_free(client_entry->internal.receive_key);
873 if (client_entry->internal.hmac_send)
874 silc_hmac_free(client_entry->internal.hmac_send);
875 if (client_entry->internal.hmac_receive)
876 silc_hmac_free(client_entry->internal.hmac_receive);
878 silc_client_ftp_session_free_client(conn, client_entry);
879 if (client_entry->internal->ke)
880 silc_client_abort_key_agreement(client, conn, client_entry);
882 silc_atomic_uninit8(&client_entry->internal.refcnt);
883 silc_free(client_entry);
886 /* Removes client from the cache by the client entry. */
888 SilcBool silc_client_del_client(SilcClient client, SilcClientConnection conn,
889 SilcClientEntry client_entry)
896 if (silc_atomic_sub_int8(&client_entry->internal.refcnt, 1) > 0)
899 SILC_LOG_DEBUG(("Deleting client %p", client_entry));
901 silc_mutex_lock(conn->internal->lock);
902 ret = silc_idcache_del_by_context(conn->internal->client_cache,
904 silc_mutex_unlock(conn->internal->lock);
907 /* Remove from channels */
908 silc_client_remove_from_channels(client, conn, client_entry);
910 /* Free the client entry data */
911 silc_client_del_client_entry(client, conn, client_entry);
917 /* Take reference of client entry */
919 void silc_client_ref_client(SilcClient client, SilcClientConnection conn,
920 SilcClientEntry client_entry)
922 silc_atomic_add_int8(&client_entry->internal.refcnt, 1);
923 SILC_LOG_DEBUG(("Client %p refcnt %d->%d", client_entry,
924 silc_atomic_get_int8(&client_entry->internal.refcnt) - 1,
925 silc_atomic_get_int8(&client_entry->internal.refcnt)));
928 /* Release reference of client entry */
930 void silc_client_unref_client(SilcClient client, SilcClientConnection conn,
931 SilcClientEntry client_entry)
934 SILC_LOG_DEBUG(("Client %p refcnt %d->%d", client_entry,
935 silc_atomic_get_int8(&client_entry->internal.refcnt),
936 silc_atomic_get_int8(&client_entry->internal.refcnt) - 1));
937 silc_client_del_client(client, conn, client_entry);
941 /* Free client entry list */
943 void silc_client_list_free(SilcClient client, SilcClientConnection conn,
944 SilcDList client_list)
946 SilcClientEntry client_entry;
949 silc_dlist_start(client_list);
950 while ((client_entry = silc_dlist_get(client_list)))
951 silc_client_unref_client(client, conn, client_entry);
953 silc_dlist_uninit(client_list);
957 /* Formats the nickname of the client specified by the `client_entry'.
958 If the format is specified by the application this will format the
959 nickname and replace the old nickname in the client entry. If the
960 format string is not specified then this function has no effect.
961 Returns the client entry that was formatted. */
963 SilcClientEntry silc_client_nickname_format(SilcClient client,
964 SilcClientConnection conn,
965 SilcClientEntry client_entry,
969 char newnick[128 + 1];
973 SilcClientEntry entry, unformatted = NULL;
975 SILC_LOG_DEBUG(("Format nickname"));
977 if (!client->internal->params->nickname_format[0])
979 if (!client_entry->nickname[0])
982 /* Get all clients with same nickname. Do not perform the formatting
983 if there aren't any clients with same nickname unless the application
984 is forcing us to do so. */
985 clients = silc_client_get_clients_local(client, conn,
986 client_entry->nickname, NULL);
989 if (silc_dlist_count(clients) == 1 &&
990 !client->internal->params->nickname_force_format) {
991 silc_client_list_free(client, conn, clients);
997 while ((entry = silc_dlist_get(clients))) {
998 if (entry->internal.valid && entry != client_entry)
1000 if (entry->internal.valid && entry != client_entry &&
1001 silc_utf8_strcasecmp(entry->nickname, client_entry->nickname)) {
1003 unformatted = entry;
1007 if (!len || freebase) {
1008 silc_client_list_free(client, conn, clients);
1009 return client_entry;
1012 /* If priority formatting, this client always gets unformatted nickname. */
1013 if (unformatted && priority)
1014 client_entry = unformatted;
1016 memset(newnick, 0, sizeof(newnick));
1017 cp = client->internal->params->nickname_format;
1027 if (!client_entry->nickname[0])
1029 len = strlen(client_entry->nickname);
1030 memcpy(&newnick[off], client_entry->nickname, len);
1034 /* Stripped hostname */
1035 if (!client_entry->hostname[0])
1037 len = strcspn(client_entry->hostname, ".");
1038 i = strcspn(client_entry->hostname, "-");
1041 memcpy(&newnick[off], client_entry->hostname, len);
1046 if (!client_entry->hostname[0])
1048 len = strlen(client_entry->hostname);
1049 memcpy(&newnick[off], client_entry->hostname, len);
1053 /* Stripped server name */
1054 if (!client_entry->server)
1056 len = strcspn(client_entry->server, ".");
1057 memcpy(&newnick[off], client_entry->server, len);
1061 /* Full server name */
1062 if (!client_entry->server)
1064 len = strlen(client_entry->server);
1065 memcpy(&newnick[off], client_entry->server, len);
1069 /* Ascending number */
1074 if (silc_dlist_count(clients) == 1)
1077 silc_dlist_start(clients);
1078 while ((entry = silc_dlist_get(clients))) {
1079 if (!silc_utf8_strncasecmp(entry->nickname, newnick, off))
1081 if (strlen(entry->nickname) <= off)
1083 num = atoi(&entry->nickname[off]);
1088 memset(tmp, 0, sizeof(tmp));
1089 snprintf(tmp, sizeof(tmp) - 1, "%d", ++max);
1091 memcpy(&newnick[off], tmp, len);
1096 /* Some other character in the string */
1097 memcpy(&newnick[off], cp, 1);
1106 memcpy(client_entry->nickname, newnick, strlen(newnick));
1107 silc_client_list_free(client, conn, clients);
1109 return client_entry;
1112 /* Parses nickname according to nickname format string */
1114 SilcBool silc_client_nickname_parse(SilcClient client,
1115 SilcClientConnection conn,
1119 char *cp, s = 0, e = 0, *nick;
1123 if (!client->internal->params->nickname_format[0])
1126 if (!nickname || !nickname[0])
1129 cp = client->internal->params->nickname_format;
1149 /* Get separator character */
1162 /* Parse the nickname */
1166 if (strchr(nickname, s))
1167 nick = strchr(nickname, s) + 1;
1169 if (strchr(nick, e))
1170 len = strchr(nick, e) - nick;
1174 *ret_nick = silc_memdup(nick, len);
1178 SILC_LOG_DEBUG(("Parsed nickname: %s", *ret_nick));
1183 /************************ Channel Searching Locally *************************/
1185 /* Finds entry for channel by the channel name. Returns the entry or NULL
1186 if the entry was not found. It is found only if the client is joined
1189 SilcChannelEntry silc_client_get_channel(SilcClient client,
1190 SilcClientConnection conn,
1193 SilcIDCacheEntry id_cache;
1194 SilcChannelEntry entry;
1196 if (!client || !conn || !channel)
1199 SILC_LOG_DEBUG(("Find channel %s", channel));
1201 /* Normalize name for search */
1202 channel = silc_channel_name_check(channel, strlen(channel), SILC_STRING_UTF8,
1207 silc_mutex_lock(conn->internal->lock);
1209 if (!silc_idcache_find_by_name_one(conn->internal->channel_cache, channel,
1211 silc_mutex_unlock(conn->internal->lock);
1216 SILC_LOG_DEBUG(("Found"));
1218 entry = id_cache->context;
1221 silc_client_ref_channel(client, conn, entry);
1222 silc_mutex_unlock(conn->internal->lock);
1229 /* Finds entry for channel by the channel ID. Returns the entry or NULL
1230 if the entry was not found. It is found only if the client is joined
1233 SilcChannelEntry silc_client_get_channel_by_id(SilcClient client,
1234 SilcClientConnection conn,
1235 SilcChannelID *channel_id)
1237 SilcIDCacheEntry id_cache;
1238 SilcChannelEntry entry;
1240 if (!client || !conn || !channel_id)
1243 SILC_LOG_DEBUG(("Find channel by id %s",
1244 silc_id_render(channel_id, SILC_ID_CHANNEL)));
1246 silc_mutex_lock(conn->internal->lock);
1248 if (!silc_idcache_find_by_id_one(conn->internal->channel_cache, channel_id,
1250 silc_mutex_unlock(conn->internal->lock);
1254 SILC_LOG_DEBUG(("Found"));
1256 entry = id_cache->context;
1259 silc_client_ref_channel(client, conn, entry);
1260 silc_mutex_unlock(conn->internal->lock);
1265 /********************** Channel Resolving from Server ***********************/
1267 /* Channel resolving context */
1270 SilcGetChannelCallback completion;
1272 } *SilcClientGetChannelInternal;
1274 /* Resolving command callback */
1276 static SilcBool silc_client_get_channel_cb(SilcClient client,
1277 SilcClientConnection conn,
1278 SilcCommand command,
1284 SilcClientGetChannelInternal i = context;
1285 SilcChannelEntry entry;
1287 if (error != SILC_STATUS_OK) {
1288 SILC_LOG_DEBUG(("Resolving failed: %s", silc_get_status_message(error)));
1290 i->completion(client, conn, error, NULL, i->context);
1294 /* Add the returned channel to list */
1295 if (i->completion) {
1296 entry = va_arg(ap, SilcChannelEntry);
1297 silc_client_ref_channel(client, conn, entry);
1298 silc_dlist_add(i->channels, entry);
1301 if (status == SILC_STATUS_OK || status == SILC_STATUS_LIST_END) {
1302 /* Deliver the channels to the caller */
1303 if (i->completion) {
1304 SILC_LOG_DEBUG(("Resolved %d channels", silc_dlist_count(i->channels)));
1305 silc_dlist_start(i->channels);
1306 i->completion(client, conn, SILC_STATUS_OK, i->channels, i->context);
1314 silc_client_list_free_channels(client, conn, i->channels);
1319 /* Resolves channel entry from the server by the channel name. */
1321 void silc_client_get_channel_resolve(SilcClient client,
1322 SilcClientConnection conn,
1324 SilcGetChannelCallback completion,
1327 SilcClientGetChannelInternal i;
1329 if (!client || !conn || !channel_name || !completion)
1332 SILC_LOG_DEBUG(("Resolve channel %s", channel_name));
1334 i = silc_calloc(1, sizeof(*i));
1337 i->completion = completion;
1338 i->context = context;
1339 i->channels = silc_dlist_init();
1345 /* Send the command */
1346 if (!silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
1347 silc_client_get_channel_cb, i, 1,
1348 3, channel_name, strlen(channel_name))) {
1350 completion(client, conn, SILC_STATUS_ERR_RESOURCE_LIMIT, NULL, context);
1354 /* Resolves channel information from the server by the channel ID. */
1357 silc_client_get_channel_by_id_resolve(SilcClient client,
1358 SilcClientConnection conn,
1359 SilcChannelID *channel_id,
1360 SilcGetChannelCallback completion,
1363 SilcClientGetChannelInternal i;
1365 SilcUInt16 cmd_ident;
1367 if (!client || !conn || !channel_id || !completion)
1370 SILC_LOG_DEBUG(("Resolve channel by id %s",
1371 silc_id_render(channel_id, SILC_ID_CHANNEL)));
1373 i = silc_calloc(1, sizeof(*i));
1376 i->completion = completion;
1377 i->context = context;
1378 i->channels = silc_dlist_init();
1384 /* Send the command */
1385 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
1386 cmd_ident = silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
1387 silc_client_get_channel_cb, i, 1,
1388 5, silc_buffer_datalen(idp));
1389 silc_buffer_free(idp);
1390 if (!cmd_ident && completion)
1391 completion(client, conn, SILC_STATUS_ERR_RESOURCE_LIMIT, NULL, context);
1396 /************************* Channel Entry Routines ***************************/
1398 /* Add new channel entry to the ID Cache */
1400 SilcChannelEntry silc_client_add_channel(SilcClient client,
1401 SilcClientConnection conn,
1402 const char *channel_name,
1404 SilcChannelID *channel_id)
1406 SilcChannelEntry channel;
1407 char *channel_namec;
1409 SILC_LOG_DEBUG(("Start"));
1411 channel = silc_calloc(1, sizeof(*channel));
1415 silc_atomic_init16(&channel->internal.refcnt, 0);
1416 channel->id = *channel_id;
1417 channel->mode = mode;
1419 channel->channel_name = strdup(channel_name);
1420 if (!channel->channel_name) {
1425 channel->user_list = silc_hash_table_alloc(1, silc_hash_ptr, NULL, NULL,
1426 NULL, NULL, NULL, TRUE);
1427 if (!channel->user_list) {
1428 silc_free(channel->channel_name);
1433 /* Normalize channel name */
1434 channel_namec = silc_channel_name_check(channel_name, strlen(channel_name),
1435 SILC_STRING_UTF8, 256, NULL);
1436 if (!channel_namec) {
1437 silc_free(channel->channel_name);
1438 silc_hash_table_free(channel->user_list);
1443 silc_mutex_lock(conn->internal->lock);
1445 /* Add channel to cache, the normalized channel name is saved to cache */
1446 if (!silc_idcache_add(conn->internal->channel_cache, channel_namec,
1447 &channel->id, channel)) {
1448 silc_free(channel_namec);
1449 silc_free(channel->channel_name);
1450 silc_hash_table_free(channel->user_list);
1452 silc_mutex_unlock(conn->internal->lock);
1456 silc_mutex_unlock(conn->internal->lock);
1457 silc_client_ref_channel(client, conn, channel);
1459 SILC_LOG_DEBUG(("Added %p", channel));
1464 /* Removes channel from the cache by the channel entry. */
1466 SilcBool silc_client_del_channel(SilcClient client, SilcClientConnection conn,
1467 SilcChannelEntry channel)
1476 if (silc_atomic_sub_int16(&channel->internal.refcnt, 1) > 0)
1479 SILC_LOG_DEBUG(("Deleting channel %p", channel));
1481 silc_mutex_lock(conn->internal->lock);
1482 ret = silc_idcache_del_by_context(conn->internal->channel_cache,
1484 silc_mutex_unlock(conn->internal->lock);
1489 silc_client_empty_channel(client, conn, channel);
1490 silc_hash_table_free(channel->user_list);
1491 silc_free(channel->channel_name);
1492 silc_free(channel->topic);
1493 if (channel->founder_key)
1494 silc_pkcs_public_key_free(channel->founder_key);
1495 if (channel->internal.channel_key)
1496 silc_cipher_free(channel->internal.channel_key);
1497 if (channel->internal.hmac)
1498 silc_hmac_free(channel->internal.hmac);
1499 if (channel->internal.old_channel_keys) {
1500 silc_dlist_start(channel->internal.old_channel_keys);
1501 while ((key = silc_dlist_get(channel->internal.old_channel_keys)))
1502 silc_cipher_free(key);
1503 silc_dlist_uninit(channel->internal.old_channel_keys);
1505 if (channel->internal.old_hmacs) {
1506 silc_dlist_start(channel->internal.old_hmacs);
1507 while ((hmac = silc_dlist_get(channel->internal.old_hmacs)))
1508 silc_hmac_free(hmac);
1509 silc_dlist_uninit(channel->internal.old_hmacs);
1511 if (channel->channel_pubkeys)
1512 silc_argument_list_free(channel->channel_pubkeys,
1513 SILC_ARGUMENT_PUBLIC_KEY);
1514 silc_client_del_channel_private_keys(client, conn, channel);
1515 silc_atomic_uninit16(&channel->internal.refcnt);
1516 silc_schedule_task_del_by_context(conn->client->schedule, channel);
1522 /* Replaces the channel ID of the `channel' to `new_id'. Returns FALSE
1523 if the ID could not be changed. */
1525 SilcBool silc_client_replace_channel_id(SilcClient client,
1526 SilcClientConnection conn,
1527 SilcChannelEntry channel,
1528 SilcChannelID *new_id)
1530 SilcBool ret = FALSE;
1535 SILC_LOG_DEBUG(("Old Channel ID id(%s)",
1536 silc_id_render(&channel->id, SILC_ID_CHANNEL)));
1537 SILC_LOG_DEBUG(("New Channel ID id(%s)",
1538 silc_id_render(new_id, SILC_ID_CHANNEL)));
1541 silc_mutex_lock(conn->internal->lock);
1542 silc_idcache_update_by_context(conn->internal->channel_cache, channel,
1543 new_id, NULL, FALSE);
1544 silc_mutex_unlock(conn->internal->lock);
1549 /* Take reference of channel entry */
1551 void silc_client_ref_channel(SilcClient client, SilcClientConnection conn,
1552 SilcChannelEntry channel_entry)
1554 silc_atomic_add_int16(&channel_entry->internal.refcnt, 1);
1555 SILC_LOG_DEBUG(("Channel %p refcnt %d->%d", channel_entry,
1556 silc_atomic_get_int16(&channel_entry->internal.refcnt) - 1,
1557 silc_atomic_get_int16(&channel_entry->internal.refcnt)));
1560 /* Release reference of channel entry */
1562 void silc_client_unref_channel(SilcClient client, SilcClientConnection conn,
1563 SilcChannelEntry channel_entry)
1565 if (channel_entry) {
1566 SILC_LOG_DEBUG(("Channel %p refcnt %d->%d", channel_entry,
1567 silc_atomic_get_int16(&channel_entry->internal.refcnt),
1568 silc_atomic_get_int16(&channel_entry->internal.refcnt)
1570 silc_client_del_channel(client, conn, channel_entry);
1574 /* Free channel entry list */
1576 void silc_client_list_free_channels(SilcClient client,
1577 SilcClientConnection conn,
1578 SilcDList channel_list)
1580 SilcChannelEntry channel_entry;
1583 silc_dlist_start(channel_list);
1584 while ((channel_entry = silc_dlist_get(channel_list)))
1585 silc_client_unref_channel(client, conn, channel_entry);
1587 silc_dlist_uninit(channel_list);
1591 /************************* Server Searching Locally *************************/
1593 /* Finds entry for server by the server name. */
1595 SilcServerEntry silc_client_get_server(SilcClient client,
1596 SilcClientConnection conn,
1599 SilcIDCacheEntry id_cache;
1600 SilcServerEntry entry;
1602 if (!client || !conn || !server_name)
1605 SILC_LOG_DEBUG(("Find server by name %s", server_name));
1607 /* Normalize server name for search */
1608 server_name = silc_identifier_check(server_name, strlen(server_name),
1609 SILC_STRING_UTF8, 256, NULL);
1613 silc_mutex_lock(conn->internal->lock);
1615 if (!silc_idcache_find_by_name_one(conn->internal->server_cache,
1616 server_name, &id_cache)) {
1617 silc_free(server_name);
1618 silc_mutex_unlock(conn->internal->lock);
1622 SILC_LOG_DEBUG(("Found"));
1625 entry = id_cache->context;
1626 silc_client_ref_server(client, conn, entry);
1628 silc_mutex_unlock(conn->internal->lock);
1630 silc_free(server_name);
1635 /* Finds entry for server by the server ID. */
1637 SilcServerEntry silc_client_get_server_by_id(SilcClient client,
1638 SilcClientConnection conn,
1639 SilcServerID *server_id)
1641 SilcIDCacheEntry id_cache;
1642 SilcServerEntry entry;
1644 if (!client || !conn || !server_id)
1647 SILC_LOG_DEBUG(("Find server by id %s",
1648 silc_id_render(server_id, SILC_ID_SERVER)));
1650 silc_mutex_lock(conn->internal->lock);
1652 if (!silc_idcache_find_by_id_one(conn->internal->server_cache,
1653 server_id, &id_cache)) {
1654 silc_mutex_unlock(conn->internal->lock);
1658 SILC_LOG_DEBUG(("Found"));
1661 entry = id_cache->context;
1662 silc_client_ref_server(client, conn, entry);
1664 silc_mutex_unlock(conn->internal->lock);
1669 /*********************** Server Resolving from Server ***********************/
1671 /* Resolving context */
1674 SilcGetServerCallback completion;
1676 } *SilcClientGetServerInternal;
1678 /* Resolving command callback */
1680 static SilcBool silc_client_get_server_cb(SilcClient client,
1681 SilcClientConnection conn,
1682 SilcCommand command,
1688 SilcClientGetServerInternal i = context;
1689 SilcServerEntry server;
1691 if (error != SILC_STATUS_OK) {
1692 SILC_LOG_DEBUG(("Resolving failed: %s", silc_get_status_message(error)));
1694 i->completion(client, conn, error, NULL, i->context);
1698 /* Add the returned servers to list */
1699 if (i->completion) {
1700 server = va_arg(ap, SilcServerEntry);
1701 silc_client_ref_server(client, conn, server);
1702 silc_dlist_add(i->servers, server);
1703 server->internal.resolve_cmd_ident = 0;
1706 if (status == SILC_STATUS_OK || status == SILC_STATUS_LIST_END) {
1707 /* Deliver the servers to the caller */
1708 if (i->completion) {
1709 SILC_LOG_DEBUG(("Resolved %d servers", silc_dlist_count(i->servers)));
1710 silc_dlist_start(i->servers);
1711 i->completion(client, conn, SILC_STATUS_OK, i->servers, i->context);
1719 silc_client_list_free_servers(client, conn, i->servers);
1724 /* Resolve server by server ID */
1727 silc_client_get_server_by_id_resolve(SilcClient client,
1728 SilcClientConnection conn,
1729 SilcServerID *server_id,
1730 SilcGetServerCallback completion,
1733 SilcClientGetServerInternal i;
1734 SilcServerEntry server;
1736 SilcUInt16 cmd_ident;
1738 if (!client || !conn || !server_id || !completion)
1741 SILC_LOG_DEBUG(("Resolve server by id %s",
1742 silc_id_render(server_id, SILC_ID_SERVER)));
1744 i = silc_calloc(1, sizeof(*i));
1747 i->completion = completion;
1748 i->context = context;
1749 i->servers = silc_dlist_init();
1755 /* Attach to resolving, if on going */
1756 server = silc_client_get_server_by_id(client, conn, server_id);
1757 if (server && server->internal.resolve_cmd_ident) {
1758 SILC_LOG_DEBUG(("Attach to existing resolving"));
1759 silc_client_unref_server(client, conn, server);
1760 silc_client_command_pending(conn, SILC_COMMAND_NONE,
1761 server->internal.resolve_cmd_ident,
1762 silc_client_get_server_cb, i);
1763 return server->internal.resolve_cmd_ident;
1766 /* Send the command */
1767 idp = silc_id_payload_encode(server_id, SILC_ID_SERVER);
1768 cmd_ident = silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
1769 silc_client_get_server_cb, i, 1,
1770 5, silc_buffer_datalen(idp));
1771 silc_buffer_free(idp);
1772 if (!cmd_ident && completion)
1773 completion(client, conn, SILC_STATUS_ERR_RESOURCE_LIMIT, NULL, context);
1775 if (server && cmd_ident)
1776 server->internal.resolve_cmd_ident = cmd_ident;
1778 silc_client_unref_server(client, conn, server);
1783 /************************** Server Entry Routines ***************************/
1785 /* Add new server entry */
1787 SilcServerEntry silc_client_add_server(SilcClient client,
1788 SilcClientConnection conn,
1789 const char *server_name,
1790 const char *server_info,
1791 SilcServerID *server_id)
1793 SilcServerEntry server_entry;
1794 char *server_namec = NULL;
1799 SILC_LOG_DEBUG(("Adding new server %s", server_name));
1801 server_entry = silc_calloc(1, sizeof(*server_entry));
1805 silc_atomic_init8(&server_entry->internal.refcnt, 0);
1806 server_entry->id = *server_id;
1808 server_entry->server_name = strdup(server_name);
1810 server_entry->server_info = strdup(server_info);
1812 /* Normalize server name */
1814 server_namec = silc_identifier_check(server_name, strlen(server_name),
1815 SILC_STRING_UTF8, 256, NULL);
1816 if (!server_namec) {
1817 silc_free(server_entry->server_name);
1818 silc_free(server_entry->server_info);
1819 silc_free(server_entry);
1824 silc_mutex_lock(conn->internal->lock);
1826 /* Add server to cache */
1827 if (!silc_idcache_add(conn->internal->server_cache, server_namec,
1828 &server_entry->id, server_entry)) {
1829 silc_free(server_namec);
1830 silc_free(server_entry->server_name);
1831 silc_free(server_entry->server_info);
1832 silc_free(server_entry);
1833 silc_mutex_unlock(conn->internal->lock);
1837 silc_mutex_unlock(conn->internal->lock);
1838 silc_client_ref_server(client, conn, server_entry);
1840 SILC_LOG_DEBUG(("Added %p", server_entry));
1842 return server_entry;
1845 /* Removes server from the cache by the server entry. */
1847 SilcBool silc_client_del_server(SilcClient client, SilcClientConnection conn,
1848 SilcServerEntry server)
1855 if (silc_atomic_sub_int8(&server->internal.refcnt, 1) > 0)
1858 SILC_LOG_DEBUG(("Deleting server %p", server));
1860 silc_mutex_lock(conn->internal->lock);
1861 ret = silc_idcache_del_by_context(conn->internal->server_cache,
1863 silc_mutex_unlock(conn->internal->lock);
1865 silc_free(server->server_name);
1866 silc_free(server->server_info);
1867 if (server->public_key)
1868 silc_pkcs_public_key_free(server->public_key);
1869 silc_atomic_uninit8(&server->internal.refcnt);
1875 /* Updates the `server_entry' with the new information sent as argument. */
1877 void silc_client_update_server(SilcClient client,
1878 SilcClientConnection conn,
1879 SilcServerEntry server_entry,
1880 const char *server_name,
1881 const char *server_info)
1883 char *server_namec = NULL;
1885 SILC_LOG_DEBUG(("Updating server %p", server_entry));
1888 (!server_entry->server_name ||
1889 !silc_utf8_strcasecmp(server_entry->server_name, server_name))) {
1891 server_namec = silc_identifier_check(server_name, strlen(server_name),
1892 SILC_STRING_UTF8, 256, NULL);
1896 silc_free(server_entry->server_name);
1897 server_entry->server_name = strdup(server_name);
1898 if (!server_entry->server_name)
1901 /* Update cache entry */
1902 silc_mutex_lock(conn->internal->lock);
1903 silc_idcache_update_by_context(conn->internal->server_cache, server_entry,
1904 NULL, server_namec, TRUE);
1905 silc_mutex_unlock(conn->internal->lock);
1909 (!server_entry->server_info ||
1910 !silc_utf8_strcasecmp(server_entry->server_info, server_info))) {
1911 silc_free(server_entry->server_info);
1912 server_entry->server_info = strdup(server_info);
1916 /* Take reference of server entry */
1918 void silc_client_ref_server(SilcClient client, SilcClientConnection conn,
1919 SilcServerEntry server_entry)
1921 silc_atomic_add_int8(&server_entry->internal.refcnt, 1);
1922 SILC_LOG_DEBUG(("Server %p refcnt %d->%d", server_entry,
1923 silc_atomic_get_int8(&server_entry->internal.refcnt) - 1,
1924 silc_atomic_get_int8(&server_entry->internal.refcnt)));
1927 /* Release reference of server entry */
1929 void silc_client_unref_server(SilcClient client, SilcClientConnection conn,
1930 SilcServerEntry server_entry)
1933 SILC_LOG_DEBUG(("Server %p refcnt %d->%d", server_entry,
1934 silc_atomic_get_int8(&server_entry->internal.refcnt),
1935 silc_atomic_get_int8(&server_entry->internal.refcnt)
1937 silc_client_del_server(client, conn, server_entry);
1941 /* Free server entry list */
1943 void silc_client_list_free_servers(SilcClient client,
1944 SilcClientConnection conn,
1945 SilcDList server_list)
1947 SilcServerEntry server_entry;
1950 silc_dlist_start(server_list);
1951 while ((server_entry = silc_dlist_get(server_list)))
1952 silc_client_unref_server(client, conn, server_entry);
1954 silc_dlist_uninit(server_list);