src/reclaim/json_reclaim.c
src/reclaim/oidc_helper.c
src/reclaim/plugin_gnsrecord_reclaim.c
-src/reclaim/plugin_reclaim_sqlite.c
src/reclaim/plugin_rest_openid_connect.c
src/reclaim/plugin_rest_reclaim.c
src/reclaim/reclaim_api.c
#define GNUNET_PROTOCOLS_H
#ifdef __cplusplus
-extern "C"
-{
-#if 0 /* keep Emacsens' auto-indent happy */
+extern "C" {
+#if 0 /* keep Emacsens' auto-indent happy */
}
#endif
#endif
#define GNUNET_MESSAGE_TYPE_DV_DISCONNECT 50
/**
- * P2P DV message telling plugin that a message transmission failed (negative ACK)
+ * P2P DV message telling plugin that a message transmission failed (negative
+ * ACK)
*/
#define GNUNET_MESSAGE_TYPE_DV_SEND_NACK 51
/**
* Receive information about transiting GETs
*/
-#define GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET 149
+#define GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET 149
/**
* Receive information about transiting GET responses
*/
-#define GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET_RESP 150
+#define GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET_RESP 150
/**
* Receive information about transiting PUTs
*/
-#define GNUNET_MESSAGE_TYPE_DHT_MONITOR_PUT 151
+#define GNUNET_MESSAGE_TYPE_DHT_MONITOR_PUT 151
/**
* Receive information about transiting PUT responses (TODO)
*/
-#define GNUNET_MESSAGE_TYPE_DHT_MONITOR_PUT_RESP 152
+#define GNUNET_MESSAGE_TYPE_DHT_MONITOR_PUT_RESP 152
/**
* Request information about transiting messages
*/
-#define GNUNET_MESSAGE_TYPE_DHT_MONITOR_START 153
+#define GNUNET_MESSAGE_TYPE_DHT_MONITOR_START 153
/**
* Stop information about transiting messages
*/
-#define GNUNET_MESSAGE_TYPE_DHT_MONITOR_STOP 154
+#define GNUNET_MESSAGE_TYPE_DHT_MONITOR_STOP 154
/**
* Certain results are already known to the client, filter those.
*/
-#define GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET_RESULTS_KNOWN 156
+#define GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET_RESULTS_KNOWN 156
/**
* Further X-VINE DHT messages continued from 880
#define GNUNET_MESSAGE_TYPE_DNS_HELPER 214
-
/*******************************************************************************
* CHAT message types START
******************************************************************************/
#define GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION 480
/**
- * Message to signal the result of #GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS request
+ * Message to signal the result of #GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS
+ * request
*/
#define GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT 481
#define GNUNET_MESSAGE_TYPE_CONSENSUS_CLIENT_CONCLUDE 524
/**
- * Sent by service to client in order to signal a completed consensus conclusion.
- * Last message sent in a consensus session.
+ * Sent by service to client in order to signal a completed consensus
+ * conclusion. Last message sent in a consensus session.
*/
#define GNUNET_MESSAGE_TYPE_CONSENSUS_CLIENT_CONCLUDE_DONE 525
#define GNUNET_MESSAGE_TYPE_CONSENSUS_P2P_HELLO 546
/**
- * Report that the peer is synced with the partner after successfuly decoding the invertible bloom filter.
+ * Report that the peer is synced with the partner after successfuly decoding
+ * the invertible bloom filter.
*/
#define GNUNET_MESSAGE_TYPE_CONSENSUS_P2P_SYNCED 547
#define GNUNET_MESSAGE_TYPE_TESTBED_LOGGER_ACK 601
-
/**
* Advertise regex capability.
*/
#define GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_BOB_CRYPTODATA 652
-
-
-
/*******************************************************************************
* PSYCSTORE message types
******************************************************************************/
/** S<--C: PSYC message which contains one or more message parts. */
#define GNUNET_MESSAGE_TYPE_PSYC_MESSAGE 691
-/** M<->S<->C: PSYC message which contains a header and one or more message parts. */
-#define GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_HEADER 692 // FIXME: start using this where appropriate
+/** M<->S<->C: PSYC message which contains a header and one or more message
+ * parts. */
+#define GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_HEADER \
+ 692 // FIXME: start using this where appropriate
/** Message part: method */
#define GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD 693
#define GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE_END 762
-
/*******************************************************************************
* SECRETSHARING message types
******************************************************************************/
/**
* Acknowledge receiving ACT MALICIOUS request
*/
-#define GNUNET_MESSAGE_TYPE_DHT_CLIENT_ACT_MALICIOUS_OK 894
+#define GNUNET_MESSAGE_TYPE_DHT_CLIENT_ACT_MALICIOUS_OK 894
#endif
/**
* RPS check liveliness message to check liveliness of other peer
*/
-#define GNUNET_MESSAGE_TYPE_RPS_PP_CHECK_LIVE 950
+#define GNUNET_MESSAGE_TYPE_RPS_PP_CHECK_LIVE 950
/**
* RPS PUSH message to push own ID to another peer
*/
-#define GNUNET_MESSAGE_TYPE_RPS_PP_PUSH 951
+#define GNUNET_MESSAGE_TYPE_RPS_PP_PUSH 951
/**
* RPS PULL REQUEST message to request the local view of another peer
*/
-#define GNUNET_MESSAGE_TYPE_RPS_PP_PULL_REQUEST 952
+#define GNUNET_MESSAGE_TYPE_RPS_PP_PULL_REQUEST 952
/**
* RPS PULL REPLY message which contains the view of the other peer
*/
-#define GNUNET_MESSAGE_TYPE_RPS_PP_PULL_REPLY 953
-
+#define GNUNET_MESSAGE_TYPE_RPS_PP_PULL_REPLY 953
/* Client-Service Messages */
/**
* RPS CS SEED Message for the Client to seed peers into rps
*/
-#define GNUNET_MESSAGE_TYPE_RPS_CS_SEED 954
+#define GNUNET_MESSAGE_TYPE_RPS_CS_SEED 954
#if ENABLE_MALICIOUS
/**
* Turn RPS service malicious
*/
-#define GNUNET_MESSAGE_TYPE_RPS_ACT_MALICIOUS 955
+#define GNUNET_MESSAGE_TYPE_RPS_ACT_MALICIOUS 955
#endif /* ENABLE_MALICIOUS */
/**
* RPS client-service message to start a sub sampler
*/
-#define GNUNET_MESSAGE_TYPE_RPS_CS_SUB_START 956
+#define GNUNET_MESSAGE_TYPE_RPS_CS_SUB_START 956
/**
* RPS client-service message to stop a sub sampler
*/
-#define GNUNET_MESSAGE_TYPE_RPS_CS_SUB_STOP 957
+#define GNUNET_MESSAGE_TYPE_RPS_CS_SUB_STOP 957
/* Debugging API continues at 1130 */
*/
#define GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE 961
-#define GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE_RESPONSE 962
+#define GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE 962
#define GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_START 963
#define GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_NEXT 975
+#define GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_DELETE 976
+
/**************************************************
*
* CREDENTIAL MESSAGE TYPES
*/
-#define GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY 981
+#define GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY 981
#define GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY_RESULT 982
#define GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX_AUTH 1009
-
/********************************** Channel *********************************/
/**
#define GNUNET_MESSAGE_TYPE_NAT_AUTO_CFG_RESULT 1068
-/* 1080-1109 reserved for TMCG (Heiko Stamer, see gnunet-developers, January 2017) */
+/* 1080-1109 reserved for TMCG (Heiko Stamer, see gnunet-developers, January
+ * 2017) */
/******************************************************************************/
#define GNUNET_MESSAGE_TYPE_AUCTION_CLIENT_OUTCOME 1112
-
/******************************************************************************/
/********************************* RPS DEBUG ********************************/
/******************************************************************************/
/**
* @brief Send update of the view
*/
-#define GNUNET_MESSAGE_TYPE_RPS_CS_DEBUG_VIEW_REPLY 1131
+#define GNUNET_MESSAGE_TYPE_RPS_CS_DEBUG_VIEW_REPLY 1131
/**
* @brief Cancel getting updates of the view
*/
-#define GNUNET_MESSAGE_TYPE_RPS_CS_DEBUG_VIEW_CANCEL 1132
+#define GNUNET_MESSAGE_TYPE_RPS_CS_DEBUG_VIEW_CANCEL 1132
/**
/**
* @brief Send peer of biased stream
*/
-#define GNUNET_MESSAGE_TYPE_RPS_CS_DEBUG_STREAM_REPLY 1134
+#define GNUNET_MESSAGE_TYPE_RPS_CS_DEBUG_STREAM_REPLY 1134
/**
* @brief Cancel getting biased strem
*/
-#define GNUNET_MESSAGE_TYPE_RPS_CS_DEBUG_STREAM_CANCEL 1135
+#define GNUNET_MESSAGE_TYPE_RPS_CS_DEBUG_STREAM_CANCEL 1135
/*******************************************************
#define GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL 1301
/**
- * Type of the 'struct RequestHelloValidationMessage' send by clients to TRANSPORT
- * to trigger validation of addresses.
+ * Type of the 'struct RequestHelloValidationMessage' send by clients to
+ * TRANSPORT to trigger validation of addresses.
*/
#define GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION 1302
#define GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE 1304
-
/* ************** NEW (NG) ATS Messages ************* */
/* NOTE: it is not clear ATS will survive in TNG */
*/
-
/**
* Type used to match 'all' message types.
*/
#define GNUNET_MESSAGE_TYPE_ALL 65535
-#if 0 /* keep Emacsens' auto-indent happy */
+#if 0 /* keep Emacsens' auto-indent happy */
{
#endif
#ifdef __cplusplus
+++ /dev/null
-/*
- This file is part of GNUnet
- Copyright (C) 2012, 2013 GNUnet e.V.
-
- GNUnet is free software: you can redistribute it and/or modify it
- under the terms of the GNU Affero General Public License as published
- by the Free Software Foundation, either version 3 of the License,
- or (at your option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-
- SPDX-License-Identifier: AGPL3.0-or-later
-*/
-
-/**
- * @author Martin Schanzenbach
- *
- * @file
- * Plugin API for the idp database backend
- *
- * @defgroup reclaim-plugin IdP service plugin API
- * Plugin API for the idp database backend
- * @{
- */
-#ifndef GNUNET_RECLAIM_PLUGIN_H
-#define GNUNET_RECLAIM_PLUGIN_H
-
-#include "gnunet_util_lib.h"
-#include "gnunet_reclaim_service.h"
-
-#ifdef __cplusplus
-extern "C"
-{
-#if 0 /* keep Emacsens' auto-indent happy */
-}
-#endif
-#endif
-
-
-/**
- * Function called by for each matching ticket.
- *
- * @param cls closure
- * @param ticket the ticket
- */
-typedef void (*GNUNET_RECLAIM_TicketIterator) (void *cls,
- const struct GNUNET_RECLAIM_Ticket *ticket,
- const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs);
-
-
-/**
- * @brief struct returned by the initialization function of the plugin
- */
-struct GNUNET_RECLAIM_PluginFunctions
-{
-
- /**
- * Closure to pass to all plugin functions.
- */
- void *cls;
-
- /**
- * Store a ticket in the database.
- *
- * @param cls closure (internal context for the plugin)
- * @param ticket the ticket to store
- * @return #GNUNET_OK on success, else #GNUNET_SYSERR
- */
- int (*store_ticket) (void *cls,
- const struct GNUNET_RECLAIM_Ticket *ticket,
- const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs);
-
- /**
- * Delete a ticket from the database.
- *
- * @param cls closure (internal context for the plugin)
- * @param ticket the ticket to store
- * @return #GNUNET_OK on success, else #GNUNET_SYSERR
- */
- int (*delete_ticket) (void *cls,
- const struct GNUNET_RECLAIM_Ticket *ticket);
-
-
-
- /**
- * Iterate over all tickets
- *
- * @param cls closure (internal context for the plugin)
- * @param identity the identity
- * @param audience GNUNET_YES if the identity is the audience of the ticket
- * else it is considered the issuer
- * @param iter function to call with the result
- * @param iter_cls closure for @a iter
- * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error
- */
- int (*iterate_tickets) (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
- int audience,
- uint64_t offset,
- GNUNET_RECLAIM_TicketIterator iter, void *iter_cls);
-
- int (*get_ticket_attributes) (void* cls,
- const struct GNUNET_RECLAIM_Ticket *ticket,
- GNUNET_RECLAIM_TicketIterator iter,
- void *iter_cls);
-};
-
-#if 0 /* keep Emacsens' auto-indent happy */
-{
-#endif
-#ifdef __cplusplus
-}
-#endif
-
-#endif
-
-/** @} */ /* end of group */
GNUNET_RECLAIM_ContinuationWithStatus cont, void *cont_cls);
+/**
+ * Delete an attribute. Tickets used to share this attribute are updated
+ * accordingly.
+ *
+ * @param h handle to the re:claimID service
+ * @param pkey Private key of the identity to add an attribute to
+ * @param attr The attribute
+ * @param cont Continuation to call when done
+ * @param cont_cls Closure for @a cont
+ * @return handle Used to to abort the request
+ */
+struct GNUNET_RECLAIM_Operation *
+GNUNET_RECLAIM_attribute_delete (
+ struct GNUNET_RECLAIM_Handle *h,
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
+ const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr,
+ GNUNET_RECLAIM_ContinuationWithStatus cont, void *cont_cls);
+
+
/**
* List all attributes for a local identity.
* This MUST lock the `struct GNUNET_RECLAIM_Handle`
*/
struct GNUNET_RECLAIM_ATTRIBUTE_Claim *claim;
+/**
+ * Claim to delete
+ */
+static char *attr_delete;
+
+/**
+ * Claim object to delete
+ */
+static struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr_to_delete;
+
static void
do_cleanup (void *cls)
{
GNUNET_free (abe_key);
if (NULL != attr_list)
GNUNET_free (attr_list);
+ if (NULL != attr_to_delete)
+ GNUNET_free (attr_to_delete);
}
static void
const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
{
char *value_str;
+ char *id;
const char *attr_type;
if (NULL == identity) {
value_str = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type, attr->data,
attr->data_size);
attr_type = GNUNET_RECLAIM_ATTRIBUTE_number_to_typename (attr->type);
- fprintf (stdout, "%s: %s [%s,v%u,id=%" PRIu64 "]\n", attr->name, value_str,
- attr_type, attr->version, attr->id);
+ id = GNUNET_STRINGS_data_to_string_alloc (&attr->id, sizeof (uint64_t));
+ fprintf (stdout, "Name: %s; Value: %s (%s); Version %u; ID: %s\n", attr->name,
+ value_str, attr_type, attr->version, id);
+ GNUNET_free (id);
}
static void
cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
}
+
+static void
+process_delete (void *cls, int success, const char *msg)
+{
+ reclaim_op = NULL;
+ if (GNUNET_OK != success) {
+ fprintf (stderr, "Deletion failed.\n");
+ ret = 1;
+ }
+ cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
+}
+
+
static void
iter_finished (void *cls)
{
&process_rvk, NULL);
return;
}
+ if (attr_delete) {
+ if (NULL == attr_to_delete) {
+ fprintf (stdout, "No such attribute ``%s''\n", attr_delete);
+ return;
+ }
+ reclaim_op = GNUNET_RECLAIM_attribute_delete (
+ reclaim_handle, pkey, attr_to_delete, &process_delete, NULL);
+ return;
+ }
if (attr_name) {
if (NULL == type_str)
type = GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING;
struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
char *attrs_tmp;
char *attr_str;
+ char *label;
+ char *id;
const char *attr_type;
if ((NULL != attr_name) && (NULL != claim)) {
break;
}
GNUNET_free (attrs_tmp);
+ } else if (attr_delete && (NULL == attr_to_delete)) {
+ label = GNUNET_STRINGS_data_to_string_alloc (&attr->id, sizeof (uint64_t));
+ if (0 == strcasecmp (attr_delete, label)) {
+ attr_to_delete = GNUNET_RECLAIM_ATTRIBUTE_claim_new (
+ attr->name, attr->type, attr->data, attr->data_size);
+ attr_to_delete->id = attr->id;
+ }
+ GNUNET_free (label);
} else if (list) {
attr_str = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type, attr->data,
attr->data_size);
attr_type = GNUNET_RECLAIM_ATTRIBUTE_number_to_typename (attr->type);
- fprintf (stdout, "%s: %s [%s,v%u,id=%" PRIu64 "]\n", attr->name, attr_str,
- attr_type, attr->version, attr->id);
+ id = GNUNET_STRINGS_data_to_string_alloc (&attr->id, sizeof (uint64_t));
+ fprintf (stdout, "Name: %s; Value: %s (%s); Version %u; ID: %s\n",
+ attr->name, attr_str, attr_type, attr->version, id);
+ GNUNET_free (id);
}
GNUNET_RECLAIM_get_attributes_next (attr_iterator);
}
GNUNET_GETOPT_option_string ('a', "add", "NAME",
gettext_noop ("Add an attribute NAME"),
&attr_name),
-
+ GNUNET_GETOPT_option_string ('d', "delete", "ID",
+ gettext_noop ("Add an attribute with ID"),
+ &attr_delete),
GNUNET_GETOPT_option_string ('V', "value", "VALUE",
gettext_noop ("The attribute VALUE"),
&attr_value),
#include "gnunet_namestore_service.h"
#include "gnunet_protocols.h"
#include "gnunet_reclaim_attribute_lib.h"
-#include "gnunet_reclaim_plugin.h"
+#include "gnunet_reclaim_service.h"
#include "gnunet_signatures.h"
#include "reclaim.h"
*/
static struct GNUNET_IDENTITY_Handle *identity_handle;
-/**
- * Database handle
- */
-static struct GNUNET_RECLAIM_PluginFunctions *TKT_database;
-
-/**
- * Name of DB plugin
- */
-static char *db_lib_name;
-
/**
* Token expiration interval
*/
/**
* A ticket iteration operation.
*/
-struct TicketIteration {
+struct TicketIteration
+{
/**
* DLL
*/
/**
* An attribute iteration operation.
*/
-struct AttributeIterator {
+struct AttributeIterator
+{
/**
* Next element in the DLL
*/
/**
* An idp client
*/
-struct IdpClient {
+struct IdpClient
+{
/**
* The client
* Tail of DLL of attribute store ops
*/
struct AttributeStoreHandle *store_op_tail;
+ /**
+ * Head of DLL of attribute delete ops
+ */
+ struct AttributeDeleteHandle *delete_op_head;
+
+ /**
+ * Tail of DLL of attribute delete ops
+ */
+ struct AttributeDeleteHandle *delete_op_tail;
+};
+
+
+struct AttributeDeleteHandle
+{
+ /**
+ * DLL
+ */
+ struct AttributeDeleteHandle *next;
+
+ /**
+ * DLL
+ */
+ struct AttributeDeleteHandle *prev;
+
+ /**
+ * Client connection
+ */
+ struct IdpClient *client;
+
+ /**
+ * Identity
+ */
+ struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
+
+
+ /**
+ * QueueEntry
+ */
+ struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
+
+ /**
+ * Iterator
+ */
+ struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
+
+ /**
+ * The attribute to delete
+ */
+ struct GNUNET_RECLAIM_ATTRIBUTE_Claim *claim;
+
+ /**
+ * Tickets to update
+ */
+ struct TicketRecordsEntry *tickets_to_update_head;
+
+ /**
+ * Tickets to update
+ */
+ struct TicketRecordsEntry *tickets_to_update_tail;
+
+ /**
+ * Attribute label
+ */
+ char *label;
+
+ /**
+ * request id
+ */
+ uint32_t r_id;
};
-struct AttributeStoreHandle {
+
+struct AttributeStoreHandle
+{
/**
* DLL
*/
uint32_t r_id;
};
-struct ConsumeTicketOperation {
+struct ConsumeTicketOperation
+{
/**
* DLL
*/
/**
* Updated attribute IDs
*/
-struct TicketAttributeUpdateEntry {
+struct TicketAttributeUpdateEntry
+{
/**
* DLL
*/
/**
* Ticket revocation request handle
*/
-struct TicketRevocationOperation {
+struct TicketRevocationOperation
+{
/**
* DLL
*/
/**
* Ticket issue operation handle
*/
-struct TicketIssueOperation {
+struct TicketIssueOperation
+{
/**
* DLL
*/
* map in json_t format
*
*/
-struct EgoEntry {
+struct EgoEntry
+{
/**
* DLL
*/
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
RECLAIM_TICKETS_deinit ();
- GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, TKT_database));
- GNUNET_free (db_lib_name);
- db_lib_name = NULL;
if (NULL != timeout_task)
GNUNET_SCHEDULER_cancel (timeout_task);
if (NULL != update_task)
{
struct AttributeStoreHandle *ash = cls;
struct GNUNET_MQ_Envelope *env;
- struct AttributeStoreResultMessage *acr_msg;
+ struct SuccessResultMessage *acr_msg;
ash->ns_qe = NULL;
GNUNET_CONTAINER_DLL_remove (ash->client->store_op_head,
return;
}
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Sending ATTRIBUTE_STORE_RESPONSE message\n");
- env = GNUNET_MQ_msg (acr_msg,
- GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE_RESPONSE);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending SUCCESS_RESPONSE message\n");
+ env = GNUNET_MQ_msg (acr_msg, GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE);
acr_msg->id = htonl (ash->r_id);
acr_msg->op_result = htonl (GNUNET_OK);
GNUNET_MQ_send (ash->client->mq, env);
GNUNET_SCHEDULER_add_now (&attr_store_task, ash);
}
+
+static void
+cleanup_adh (struct AttributeDeleteHandle *adh)
+{
+ struct TicketRecordsEntry *le;
+ if (NULL != adh->ns_it)
+ GNUNET_NAMESTORE_zone_iteration_stop (adh->ns_it);
+ if (NULL != adh->ns_qe)
+ GNUNET_NAMESTORE_cancel (adh->ns_qe);
+ if (NULL != adh->label)
+ GNUNET_free (adh->label);
+ if (NULL != adh->claim)
+ GNUNET_free (adh->claim);
+ while (NULL != (le = adh->tickets_to_update_head)) {
+ GNUNET_CONTAINER_DLL_remove (adh->tickets_to_update_head,
+ adh->tickets_to_update_tail, le);
+ if (NULL != le->label)
+ GNUNET_free (le->label);
+ if (NULL != le->data)
+ GNUNET_free (le->data);
+ GNUNET_free (le);
+ }
+ GNUNET_free (adh);
+}
+
+
+static void
+send_delete_response (struct AttributeDeleteHandle *adh, int32_t success)
+{
+ struct GNUNET_MQ_Envelope *env;
+ struct SuccessResultMessage *acr_msg;
+
+ GNUNET_CONTAINER_DLL_remove (adh->client->delete_op_head,
+ adh->client->delete_op_tail, adh);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending SUCCESS_RESPONSE message\n");
+ env = GNUNET_MQ_msg (acr_msg, GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE);
+ acr_msg->id = htonl (adh->r_id);
+ acr_msg->op_result = htonl (success);
+ GNUNET_MQ_send (adh->client->mq, env);
+}
+
+
+static void
+ticket_iter (void *cls, const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
+ const char *label, unsigned int rd_count,
+ const struct GNUNET_GNSRECORD_Data *rd)
+{
+ struct AttributeDeleteHandle *adh = cls;
+ struct TicketRecordsEntry *le;
+ int has_changed = GNUNET_NO;
+
+ for (int i = 0; i < rd_count; i++) {
+ if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
+ continue;
+ if (0 != memcmp (rd[i].data, &adh->claim->id, sizeof (uint64_t)))
+ continue;
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Attribute to delete found (%s)\n",
+ adh->label);
+ has_changed = GNUNET_YES;
+ break;
+ }
+ if (GNUNET_YES == has_changed) {
+ le = GNUNET_new (struct TicketRecordsEntry);
+ le->data_size = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
+ le->data = GNUNET_malloc (le->data_size);
+ le->rd_count = rd_count;
+ le->label = GNUNET_strdup (label);
+ GNUNET_GNSRECORD_records_serialize (rd_count, rd, le->data_size, le->data);
+ GNUNET_CONTAINER_DLL_insert (adh->tickets_to_update_head,
+ adh->tickets_to_update_tail, le);
+ }
+ GNUNET_NAMESTORE_zone_iterator_next (adh->ns_it, 1);
+}
+
+
+static void
+update_tickets (void *cls);
+
+
+static void
+ticket_updated (void *cls, int32_t success, const char *emsg)
+{
+ struct AttributeDeleteHandle *adh = cls;
+ adh->ns_qe = NULL;
+ GNUNET_SCHEDULER_add_now (&update_tickets, adh);
+}
+
+static void
+update_tickets (void *cls)
+{
+ struct AttributeDeleteHandle *adh = cls;
+ struct TicketRecordsEntry *le;
+ if (NULL == adh->tickets_to_update_head) {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Finished updatding tickets, success\n");
+ send_delete_response (adh, GNUNET_OK);
+ cleanup_adh (adh);
+ return;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Updating %s\n",
+ adh->tickets_to_update_head->label);
+ le = adh->tickets_to_update_head;
+ GNUNET_CONTAINER_DLL_remove (adh->tickets_to_update_head,
+ adh->tickets_to_update_tail, le);
+ struct GNUNET_GNSRECORD_Data rd[le->rd_count];
+ struct GNUNET_GNSRECORD_Data rd_new[le->rd_count - 1];
+ GNUNET_GNSRECORD_records_deserialize (le->data_size, le->data, le->rd_count,
+ rd);
+ int j = 0;
+ for (int i = 0; i < le->rd_count; i++) {
+ if ((GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF == rd[i].record_type) &&
+ (0 == memcmp (rd[i].data, &adh->claim->id, sizeof (uint64_t))))
+ continue;
+ rd_new[j] = rd[i];
+ j++;
+ }
+ adh->ns_qe = GNUNET_NAMESTORE_records_store (nsh, &adh->identity, le->label,
+ j, rd_new, &ticket_updated, adh);
+ GNUNET_free (le->label);
+ GNUNET_free (le->data);
+ GNUNET_free (le);
+}
+
+
+static void
+ticket_iter_fin (void *cls)
+{
+ struct AttributeDeleteHandle *adh = cls;
+ adh->ns_it = NULL;
+ GNUNET_SCHEDULER_add_now (&update_tickets, adh);
+}
+
+
+static void
+ticket_iter_err (void *cls)
+{
+ struct AttributeDeleteHandle *adh = cls;
+ adh->ns_it = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Namestore error on delete %s\n",
+ adh->label);
+ send_delete_response (adh, GNUNET_SYSERR);
+ cleanup_adh (adh);
+}
+
+
+static void
+start_ticket_update (void *cls)
+{
+ struct AttributeDeleteHandle *adh = cls;
+ adh->ns_it = GNUNET_NAMESTORE_zone_iteration_start (
+ nsh, &adh->identity, &ticket_iter_err, adh, &ticket_iter, adh,
+ &ticket_iter_fin, adh);
+}
+
+
+static void
+attr_delete_cont (void *cls, int32_t success, const char *emsg)
+{
+ struct AttributeDeleteHandle *adh = cls;
+ adh->ns_qe = NULL;
+ if (GNUNET_SYSERR == success) {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error deleting attribute %s (%s)\n",
+ adh->claim->name, adh->label);
+ send_delete_response (adh, GNUNET_SYSERR);
+ cleanup_adh (adh);
+ return;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Updating tickets...\n");
+ GNUNET_SCHEDULER_add_now (&start_ticket_update, adh);
+}
+
+
+static int
+check_attribute_delete_message (void *cls,
+ const struct AttributeDeleteMessage *dam)
+{
+ uint16_t size;
+
+ size = ntohs (dam->header.size);
+ if (size <= sizeof (struct AttributeDeleteMessage)) {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+static void
+handle_attribute_delete_message (void *cls,
+ const struct AttributeDeleteMessage *dam)
+{
+ struct AttributeDeleteHandle *adh;
+ struct IdpClient *idp = cls;
+ size_t data_len;
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Received ATTRIBUTE_DELETE message\n");
+
+ data_len = ntohs (dam->attr_len);
+
+ adh = GNUNET_new (struct AttributeDeleteHandle);
+ adh->claim = GNUNET_RECLAIM_ATTRIBUTE_deserialize ((char *)&dam[1], data_len);
+
+ adh->r_id = ntohl (dam->id);
+ adh->identity = dam->identity;
+ adh->label =
+ GNUNET_STRINGS_data_to_string_alloc (&adh->claim->id, sizeof (uint64_t));
+ GNUNET_SERVICE_client_continue (idp->client);
+ adh->client = idp;
+ GNUNET_CONTAINER_DLL_insert (idp->delete_op_head, idp->delete_op_tail, adh);
+ adh->ns_qe = GNUNET_NAMESTORE_records_store (nsh, &adh->identity, adh->label,
+ 0, NULL, &attr_delete_cont, adh);
+}
+
+
/*************************************************
* Attrubute iteration
*************************************************/
run (void *cls, const struct GNUNET_CONFIGURATION_Handle *c,
struct GNUNET_SERVICE_Handle *server)
{
- char *database;
cfg = c;
if (GNUNET_OK != RECLAIM_TICKETS_init (cfg)) {
}
identity_handle = GNUNET_IDENTITY_connect (cfg, NULL, NULL);
- /* Loading DB plugin */
- if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (
- cfg, "reclaim", "database", &database))
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No database backend configured\n");
- GNUNET_asprintf (&db_lib_name, "libgnunet_plugin_reclaim_%s", database);
- TKT_database = GNUNET_PLUGIN_load (db_lib_name, (void *)cfg);
- GNUNET_free (database);
- if (NULL == TKT_database) {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Could not load database backend `%s'\n", db_lib_name);
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_time (
cfg, "reclaim", "TOKEN_EXPIRATION_INTERVAL",
struct TicketIssueOperation *iss;
struct ConsumeTicketOperation *ct;
struct AttributeStoreHandle *as;
+ struct AttributeDeleteHandle *adh;
// TODO other operations
GNUNET_CONTAINER_DLL_remove (idp->store_op_head, idp->store_op_tail, as);
cleanup_as_handle (as);
}
+ while (NULL != (adh = idp->delete_op_head)) {
+ GNUNET_CONTAINER_DLL_remove (idp->delete_op_head, idp->delete_op_tail, adh);
+ cleanup_adh (adh);
+ }
while (NULL != (ai = idp->attr_iter_head)) {
GNUNET_CONTAINER_DLL_remove (idp->attr_iter_head, idp->attr_iter_tail, ai);
GNUNET_MQ_hd_var_size (attribute_store_message,
GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE,
struct AttributeStoreMessage, NULL),
+ GNUNET_MQ_hd_var_size (attribute_delete_message,
+ GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_DELETE,
+ struct AttributeDeleteMessage, NULL),
GNUNET_MQ_hd_fixed_size (
iteration_start, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_START,
struct AttributeIterationStartMessage, NULL),
struct ParallelLookup;
+
+/**
+ * A reference to a ticket stored in GNS
+ */
+struct TicketReference
+{
+ /**
+ * DLL
+ */
+ struct TicketReference *next;
+
+ /**
+ * DLL
+ */
+ struct TicketReference *prev;
+
+ /**
+ * Attributes
+ */
+ struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
+
+ /**
+ * Tickets
+ */
+ struct GNUNET_RECLAIM_Ticket ticket;
+};
+
+
struct RECLAIM_TICKETS_ConsumeHandle
{
/**
};
-/**
- * A reference to a ticket stored in GNS
- */
-struct TicketReference
-{
- /**
- * DLL
- */
- struct TicketReference *next;
-
- /**
- * DLL
- */
- struct TicketReference *prev;
-
- /**
- * Attributes
- */
- struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
-
- /**
- * Tickets
- */
- struct GNUNET_RECLAIM_Ticket ticket;
-};
-
-
/**
* Ticket issue request handle
*/
};
-struct TicketRecordsEntry
-{
- /**
- * DLL
- */
- struct TicketRecordsEntry *next;
-
- /**
- * DLL
- */
- struct TicketRecordsEntry *prev;
-
- /**
- * Record count
- */
- unsigned int rd_count;
-
- /**
- * Data
- */
- char *data;
-
- /**
- * Data size
- */
- size_t data_size;
-
- /**
- * Label
- */
- char *label;
-};
-
/**
* Ticket revocation request handle
*/
const struct GNUNET_GNSRECORD_Data *rd)
{
struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
+ struct GNUNET_RECLAIM_ATTRIBUTE_Claim *claim;
+ struct GNUNET_GNSRECORD_Data new_rd;
struct RevokedAttributeEntry *le;
char *new_label;
+ char *attr_data;
rvk->ns_qe = NULL;
if (0 == rd_count) {
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
/** find a new place for this attribute **/
rvk->move_attr->new_id =
GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
+ new_rd = *rd;
+ claim = GNUNET_RECLAIM_ATTRIBUTE_deserialize (rd->data, rd->data_size);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Attribute to update: Name=%s, ID=%" PRIu64 "\n", claim->name,
+ claim->id);
+ claim->id = rvk->move_attr->new_id;
+ new_rd.data_size = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (claim);
+ attr_data = GNUNET_malloc (rd->data_size);
+ new_rd.data_size = GNUNET_RECLAIM_ATTRIBUTE_serialize (claim, attr_data);
+ new_rd.data = attr_data;
new_label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->new_id,
sizeof (uint64_t));
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute %s\n", new_label);
- rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh, &rvk->identity, new_label,
- 1, rd, &move_attr_finished, rvk);
+ rvk->ns_qe = GNUNET_NAMESTORE_records_store (
+ nsh, &rvk->identity, new_label, 1, &new_rd, &move_attr_finished, rvk);
GNUNET_free (new_label);
+ GNUNET_free (claim);
+ GNUNET_free (attr_data);
}
struct ParallelLookup *parallel_lookup = cls;
struct RECLAIM_TICKETS_ConsumeHandle *cth = parallel_lookup->handle;
struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *attr_le;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Parallel lookup finished (count=%u)\n",
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Parallel lookup finished (count=%u)\n",
rd_count);
GNUNET_CONTAINER_DLL_remove (cth->parallel_lookups_head,
GNUNET_YES);
for (int i = 0; i < rd_count; i++) {
+ if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
+ continue;
lbl = GNUNET_STRINGS_data_to_string_alloc (rd[i].data, rd[i].data_size);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Attribute ref found %s\n", lbl);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Attribute ref found %s\n", lbl);
parallel_lookup = GNUNET_new (struct ParallelLookup);
parallel_lookup->handle = cth;
parallel_lookup->label = lbl;
GNUNET_CONTAINER_DLL_insert (cth->parallel_lookups_head,
cth->parallel_lookups_tail, parallel_lookup);
}
- cth->kill_task = GNUNET_SCHEDULER_add_delayed (
- GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 3),
- &abort_parallel_lookups, cth);
+ if (NULL != cth->parallel_lookups_head) {
+ cth->kill_task = GNUNET_SCHEDULER_add_delayed (
+ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 3),
+ &abort_parallel_lookups, cth);
+ return;
+ }
+ cth->cb (cth->cb_cls, &cth->ticket.identity, cth->attrs, GNUNET_OK, NULL);
+ cleanup_cth (cth);
}
cth->cb_cls = cb_cls;
label =
GNUNET_STRINGS_data_to_string_alloc (&cth->ticket.rnd, sizeof (uint64_t));
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking for AuthZ info under %s\n",
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Looking for AuthZ info under %s\n",
label);
cth->lookup_start_time = GNUNET_TIME_absolute_get ();
cth->lookup_request = GNUNET_GNS_lookup (
#include "gnunet_namestore_service.h"
#include "gnunet_protocols.h"
#include "gnunet_reclaim_attribute_lib.h"
-#include "gnunet_reclaim_plugin.h"
+#include "gnunet_reclaim_service.h"
#include "gnunet_signatures.h"
#include "gnunet_statistics_service.h"
#include "reclaim.h"
struct RECLAIM_TICKETS_ConsumeHandle;
struct RECLAIM_TICKETS_RevokeHandle;
+
+struct TicketRecordsEntry
+{
+ /**
+ * DLL
+ */
+ struct TicketRecordsEntry *next;
+
+ /**
+ * DLL
+ */
+ struct TicketRecordsEntry *prev;
+
+ /**
+ * Record count
+ */
+ unsigned int rd_count;
+
+ /**
+ * Data
+ */
+ char *data;
+
+ /**
+ * Data size
+ */
+ size_t data_size;
+
+ /**
+ * Label
+ */
+ char *label;
+};
+
+
/**
* Continuation called with ticket.
*
GNUNET_NETWORK_STRUCT_BEGIN
+
/**
* Use to store an identity attribute
*/
struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
/* followed by the serialized attribute */
+};
+
+
+/**
+ * Use to delete an identity attribute
+ */
+struct AttributeDeleteMessage
+{
+ /**
+ * Type: #GNUNET_MESSAGE_TYPE_IDENTITY_SET_DEFAULT
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Unique identifier for this request (for key collisions).
+ */
+ uint32_t id GNUNET_PACKED;
+
+ /**
+ * The length of the attribute
+ */
+ uint32_t attr_len GNUNET_PACKED;
+
+ /**
+ * Identity
+ */
+ struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
+ /* followed by the serialized attribute */
};
+
/**
- * Attribute store response message
+ * Attribute store/delete response message
*/
-struct AttributeStoreResultMessage
+struct SuccessResultMessage
{
/**
* Message header
* #GNUNET_SYSERR on failure, #GNUNET_OK on success
*/
int32_t op_result GNUNET_PACKED;
-
};
/**
*/
struct GNUNET_MessageHeader header;
- /**
+ /**
* Unique identifier for this request (for key collisions).
*/
uint32_t id GNUNET_PACKED;
* Identity.
*/
struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
-
};
* Unique identifier for this request (for key collisions).
*/
uint32_t id GNUNET_PACKED;
-
};
* Unique identifier for this request (for key collisions).
*/
uint32_t id GNUNET_PACKED;
-
};
/**
* Identity.
*/
struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
-
};
* Unique identifier for this request (for key collisions).
*/
uint32_t id GNUNET_PACKED;
-
};
* Unique identifier for this request (for key collisions).
*/
uint32_t id GNUNET_PACKED;
-
};
-
/**
* Ticket issue message
*/
*/
uint32_t attr_len GNUNET_PACKED;
- //Followed by a serialized attribute list
+ // Followed by a serialized attribute list
};
/**
*/
uint32_t attrs_len GNUNET_PACKED;
- //Followed by a ticket and serialized attribute list
+ // Followed by a ticket and serialized attribute list
};
/**
* Unique identifier for this request (for key collisions).
*/
uint32_t id GNUNET_PACKED;
-
};
/**
*/
struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
- //Followed by a serialized ticket
+ // Followed by a serialized ticket
};
/**
*/
struct GNUNET_MessageHeader header;
- /**
+ /**
* Unique identifier for this request (for key collisions).
*/
uint32_t id GNUNET_PACKED;
};
-
GNUNET_NETWORK_STRUCT_END
#endif
/**
* Handle an incoming message of type
- * #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_RESPONSE
+ * #GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE
*
* @param cls
* @param msg the message we received
*/
static void
-handle_attribute_store_response (void *cls,
- const struct AttributeStoreResultMessage *msg)
+handle_success_response (void *cls, const struct SuccessResultMessage *msg)
{
struct GNUNET_RECLAIM_Handle *h = cls;
struct GNUNET_RECLAIM_Operation *op;
return;
res = ntohl (msg->op_result);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Received ATTRIBUTE_STORE_RESPONSE with result %d\n", res);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Received SUCCESS_RESPONSE with result %d\n",
+ res);
/* TODO: add actual error message to response... */
if (GNUNET_SYSERR == res)
reconnect (struct GNUNET_RECLAIM_Handle *h)
{
struct GNUNET_MQ_MessageHandler handlers[] = {
- GNUNET_MQ_hd_fixed_size (
- attribute_store_response,
- GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE_RESPONSE,
- struct AttributeStoreResultMessage, h),
+ GNUNET_MQ_hd_fixed_size (success_response,
+ GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE,
+ struct SuccessResultMessage, h),
GNUNET_MQ_hd_var_size (attribute_result,
GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT,
struct AttributeResultMessage, h),
}
+/**
+ * Delete an attribute. Tickets used to share this attribute are updated
+ * accordingly.
+ *
+ * @param h handle to the re:claimID service
+ * @param pkey Private key of the identity to add an attribute to
+ * @param attr The attribute
+ * @param cont Continuation to call when done
+ * @param cont_cls Closure for @a cont
+ * @return handle Used to to abort the request
+ */
+struct GNUNET_RECLAIM_Operation *
+GNUNET_RECLAIM_attribute_delete (
+ struct GNUNET_RECLAIM_Handle *h,
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
+ const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr,
+ GNUNET_RECLAIM_ContinuationWithStatus cont, void *cont_cls)
+{
+ struct GNUNET_RECLAIM_Operation *op;
+ struct AttributeDeleteMessage *dam;
+ size_t attr_len;
+
+ op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
+ op->h = h;
+ op->as_cb = cont;
+ op->cls = cont_cls;
+ op->r_id = h->r_id_gen++;
+ GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
+ attr_len = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (attr);
+ op->env = GNUNET_MQ_msg_extra (dam, attr_len,
+ GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_DELETE);
+ dam->identity = *pkey;
+ dam->id = htonl (op->r_id);
+ GNUNET_RECLAIM_ATTRIBUTE_serialize (attr, (char *)&dam[1]);
+
+ dam->attr_len = htons (attr_len);
+ if (NULL != h->mq)
+ GNUNET_MQ_send_copy (h->mq, op->env);
+ return op;
+}
+
+
/**
* List all attributes for a local identity.
* This MUST lock the `struct GNUNET_RECLAIM_Handle`