+/* Context for holding clients searched by public key. */
+typedef struct {
+ SilcClientEntry **clients;
+ SilcUInt32 *clients_count;
+ bool found;
+} *SilcServerPublicKeyUser, SilcServerPublicKeyUserStruct;
+
+void silc_server_public_key_hash_foreach(void *key, void *context,
+ void *user_context)
+{
+ SilcServerPublicKeyUser uc = user_context;
+ SilcClientEntry entry = context;
+
+ /* Nothing was found, just return */
+ if (!context)
+ return;
+
+ uc->found = TRUE;
+
+ (*uc->clients) = silc_realloc((*uc->clients),
+ sizeof((**uc->clients)) *
+ ((*uc->clients_count) + 1));
+ (*uc->clients)[(*uc->clients_count)++] = entry;
+}
+
+/* If clients are set, limit the found clients using the attributes in
+ the query. If clients are not set, try to find some clients using
+ the attributes */
+
+void silc_server_query_check_attributes(SilcServer server,
+ SilcServerQuery query,
+ SilcClientEntry **clients,
+ SilcUInt32 *clients_count) {
+ SilcClientEntry entry;
+ SilcAttributePayload attr;
+ SilcAttribute attribute;
+ SilcAttributeObjPk pk;
+ SilcPublicKey publickey;
+ int i;
+ bool found = FALSE, no_clients = FALSE;
+
+ /* If no clients were found, we only check the attributes
+ if the user wasn't searching for nickname/ids */
+ if (!(*clients)) {
+ no_clients = TRUE;
+ if (query->nickname || query->ids_count)
+ return;
+ }
+
+ silc_dlist_start(query->attrs);
+ while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
+ attribute = silc_attribute_get_attribute(attr);
+ switch (attribute) {
+
+ case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
+ SILC_LOG_DEBUG(("Finding clients by public key attribute"));
+
+ if (!silc_attribute_get_object(attr, &pk, sizeof(pk)))
+ continue;
+
+ if (!silc_pkcs_public_key_decode(pk.data, pk.data_len,
+ &publickey)) {
+ silc_free(pk.type);
+ silc_free(pk.data);
+ continue;
+ }
+
+ /* If no clients were set on calling this function, we
+ just search for clients, otherwise we try to limit
+ the clients */
+ if (no_clients) {
+ SilcServerPublicKeyUserStruct usercontext;
+
+ usercontext.clients = clients;
+ usercontext.clients_count = clients_count;
+ usercontext.found = FALSE;
+
+ silc_hash_table_find_foreach(server->pk_hash, publickey,
+ silc_server_public_key_hash_foreach,
+ &usercontext);
+
+ if (usercontext.found == TRUE)
+ found = TRUE;
+ } else {
+ for (i = 0; i < *clients_count; i++) {
+ entry = (*clients)[i];
+
+ if (!entry->data.public_key)
+ continue;
+
+ if (!silc_hash_table_find_by_context(server->pk_hash, publickey,
+ entry, NULL))
+ (*clients)[i] = NULL;
+ else
+ found = TRUE;
+ }
+ }
+ silc_free(pk.type);
+ silc_free(pk.data);
+ silc_pkcs_public_key_free(publickey);
+ break;
+ }
+ }
+
+ if (!found && !query->nickname && !query->ids)
+ silc_server_query_add_error(server, query, 2, 0,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+}
+