ticket duplicates fix
[oweals/gnunet.git] / src / reclaim / gnunet-service-reclaim.c
index 3321a79d8b6208b0a58b2efd1a6c46c15236ac31..57bff8ed463effebc574725e10174b1f7fe633d8 100644 (file)
    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
  */
 #include "platform.h"
 #include "gnunet_util_lib.h"
+#include "gnunet-service-reclaim_tickets.h"
 #include "gnunet_constants.h"
-#include "gnunet_protocols.h"
-#include "gnunet_identity_service.h"
 #include "gnunet_gnsrecord_lib.h"
-#include "gnunet_namestore_service.h"
-#include "gnunet_abe_lib.h"
-#include "gnunet_credential_service.h"
-#include "gnunet_statistics_service.h"
-#include "gnunet_gns_service.h"
-#include "gnunet_reclaim_plugin.h"
+#include "gnunet_protocols.h"
 #include "gnunet_reclaim_attribute_lib.h"
+#include "gnunet_reclaim_service.h"
 #include "gnunet_signatures.h"
 #include "reclaim.h"
 
-/**
- * First pass state
- */
-#define STATE_INIT 0
-
-/**
- * Normal operation state
- */
-#define STATE_POST_INIT 1
-
-/**
- * Minimum interval between updates
- */
-#define MIN_WAIT_TIME GNUNET_TIME_UNIT_MINUTES
-
-/**
- * Standard token expiration time
- */
-#define DEFAULT_TOKEN_EXPIRATION_INTERVAL GNUNET_TIME_UNIT_HOURS
-
-/**
- * Identity handle
- */
-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
- */
-static struct GNUNET_TIME_Relative token_expiration_interval;
 
 /**
  * Namestore handle
  */
-static struct GNUNET_NAMESTORE_Handle *ns_handle;
-
-/**
- * GNS handle
- */
-static struct GNUNET_GNS_Handle *gns_handle;
-
-/**
- * Credential handle
- */
-static struct GNUNET_CREDENTIAL_Handle *credential_handle;
-
-/**
- * Namestore qe
- */
-static struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
-
-/**
- * Namestore iterator
- */
-static struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
+static struct GNUNET_NAMESTORE_Handle *nsh;
 
 /**
  * Timeout task
  */
 static struct GNUNET_SCHEDULER_Task *timeout_task;
 
-/**
- * Update task
- */
-static struct GNUNET_SCHEDULER_Task *update_task;
-
-
-/**
- * Currently processed token
- */
-static struct IdentityToken *token;
-
-/**
- * Label for currently processed token
- */
-static char* label;
-
-/**
- * Scopes for processed token
- */
-static char* scopes;
-
-/**
- * Handle to the statistics service.
- */
-static struct GNUNET_STATISTICS_Handle *stats;
-
 /**
  * Our configuration.
  */
@@ -163,73 +75,18 @@ struct TicketIteration
    */
   struct IdpClient *client;
 
-  /**
-   * Key of the identity we are iterating over.
-   */
-  struct GNUNET_CRYPTO_EcdsaPublicKey identity;
-
-  /**
-   * Identity is audience
-   */
-  uint32_t is_audience;
-
   /**
    * The operation id fot the iteration in the response for the client
    */
   uint32_t r_id;
 
   /**
-   * Offset of the iteration used to address next result of the 
-   * iteration in the store
-   *
-   * Initialy set to 0 in handle_iteration_start
-   * Incremented with by every call to handle_iteration_next
+   * The ticket iterator
    */
-  uint32_t offset;
-
+  struct RECLAIM_TICKETS_Iterator *iter;
 };
 
 
-
-/**
- * Callback after an ABE bootstrap
- *
- * @param cls closure
- * @param abe_key the ABE key that exists or was created
- */
-typedef void
-(*AbeBootstrapResult) (void *cls,
-                       struct GNUNET_ABE_AbeMasterKey *abe_key);
-
-
-struct AbeBootstrapHandle
-{
-  /**
-   * Function to call when finished
-   */
-  AbeBootstrapResult proc;
-
-  /**
-   * Callback closure
-   */
-  char *proc_cls;
-
-  /**
-   * Key of the zone we are iterating over.
-   */
-  struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
-
-  /**
-   * Namestore Queue Entry
-   */
-  struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
-
-  /**
-   * The issuer egos ABE master key
-   */
-  struct GNUNET_ABE_AbeMasterKey *abe_key;
-};
-
 /**
  * An attribute iteration operation.
  */
@@ -255,11 +112,6 @@ struct AttributeIterator
    */
   struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
 
-  /**
-   * The issuer egos ABE master key
-   */
-  struct GNUNET_ABE_AbeMasterKey *abe_key;
-
   /**
    * Namestore iterator
    */
@@ -269,16 +121,23 @@ struct AttributeIterator
    * The operation id fot the zone iteration in the response for the client
    */
   uint32_t request_id;
-
 };
 
 
-
 /**
  * An idp client
  */
 struct IdpClient
 {
+  /**
+   * DLL
+   */
+  struct IdpClient *prev;
+
+  /**
+   * DLL
+   */
+  struct IdpClient *next;
 
   /**
    * The client
@@ -289,17 +148,17 @@ struct IdpClient
    * Message queue for transmission to @e client
    */
   struct GNUNET_MQ_Handle *mq;
-  
+
   /**
    * Head of the DLL of
-   * Attribute iteration operations in 
+   * Attribute iteration operations in
    * progress initiated by this client
    */
   struct AttributeIterator *attr_iter_head;
 
   /**
    * Tail of the DLL of
-   * Attribute iteration operations 
+   * Attribute iteration operations
    * in progress initiated by this client
    */
   struct AttributeIterator *attr_iter_tail;
@@ -317,32 +176,32 @@ struct IdpClient
   /**
    * Head of DLL of ticket revocation ops
    */
-  struct TicketRevocationHandle *revoke_op_head;
+  struct TicketRevocationOperation *revoke_op_head;
 
   /**
    * Tail of DLL of ticket revocation ops
    */
-  struct TicketRevocationHandle *revoke_op_tail;
+  struct TicketRevocationOperation *revoke_op_tail;
 
   /**
    * Head of DLL of ticket issue ops
    */
-  struct TicketIssueHandle *issue_op_head;
+  struct TicketIssueOperation *issue_op_head;
 
   /**
    * Tail of DLL of ticket issue ops
    */
-  struct TicketIssueHandle *issue_op_tail;
+  struct TicketIssueOperation *issue_op_tail;
 
   /**
    * Head of DLL of ticket consume ops
    */
-  struct ConsumeTicketHandle *consume_op_head;
+  struct ConsumeTicketOperation *consume_op_head;
 
   /**
    * Tail of DLL of ticket consume ops
    */
-  struct ConsumeTicketHandle *consume_op_tail;
+  struct ConsumeTicketOperation *consume_op_tail;
 
   /**
    * Head of DLL of attribute store ops
@@ -353,20 +212,32 @@ struct IdpClient
    * 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 AttributeStoreHandle
+
+/**
+ * Handle for attribute deletion request
+ */
+struct AttributeDeleteHandle
 {
   /**
    * DLL
    */
-  struct AttributeStoreHandle *next;
+  struct AttributeDeleteHandle *next;
 
   /**
    * DLL
    */
-  struct AttributeStoreHandle *prev;
+  struct AttributeDeleteHandle *prev;
 
   /**
    * Client connection
@@ -378,30 +249,36 @@ struct AttributeStoreHandle
    */
   struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
 
+
   /**
-   * Identity pubkey
+   * QueueEntry
    */
-  struct GNUNET_CRYPTO_EcdsaPublicKey identity_pkey;
+  struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
 
   /**
-   * The issuer egos ABE master key
+   * Iterator
    */
-  struct GNUNET_ABE_AbeMasterKey *abe_key;
+  struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
 
   /**
-   * QueueEntry
+   * The attribute to delete
    */
-  struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
+  struct GNUNET_RECLAIM_ATTRIBUTE_Claim *claim;
 
   /**
-   * The attribute to store
+   * Tickets to update
    */
-  struct GNUNET_RECLAIM_ATTRIBUTE_Claim *claim;
+  struct TicketRecordsEntry *tickets_to_update_head;
 
   /**
-   * The attribute expiration interval
+   * Tickets to update
    */
-  struct GNUNET_TIME_Relative exp;
+  struct TicketRecordsEntry *tickets_to_update_tail;
+
+  /**
+   * Attribute label
+   */
+  char *label;
 
   /**
    * request id
@@ -410,20 +287,20 @@ struct AttributeStoreHandle
 };
 
 
-/* Prototype */
-struct ParallelLookup;
-
-struct ConsumeTicketHandle
+/**
+ * Handle for attribute store request
+ */
+struct AttributeStoreHandle
 {
   /**
    * DLL
    */
-  struct ConsumeTicketHandle *next;
+  struct AttributeStoreHandle *next;
 
   /**
    * DLL
    */
-  struct ConsumeTicketHandle *prev;
+  struct AttributeStoreHandle *prev;
 
   /**
    * Client connection
@@ -431,101 +308,51 @@ struct ConsumeTicketHandle
   struct IdpClient *client;
 
   /**
-   * Ticket
-   */
-  struct GNUNET_RECLAIM_Ticket ticket;
-
-  /**
-   * LookupRequest
-   */
-  struct GNUNET_GNS_LookupRequest *lookup_request;
-
-  /**
-   * Audience Key
+   * Identity
    */
   struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
 
   /**
-   * Audience Key
+   * Identity pubkey
    */
-  struct GNUNET_CRYPTO_EcdsaPublicKey identity_pub;
+  struct GNUNET_CRYPTO_EcdsaPublicKey identity_pkey;
 
   /**
-   * Lookup DLL
+   * QueueEntry
    */
-  struct ParallelLookup *parallel_lookups_head;
+  struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
 
   /**
-   * Lookup DLL
-   */
-  struct ParallelLookup *parallel_lookups_tail;
-  
-  /**
-   * Kill task
+   * The attribute to store
    */
-  struct GNUNET_SCHEDULER_Task *kill_task;
+  struct GNUNET_RECLAIM_ATTRIBUTE_Claim *claim;
 
   /**
-   * The ABE key
+   * The attribute expiration interval
    */
-  struct GNUNET_ABE_AbeKey *key;
+  struct GNUNET_TIME_Relative exp;
 
-  /**
-   * Attributes
-   */
-  struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
-  
-  /**
-   * Lookup time
-   */
-  struct GNUNET_TIME_Absolute lookup_start_time;
   /**
    * request id
    */
   uint32_t r_id;
 };
 
-/**
- * Handle for a parallel GNS lookup job
- */
-struct ParallelLookup
-{
-  /* DLL */
-  struct ParallelLookup *next;
-
-  /* DLL */
-  struct ParallelLookup *prev;
-
-  /* The GNS request */
-  struct GNUNET_GNS_LookupRequest *lookup_request;
-
-  /* The handle the return to */
-  struct ConsumeTicketHandle *handle;
-
-  /**
-   * Lookup time
-   */
-  struct GNUNET_TIME_Absolute lookup_start_time;
-
-  /* The label to look up */
-  char *label;
-};
 
 /**
- * Ticket revocation request handle
+ * Handle for ticket consume request
  */
-struct TicketRevocationHandle
+struct ConsumeTicketOperation
 {
   /**
    * DLL
    */
-  struct TicketRevocationHandle *prev;
+  struct ConsumeTicketOperation *next;
 
   /**
    * DLL
    */
-  struct TicketRevocationHandle *next;
+  struct ConsumeTicketOperation *prev;
 
   /**
    * Client connection
@@ -533,67 +360,31 @@ struct TicketRevocationHandle
   struct IdpClient *client;
 
   /**
-   * Attributes to reissue
-   */
-  struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
-
-  /**
-   * Attributes to revoke
-   */
-  struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *rvk_attrs;
-
-  /**
-   * Issuer Key
-   */
-  struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
-
-  /**
-   * Ticket to issue
-   */
-  struct GNUNET_RECLAIM_Ticket ticket;
-
-  /**
-   * QueueEntry
-   */
-  struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
-
-  /**
-   * Namestore iterator
-   */
-  struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
-
-  /**
-   * The ABE master key
-   */
-  struct GNUNET_ABE_AbeMasterKey *abe_key;
-
-  /**
-   * Offset
+   * request id
    */
-  uint32_t offset;
+  uint32_t r_id;
 
   /**
-   * request id
+   * Ticket consume handle
    */
-  uint32_t r_id;
+  struct RECLAIM_TICKETS_ConsumeHandle *ch;
 };
 
 
-
 /**
- * Ticket issue request handle
+ * Ticket revocation request handle
  */
-struct TicketIssueHandle
+struct TicketRevocationOperation
 {
   /**
    * DLL
    */
-  struct TicketIssueHandle *prev;
+  struct TicketRevocationOperation *prev;
 
   /**
    * DLL
    */
-  struct TicketIssueHandle *next;
+  struct TicketRevocationOperation *next;
 
   /**
    * Client connection
@@ -601,24 +392,9 @@ struct TicketIssueHandle
   struct IdpClient *client;
 
   /**
-   * Attributes to issue
-   */
-  struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
-
-  /**
-   * Issuer Key
-   */
-  struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
-
-  /**
-   * Ticket to issue
-   */
-  struct GNUNET_RECLAIM_Ticket ticket;
-
-  /**
-   * QueueEntry
+   * Revocation handle
    */
-  struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
+  struct RECLAIM_TICKETS_RevokeHandle *rh;
 
   /**
    * request id
@@ -628,462 +404,261 @@ struct TicketIssueHandle
 
 
 /**
- * DLL for ego handles to egos containing the ID_ATTRS in a map in json_t format
- *
+ * Ticket issue operation handle
  */
-struct EgoEntry
+struct TicketIssueOperation
 {
   /**
    * DLL
    */
-  struct EgoEntry *next;
+  struct TicketIssueOperation *prev;
 
   /**
    * DLL
    */
-  struct EgoEntry *prev;
+  struct TicketIssueOperation *next;
 
   /**
-   * Ego handle
+   * Client connection
    */
-  struct GNUNET_IDENTITY_Ego *ego;
+  struct IdpClient *client;
 
   /**
-   * Attribute map. Contains the attributes as json_t
+   * request id
    */
-  struct GNUNET_CONTAINER_MultiHashMap *attr_map;
-
+  uint32_t r_id;
 };
 
+
 /**
- * Cleanup task
+ * Client list
  */
-static void
-cleanup()
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Cleaning up\n");
+static struct IdpClient *client_list_head = NULL;
 
-  if (NULL != stats)
-  {
-    GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
-    stats = NULL;
-  }
-  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)
-    GNUNET_SCHEDULER_cancel (update_task);
-  if (NULL != identity_handle)
-    GNUNET_IDENTITY_disconnect (identity_handle);
-  if (NULL != gns_handle)
-    GNUNET_GNS_disconnect (gns_handle);
-  if (NULL != credential_handle)
-    GNUNET_CREDENTIAL_disconnect (credential_handle);
-  if (NULL != ns_it)
-    GNUNET_NAMESTORE_zone_iteration_stop (ns_it);
-  if (NULL != ns_qe)
-    GNUNET_NAMESTORE_cancel (ns_qe);
-  if (NULL != ns_handle)
-    GNUNET_NAMESTORE_disconnect (ns_handle);
-  GNUNET_free_non_null (token);
-  GNUNET_free_non_null (label);
+/**
+ * Client list
+ */
+static struct IdpClient *client_list_tail = NULL;
 
-}
 
 /**
- * Shutdown task
+ * Cleanup attribute delete handle
  *
- * @param cls NULL
+ * @param adh the attribute to cleanup
  */
 static void
-do_shutdown (void *cls)
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "Shutting down...\n");
-  cleanup();
+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);
 }
 
+
 /**
- * Finished storing newly bootstrapped ABE key
+ * Cleanup attribute store handle
+ *
+ * @param handle handle to clean up
  */
 static void
-bootstrap_store_cont (void *cls,
-                      int32_t success,
-                      const char *emsg)
+cleanup_as_handle (struct AttributeStoreHandle *ash)
 {
-  struct AbeBootstrapHandle *abh = cls;
-  if (GNUNET_SYSERR == success)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Failed to bootstrap ABE master %s\n",
-                emsg);
-    abh->proc (abh->proc_cls, NULL);
-    GNUNET_free (abh->abe_key);
-    GNUNET_free (abh);
-    return;
-  }
-  abh->proc (abh->proc_cls, abh->abe_key);
-  GNUNET_free (abh);
+  if (NULL != ash->ns_qe)
+    GNUNET_NAMESTORE_cancel (ash->ns_qe);
+  if (NULL != ash->claim)
+    GNUNET_free (ash->claim);
+  GNUNET_free (ash);
 }
 
+
 /**
- * Generates and stores a new ABE key
+ * Cleanup client
+ *
+ * @param idp the client to clean up
  */
 static void
-bootstrap_store_task (void *cls)
+cleanup_client (struct IdpClient *idp)
 {
-  struct AbeBootstrapHandle *abh = cls;
-  struct GNUNET_GNSRECORD_Data rd[1];
-  char *key;
-
-  rd[0].data_size = GNUNET_ABE_cpabe_serialize_master_key (abh->abe_key,
-                                                              (void**)&key);
-  rd[0].data = key;
-  rd[0].record_type = GNUNET_GNSRECORD_TYPE_ABE_MASTER;
-  rd[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION | GNUNET_GNSRECORD_RF_PRIVATE;
-  rd[0].expiration_time = GNUNET_TIME_UNIT_HOURS.rel_value_us; //TODO sane?
-  abh->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
-                                               &abh->identity,
-                                               "+",
-                                               1,
-                                               rd,
-                                               &bootstrap_store_cont,
-                                               abh);
-  GNUNET_free (key);
-}
-
-/**
- * Error checking for ABE master
- */
-static void
-bootstrap_abe_error (void *cls)
-{
-  struct AbeBootstrapHandle *abh = cls;
-  abh->proc (abh->proc_cls, NULL);
-  GNUNET_free (abh);
-}
-
-
-/**
- * Handle ABE lookup in namestore
- */
-static void
-bootstrap_abe_result (void *cls,
-                      const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
-                      const char *label,
-                      unsigned int rd_count,
-                      const struct GNUNET_GNSRECORD_Data *rd)
-{
-  struct AbeBootstrapHandle *abh = cls;
-  struct GNUNET_ABE_AbeMasterKey *abe_key;
+  struct AttributeIterator *ai;
+  struct TicketIteration *ti;
+  struct TicketRevocationOperation *rop;
+  struct TicketIssueOperation *iss;
+  struct ConsumeTicketOperation *ct;
+  struct AttributeStoreHandle *as;
+  struct AttributeDeleteHandle *adh;
 
-  for (uint32_t i=0;i<rd_count;i++) {
-    if (GNUNET_GNSRECORD_TYPE_ABE_MASTER != rd[i].record_type)
-      continue;
-    abe_key = GNUNET_ABE_cpabe_deserialize_master_key (rd[i].data,
-                                                          rd[i].data_size);
-    abh->proc (abh->proc_cls, abe_key);
-    GNUNET_free (abh);
-    return;
+  while (NULL != (iss = idp->issue_op_head)) {
+    GNUNET_CONTAINER_DLL_remove (idp->issue_op_head, idp->issue_op_tail, iss);
+    GNUNET_free (iss);
+  }
+  while (NULL != (ct = idp->consume_op_head)) {
+    GNUNET_CONTAINER_DLL_remove (idp->consume_op_head,
+                                 idp->consume_op_tail,
+                                 ct);
+    if (NULL != ct->ch)
+      RECLAIM_TICKETS_consume_cancel (ct->ch);
+    GNUNET_free (ct);
+  }
+  while (NULL != (as = idp->store_op_head)) {
+    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);
   }
 
-  //No ABE master found, bootstrapping...
-  abh->abe_key = GNUNET_ABE_cpabe_create_master_key ();
-  GNUNET_SCHEDULER_add_now (&bootstrap_store_task, abh);
+  while (NULL != (ai = idp->attr_iter_head)) {
+    GNUNET_CONTAINER_DLL_remove (idp->attr_iter_head, idp->attr_iter_tail, ai);
+    GNUNET_free (ai);
+  }
+  while (NULL != (rop = idp->revoke_op_head)) {
+    GNUNET_CONTAINER_DLL_remove (idp->revoke_op_head, idp->revoke_op_tail, rop);
+    if (NULL != rop->rh)
+      RECLAIM_TICKETS_revoke_cancel (rop->rh);
+    GNUNET_free (rop);
+  }
+  while (NULL != (ti = idp->ticket_iter_head)) {
+    GNUNET_CONTAINER_DLL_remove (idp->ticket_iter_head,
+                                 idp->ticket_iter_tail,
+                                 ti);
+    if (NULL != ti->iter)
+      RECLAIM_TICKETS_iteration_stop (ti->iter);
+    GNUNET_free (ti);
+  }
+  GNUNET_free (idp);
 }
 
+
 /**
- * Bootstrap ABE master if it does not yet exists.
- * Will call the AbeBootstrapResult processor when done.
- * will always recreate the ABE key of GNUNET_YES == recreate
+ * Cleanup task
  */
 static void
-bootstrap_abe (const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
-               AbeBootstrapResult proc,
-               void* cls,
-               int recreate)
+cleanup ()
 {
-  struct AbeBootstrapHandle *abh;
+  struct IdpClient *cl;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
 
-  abh = GNUNET_new (struct AbeBootstrapHandle);
-  abh->proc = proc;
-  abh->proc_cls = cls;
-  abh->identity = *identity;
-  if (GNUNET_YES == recreate)
+  while (NULL != (cl = client_list_head))
   {
-    abh->abe_key = GNUNET_ABE_cpabe_create_master_key ();
-    GNUNET_SCHEDULER_add_now (&bootstrap_store_task, abh);
-  } else {
-    abh->ns_qe = GNUNET_NAMESTORE_records_lookup (ns_handle,
-                                                  identity,
-                                                  "+",
-                                                  &bootstrap_abe_error,
-                                                  abh,
-                                                  &bootstrap_abe_result,
-                                                  abh);
+    GNUNET_CONTAINER_DLL_remove (client_list_head,
+                                 client_list_tail,
+                                 cl);
+    cleanup_client (cl);
   }
+  RECLAIM_TICKETS_deinit ();
+  if (NULL != timeout_task)
+    GNUNET_SCHEDULER_cancel (timeout_task);
+  if (NULL != nsh)
+    GNUNET_NAMESTORE_disconnect (nsh);
 }
 
 
-
-static int
-create_sym_key_from_ecdh(const struct GNUNET_HashCode *new_key_hash,
-                         struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
-                         struct GNUNET_CRYPTO_SymmetricInitializationVector *iv)
-{
-  struct GNUNET_CRYPTO_HashAsciiEncoded new_key_hash_str;
-
-  GNUNET_CRYPTO_hash_to_enc (new_key_hash,
-                             &new_key_hash_str);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating symmetric rsa key from %s\n", (char*)&new_key_hash_str);
-  static const char ctx_key[] = "gnuid-aes-ctx-key";
-  GNUNET_CRYPTO_kdf (skey, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey),
-                     new_key_hash, sizeof (struct GNUNET_HashCode),
-                     ctx_key, strlen (ctx_key),
-                     NULL, 0);
-  static const char ctx_iv[] = "gnuid-aes-ctx-iv";
-  GNUNET_CRYPTO_kdf (iv, sizeof (struct GNUNET_CRYPTO_SymmetricInitializationVector),
-                     new_key_hash, sizeof (struct GNUNET_HashCode),
-                     ctx_iv, strlen (ctx_iv),
-                     NULL, 0);
-  return GNUNET_OK;
-}
-
 /**
- * Cleanup ticket consume handle
- * @param handle the handle to clean up
+ * Shutdown task
+ *
+ * @param cls NULL
  */
 static void
-cleanup_ticket_issue_handle (struct TicketIssueHandle *handle)
+do_shutdown (void *cls)
 {
-  if (NULL != handle->attrs)
-    GNUNET_RECLAIM_ATTRIBUTE_list_destroy (handle->attrs);
-  if (NULL != handle->ns_qe)
-    GNUNET_NAMESTORE_cancel (handle->ns_qe);
-  GNUNET_free (handle);
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down...\n");
+  cleanup ();
 }
 
 
+/**
+ * Sends a ticket result message to the client
+ *
+ * @param client the client to send to
+ * @param r_id the request message ID to reply to
+ * @param ticket the ticket to include (may be NULL)
+ * @param success the success status of the request
+ */
 static void
-send_ticket_result (struct IdpClient *client,
+send_ticket_result (const struct IdpClient *client,
                     uint32_t r_id,
                     const struct GNUNET_RECLAIM_Ticket *ticket,
-                    const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs)
+                    uint32_t success)
 {
   struct TicketResultMessage *irm;
   struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_RECLAIM_Ticket *ticket_buf;
 
-  /* store ticket in DB */
-  if (GNUNET_OK != TKT_database->store_ticket (TKT_database->cls,
-                                               ticket,
-                                               attrs))
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Unable to store ticket after issue\n");
-    GNUNET_break (0);
+  env = GNUNET_MQ_msg (irm,
+                       GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT);
+  if (NULL != ticket) {
+    irm->ticket = *ticket;
   }
-
-  env = GNUNET_MQ_msg_extra (irm,
-                             sizeof (struct GNUNET_RECLAIM_Ticket),
-                             GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT);
-  ticket_buf = (struct GNUNET_RECLAIM_Ticket *)&irm[1];
-  *ticket_buf = *ticket;
+  // TODO add success member
   irm->id = htonl (r_id);
-  GNUNET_MQ_send (client->mq,
-                  env);
-}
-
-static void
-store_ticket_issue_cont (void *cls,
-                         int32_t success,
-                         const char *emsg)
-{
-  struct TicketIssueHandle *handle = cls;
-
-  handle->ns_qe = NULL;
-  GNUNET_CONTAINER_DLL_remove (handle->client->issue_op_head,
-                               handle->client->issue_op_tail,
-                               handle);
-  if (GNUNET_SYSERR == success)
-  {
-    cleanup_ticket_issue_handle (handle);
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
-                "Unknown Error\n");
-    GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
-    return;
-  }
-  send_ticket_result (handle->client,
-                      handle->r_id,
-                      &handle->ticket,
-                      handle->attrs);
-  cleanup_ticket_issue_handle (handle);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending TICKET_RESULT message\n");
+  GNUNET_MQ_send (client->mq, env);
 }
 
 
-
-int
-serialize_abe_keyinfo2 (const struct GNUNET_RECLAIM_Ticket *ticket,
-                        const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
-                        const struct GNUNET_ABE_AbeKey *rp_key,
-                        struct GNUNET_CRYPTO_EcdhePrivateKey **ecdh_privkey,
-                        char **result)
-{
-  struct GNUNET_CRYPTO_EcdhePublicKey ecdh_pubkey;
-  struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
-  char *enc_keyinfo;
-  char *serialized_key;
-  char *buf;
-  char *write_ptr;
-  char attrs_str_len;
-  ssize_t size;
-
-  struct GNUNET_CRYPTO_SymmetricSessionKey skey;
-  struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
-  struct GNUNET_HashCode new_key_hash;
-  ssize_t enc_size;
-
-  size = GNUNET_ABE_cpabe_serialize_key (rp_key,
-                                         (void**)&serialized_key);
-  attrs_str_len = 0;
-  for (le = attrs->list_head; NULL != le; le = le->next) {
-    attrs_str_len += strlen (le->claim->name) + 1;
-  }
-  buf = GNUNET_malloc (attrs_str_len + size);
-  write_ptr = buf;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Writing attributes\n");
-  for (le = attrs->list_head; NULL != le; le = le->next) {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "%s\n", le->claim->name);
-
-
-    GNUNET_memcpy (write_ptr,
-                   le->claim->name,
-                   strlen (le->claim->name));
-    write_ptr[strlen (le->claim->name)] = ',';
-    write_ptr += strlen (le->claim->name) + 1;
-  }
-  write_ptr--;
-  write_ptr[0] = '\0'; //replace last , with a 0-terminator
-  write_ptr++;
-  GNUNET_memcpy (write_ptr,
-                 serialized_key,
-                 size);
-  GNUNET_free (serialized_key);
-  // ECDH keypair E = eG
-  *ecdh_privkey = GNUNET_CRYPTO_ecdhe_key_create();
-  GNUNET_CRYPTO_ecdhe_key_get_public (*ecdh_privkey,
-                                      &ecdh_pubkey);
-  enc_keyinfo = GNUNET_malloc (size + attrs_str_len);
-  // Derived key K = H(eB)
-  GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdh_ecdsa (*ecdh_privkey,
-                                                        &ticket->audience,
-                                                        &new_key_hash));
-  create_sym_key_from_ecdh(&new_key_hash, &skey, &iv);
-  enc_size = GNUNET_CRYPTO_symmetric_encrypt (buf,
-                                              size + attrs_str_len,
-                                              &skey, &iv,
-                                              enc_keyinfo);
-  *result = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)+
-                           enc_size);
-  GNUNET_memcpy (*result,
-                 &ecdh_pubkey,
-                 sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
-  GNUNET_memcpy (*result + sizeof (struct GNUNET_CRYPTO_EcdhePublicKey),
-                 enc_keyinfo,
-                 enc_size);
-  GNUNET_free (enc_keyinfo);
-  GNUNET_free (buf);
-  return sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)+enc_size;
-}
-
-
-
+/**
+ * Issue ticket result
+ *
+ * @param cls out ticket issue operation handle
+ * @param ticket the issued ticket
+ * @param success issue success status (GNUNET_OK if successful)
+ * @param emsg error message (NULL of success is GNUNET_OK)
+ */
 static void
-issue_ticket_after_abe_bootstrap (void *cls,
-                                  struct GNUNET_ABE_AbeMasterKey *abe_key)
-{
-  struct TicketIssueHandle *ih = cls;
-  struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
-  struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey;
-  struct GNUNET_GNSRECORD_Data code_record[1];
-  struct GNUNET_ABE_AbeKey *rp_key;
-  char *code_record_data;
-  char **attrs;
-  char *label;
-  char *policy;
-  int attrs_len;
-  uint32_t i;
-  size_t code_record_len;
-
-  //Create new ABE key for RP
-  attrs_len = 0;
-  for (le = ih->attrs->list_head; NULL != le; le = le->next)
-    attrs_len++;
-  attrs = GNUNET_malloc ((attrs_len + 1)*sizeof (char*));
-  i = 0;
-  for (le = ih->attrs->list_head; NULL != le; le = le->next) {
-    GNUNET_asprintf (&policy, "%s_%lu",
-                     le->claim->name,
-                     le->claim->version);
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Adding attribute to key: %s\n",
-                policy);
-    attrs[i] = policy;
-    i++;
+issue_ticket_result_cb (void *cls,
+                        struct GNUNET_RECLAIM_Ticket *ticket,
+                        int32_t success,
+                        const char *emsg)
+{
+  struct TicketIssueOperation *tio = cls;
+  if (GNUNET_OK != success) {
+    send_ticket_result (tio->client, tio->r_id, NULL, GNUNET_SYSERR);
+    GNUNET_CONTAINER_DLL_remove (tio->client->issue_op_head,
+                                 tio->client->issue_op_tail,
+                                 tio);
+    GNUNET_free (tio);
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error issuing ticket: %s\n", emsg);
+    return;
   }
-  attrs[i] = NULL;
-  rp_key = GNUNET_ABE_cpabe_create_key (abe_key,
-                                        attrs);
-
-  //TODO review this wireformat
-  code_record_len = serialize_abe_keyinfo2 (&ih->ticket,
-                                            ih->attrs,
-                                            rp_key,
-                                            &ecdhe_privkey,
-                                            &code_record_data);
-  code_record[0].data = code_record_data;
-  code_record[0].data_size = code_record_len;
-  code_record[0].expiration_time = GNUNET_TIME_UNIT_DAYS.rel_value_us;
-  code_record[0].record_type = GNUNET_GNSRECORD_TYPE_ABE_KEY;
-  code_record[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
-
-  label = GNUNET_STRINGS_data_to_string_alloc (&ih->ticket.rnd,
-                                               sizeof (uint64_t));
-  //Publish record
-  ih->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
-                                              &ih->identity,
-                                              label,
-                                              1,
-                                              code_record,
-                                              &store_ticket_issue_cont,
-                                              ih);
-  //for (; i > 0; i--)
-  //  GNUNET_free (attrs[i-1]);
-  GNUNET_free (ecdhe_privkey);
-  GNUNET_free (label);
-  GNUNET_free (attrs);
-  GNUNET_free (code_record_data);
-  GNUNET_ABE_cpabe_delete_key (rp_key,
-                               GNUNET_YES);
-  GNUNET_ABE_cpabe_delete_master_key (abe_key);
+  send_ticket_result (tio->client, tio->r_id, ticket, GNUNET_SYSERR);
+  GNUNET_CONTAINER_DLL_remove (tio->client->issue_op_head,
+                               tio->client->issue_op_tail,
+                               tio);
+  GNUNET_free (tio);
 }
 
 
+/**
+ * Check issue ticket message
+ *
+ * @cls unused
+ * @im message to check
+ * @return GNUNET_OK if message is ok
+ */
 static int
-check_issue_ticket_message(void *cls,
-                           const struct IssueTicketMessage *im)
+check_issue_ticket_message (void *cls, const struct IssueTicketMessage *im)
 {
   uint16_t size;
 
   size = ntohs (im->header.size);
-  if (size <= sizeof (struct IssueTicketMessage))
-  {
+  if (size <= sizeof (struct IssueTicketMessage)) {
     GNUNET_break (0);
     return GNUNET_SYSERR;
   }
@@ -1091,1006 +666,582 @@ check_issue_ticket_message(void *cls,
 }
 
 
+/**
+ * Handle ticket issue message
+ *
+ * @param cls our client
+ * @param im the message
+ */
 static void
-handle_issue_ticket_message (void *cls,
-                             const struct IssueTicketMessage *im)
+handle_issue_ticket_message (void *cls, const struct IssueTicketMessage *im)
 {
-  struct TicketIssueHandle *ih;
+  struct TicketIssueOperation *tio;
   struct IdpClient *idp = cls;
+  struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
   size_t attrs_len;
 
-  ih = GNUNET_new (struct TicketIssueHandle);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ISSUE_TICKET message\n");
+  tio = GNUNET_new (struct TicketIssueOperation);
   attrs_len = ntohs (im->attr_len);
-  ih->attrs = GNUNET_RECLAIM_ATTRIBUTE_list_deserialize ((char*)&im[1], attrs_len);
-  ih->r_id = ntohl (im->id);
-  ih->client = idp;
-  ih->identity = im->identity;
-  GNUNET_CRYPTO_ecdsa_key_get_public (&ih->identity,
-                                      &ih->ticket.identity);
-  ih->ticket.audience = im->rp;
-  ih->ticket.rnd =
-    GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG,
-                              UINT64_MAX);
-  GNUNET_CONTAINER_DLL_insert (idp->issue_op_head,
-                               idp->issue_op_tail,
-                               ih);
-  bootstrap_abe (&ih->identity, &issue_ticket_after_abe_bootstrap, ih, GNUNET_NO);
+  attrs = GNUNET_RECLAIM_ATTRIBUTE_list_deserialize ((char *)&im[1], attrs_len);
+  tio->r_id = ntohl (im->id);
+  tio->client = idp;
+  GNUNET_CONTAINER_DLL_insert (idp->issue_op_head, idp->issue_op_tail, tio);
+  RECLAIM_TICKETS_issue (&im->identity,
+                         attrs,
+                         &im->rp,
+                         &issue_ticket_result_cb,
+                         tio);
   GNUNET_SERVICE_client_continue (idp->client);
-
+  GNUNET_RECLAIM_ATTRIBUTE_list_destroy (attrs);
 }
 
+
+
 /**********************************************************
  * Revocation
  **********************************************************/
 
 /**
- * Cleanup revoke handle
- *
- * @param rh the ticket revocation handle
- */
-static void
-cleanup_revoke_ticket_handle (struct TicketRevocationHandle *rh)
-{
-  if (NULL != rh->attrs)
-    GNUNET_RECLAIM_ATTRIBUTE_list_destroy (rh->attrs);
-  if (NULL != rh->rvk_attrs)
-    GNUNET_RECLAIM_ATTRIBUTE_list_destroy (rh->rvk_attrs);
-  if (NULL != rh->abe_key)
-    GNUNET_ABE_cpabe_delete_master_key (rh->abe_key);
-  if (NULL != rh->ns_qe)
-    GNUNET_NAMESTORE_cancel (rh->ns_qe);
-  if (NULL != rh->ns_it)
-    GNUNET_NAMESTORE_zone_iteration_stop (rh->ns_it);
-  GNUNET_free (rh);
-}
-
-
-/**
- * Send revocation result
+ * Handles revocation result
  *
- * @param rh ticket revocation handle
- * @param success GNUNET_OK if successful result
+ * @param cls our revocation operation handle
+ * @param success revocation result (GNUNET_OK if successful)
  */
 static void
-send_revocation_finished (struct TicketRevocationHandle *rh,
-                          uint32_t success)
+revoke_result_cb (void *cls, int32_t success)
 {
+  struct TicketRevocationOperation *rop = cls;
   struct GNUNET_MQ_Envelope *env;
   struct RevokeTicketResultMessage *trm;
-  
-  GNUNET_break(TKT_database->delete_ticket (TKT_database->cls,
-                                            &rh->ticket));
 
-  env = GNUNET_MQ_msg (trm,
-                       GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET_RESULT);
-  trm->id = htonl (rh->r_id);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending REVOKE_TICKET_RESULT message\n");
+  rop->rh = NULL;
+  env = GNUNET_MQ_msg (trm, GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET_RESULT);
+  trm->id = htonl (rop->r_id);
   trm->success = htonl (success);
-  GNUNET_MQ_send (rh->client->mq,
-                  env);
-  GNUNET_CONTAINER_DLL_remove (rh->client->revoke_op_head,
-                               rh->client->revoke_op_tail,
-                               rh);
+  GNUNET_MQ_send (rop->client->mq, env);
+  GNUNET_CONTAINER_DLL_remove (rop->client->revoke_op_head,
+                               rop->client->revoke_op_tail,
+                               rop);
+  GNUNET_free (rop);
 }
 
 
 /**
- * Process ticket from database
+ * Check revocation message format
  *
- * @param cls struct TicketIterationProcResult
- * @param ticket the ticket
- * @param attrs the attributes
+ * @param cls unused
+ * @param im the message to check
+ * @return GNUNET_OK if message is ok
  */
-static void
-ticket_reissue_proc (void *cls,
-                     const struct GNUNET_RECLAIM_Ticket *ticket,
-                     const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs);
-
-static void
-revocation_reissue_tickets (struct TicketRevocationHandle *rh);
-
-
-static void reissue_next (void *cls)
-{
-  struct TicketRevocationHandle *rh = cls;
-  revocation_reissue_tickets (rh);
-}
-
-
-static void
-reissue_ticket_cont (void *cls,
-                     int32_t success,
-                     const char *emsg)
+static int
+check_revoke_ticket_message (void *cls, const struct RevokeTicketMessage *im)
 {
-  struct TicketRevocationHandle *rh = cls;
+  uint16_t size;
 
-  rh->ns_qe = NULL;
-  if (GNUNET_SYSERR == success)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
-                "Unknown Error\n");
-    send_revocation_finished (rh, GNUNET_SYSERR);
-    cleanup_revoke_ticket_handle (rh);
-    return;
+  size = ntohs (im->header.size);
+  if (size != sizeof (struct RevokeTicketMessage)) {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
   }
-  rh->offset++;
-  GNUNET_SCHEDULER_add_now (&reissue_next, rh);
+  return GNUNET_OK;
 }
 
 
 /**
- * Process ticket from database
+ * Handle a revocation message to a ticket.
  *
- * @param cls struct TicketIterationProcResult
- * @param ticket the ticket
- * @param attrs the attributes
+ * @param cls our client
+ * @param rm the message to handle
  */
 static void
-ticket_reissue_proc (void *cls,
-                     const struct GNUNET_RECLAIM_Ticket *ticket,
-                     const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs)
+handle_revoke_ticket_message (void *cls, const struct RevokeTicketMessage *rm)
 {
-  struct TicketRevocationHandle *rh = cls;
-  struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
-  struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le_rollover;
-  struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey;
-  struct GNUNET_GNSRECORD_Data code_record[1];
-  struct GNUNET_ABE_AbeKey *rp_key;
-  char *code_record_data;
-  char **attr_arr;
-  char *label;
-  char *policy;
-  int attrs_len;
-  uint32_t i;
-  int reissue_ticket;
-  size_t code_record_len;
-
-
-  if (NULL == ticket)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Iteration done\n");
-    return;
-  }
-
-  if (0 == memcmp (&ticket->audience,
-                   &rh->ticket.audience,
-                   sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Do not reissue for this identity.!\n");
-    label = GNUNET_STRINGS_data_to_string_alloc (&rh->ticket.rnd,
-                                                 sizeof (uint64_t));
-    //Delete record
-    rh->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
-                                                &rh->identity,
-                                                label,
-                                                0,
-                                                NULL,
-                                                &reissue_ticket_cont,
-                                                rh);
-
-    GNUNET_free (label);
-    return;
-  }
-
-  /* 
-   * Check if any attribute of this ticket intersects with a rollover attribute
-   */
-  reissue_ticket = GNUNET_NO;
-  for (le = attrs->list_head; NULL != le; le = le->next)
-  {
-    for (le_rollover = rh->rvk_attrs->list_head;
-         NULL != le_rollover;
-         le_rollover = le_rollover->next)
-    {
-      if (0 == strcmp (le_rollover->claim->name,
-                       le->claim->name))
-      {
-        reissue_ticket = GNUNET_YES;
-        le->claim->version = le_rollover->claim->version;
-      }
-    }
-  }
-
-  if (GNUNET_NO == reissue_ticket)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Skipping ticket.\n");
-
-    rh->offset++;
-    GNUNET_SCHEDULER_add_now (&reissue_next, rh);
-
-
-    return;
-  }
+  struct TicketRevocationOperation *rop;
+  struct IdpClient *idp = cls;
 
-  //Create new ABE key for RP
-  attrs_len = 0;
-
-  /* If this is the RP we want to revoke attributes of, the do so */
-
-  for (le = attrs->list_head; NULL != le; le = le->next)
-    attrs_len++;
-  attr_arr = GNUNET_malloc ((attrs_len + 1)*sizeof (char*));
-  i = 0;
-  for (le = attrs->list_head; NULL != le; le = le->next) {
-    GNUNET_asprintf (&policy, "%s_%lu",
-                     le->claim->name,
-                     le->claim->version);
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Recreating key with %s\n", policy);
-    attr_arr[i] = policy;
-    i++;
-  }
-  attr_arr[i] = NULL;
-  rp_key = GNUNET_ABE_cpabe_create_key (rh->abe_key,
-                                        attr_arr);
-
-  //TODO review this wireformat
-  code_record_len = serialize_abe_keyinfo2 (ticket,
-                                            attrs,
-                                            rp_key,
-                                            &ecdhe_privkey,
-                                            &code_record_data);
-  code_record[0].data = code_record_data;
-  code_record[0].data_size = code_record_len;
-  code_record[0].expiration_time = GNUNET_TIME_UNIT_DAYS.rel_value_us;
-  code_record[0].record_type = GNUNET_GNSRECORD_TYPE_ABE_KEY;
-  code_record[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
-
-  label = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
-                                               sizeof (uint64_t));
-  //Publish record
-  rh->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
-                                              &rh->identity,
-                                              label,
-                                              1,
-                                              code_record,
-                                              &reissue_ticket_cont,
-                                              rh);
-  //for (; i > 0; i--)
-  //  GNUNET_free (attr_arr[i-1]);
-  GNUNET_free (ecdhe_privkey);
-  GNUNET_free (label);
-  GNUNET_free (attr_arr);
-  GNUNET_free (code_record_data);
-  GNUNET_ABE_cpabe_delete_key (rp_key, GNUNET_YES);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received REVOKE_TICKET message\n");
+  rop = GNUNET_new (struct TicketRevocationOperation);
+  rop->r_id = ntohl (rm->id);
+  rop->client = idp;
+  GNUNET_CONTAINER_DLL_insert (idp->revoke_op_head, idp->revoke_op_tail, rop);
+  rop->rh
+    = RECLAIM_TICKETS_revoke (&rm->ticket, &rm->identity, &revoke_result_cb, rop);
+  GNUNET_SERVICE_client_continue (idp->client);
 }
 
 
-/* Prototype for below function */
-static void
-attr_reenc_cont (void *cls,
-                 int32_t success,
-                 const char *emsg);
-
-static void
-revocation_reissue_tickets (struct TicketRevocationHandle *rh)
-{
-  int ret;
-  /* Done, issue new keys */
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Revocation Phase III: Reissuing Tickets\n");
-  if (GNUNET_SYSERR == (ret = TKT_database->iterate_tickets (TKT_database->cls,
-                                                             &rh->ticket.identity,
-                                                             GNUNET_NO,
-                                                             rh->offset,
-                                                             &ticket_reissue_proc,
-                                                             rh)))
-  {
-    GNUNET_break (0);
-  }
-  if (GNUNET_NO == ret)
-  {
-    send_revocation_finished (rh, GNUNET_OK);
-    cleanup_revoke_ticket_handle (rh);
-    return;
-  }
-}
-
 /**
- * Failed to check for attribute
+ * Handle a ticket consume result
+ *
+ * @param cls our consume ticket operation handle
+ * @param identity the attribute authority
+ * @param attrs the attribute/claim list
+ * @param success GNUNET_OK if successful
+ * @param emsg error message (NULL if success=GNUNET_OK)
  */
 static void
-check_attr_error (void *cls)
+consume_result_cb (void *cls,
+                   const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
+                   const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
+                   int32_t success,
+                   const char *emsg)
 {
-  struct TicketRevocationHandle *rh = cls;
-  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-              "Unable to check for existing attribute\n");
-  rh->ns_qe = NULL;
-  send_revocation_finished (rh, GNUNET_SYSERR);
-  cleanup_revoke_ticket_handle (rh);
+  struct ConsumeTicketOperation *cop = cls;
+  struct ConsumeTicketResultMessage *crm;
+  struct GNUNET_MQ_Envelope *env;
+  char *data_tmp;
+  size_t attrs_len;
+  if (GNUNET_OK != success) {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error consuming ticket: %s\n", emsg);
+  }
+  attrs_len = GNUNET_RECLAIM_ATTRIBUTE_list_serialize_get_size (attrs);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending CONSUME_TICKET_RESULT message\n");
+  env = GNUNET_MQ_msg_extra (crm,
+                             attrs_len,
+                             GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT);
+  crm->id = htonl (cop->r_id);
+  crm->attrs_len = htons (attrs_len);
+  crm->identity = *identity;
+  crm->result = htonl (success);
+  data_tmp = (char *)&crm[1];
+  GNUNET_RECLAIM_ATTRIBUTE_list_serialize (attrs, data_tmp);
+  GNUNET_MQ_send (cop->client->mq, env);
+  GNUNET_CONTAINER_DLL_remove (cop->client->consume_op_head,
+                               cop->client->consume_op_tail,
+                               cop);
+  GNUNET_free (cop);
 }
 
 
 /**
- * Revoke next attribte by reencryption with
- * new ABE master
- */
-static void
-reenc_next_attribute (void *cls);
-
-/**
- * Check for existing attribute and overwrite
+ * Check a consume ticket message
+ *
+ * @param cls unused
+ * @param cm the message to handle
  */
-static void
-check_attr_cb (void *cls,
-               const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
-               const char *label,
-               unsigned int rd_count,
-               const struct GNUNET_GNSRECORD_Data *rd_old)
+static int
+check_consume_ticket_message (void *cls, const struct ConsumeTicketMessage *cm)
 {
-  struct TicketRevocationHandle *rh = cls;
-  struct GNUNET_GNSRECORD_Data rd[1];
-  char* buf;
-  char* enc_buf;
-  size_t enc_size;
-  char* rd_buf;
-  size_t buf_size;
-  char* policy;
-  uint32_t attr_ver;
-
-  rh->ns_qe = NULL;
-  if (1 != rd_count) {
-    GNUNET_SCHEDULER_add_now (&reenc_next_attribute,
-                              rh);
-    return;
-  }
+  uint16_t size;
 
-  buf_size = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (rh->attrs->list_head->claim);
-  buf = GNUNET_malloc (buf_size);
-  rh->attrs->list_head->claim->version++;
-  GNUNET_RECLAIM_ATTRIBUTE_serialize (rh->attrs->list_head->claim,
-                                       buf);
-  GNUNET_asprintf (&policy, "%s_%lu",
-                   rh->attrs->list_head->claim->name,
-                   rh->attrs->list_head->claim->version);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Encrypting with policy %s\n", policy);
-  /**
-   * Encrypt the attribute value and store in namestore
-   */
-  enc_size = GNUNET_ABE_cpabe_encrypt (buf,
-                                       buf_size,
-                                       policy, //Policy
-                                       rh->abe_key,
-                                       (void**)&enc_buf);
-  GNUNET_free (buf);
-  if (GNUNET_SYSERR == enc_size)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Unable to re-encrypt with policy %s\n",
-                policy);
-    GNUNET_free (policy);
-    send_revocation_finished (rh, GNUNET_SYSERR);
-    cleanup_revoke_ticket_handle (rh);
-    return;
+  size = ntohs (cm->header.size);
+  if (size != sizeof (struct ConsumeTicketMessage)) {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
   }
-  GNUNET_free (policy);
-
-  rd[0].data_size = enc_size + sizeof (uint32_t);
-  rd_buf = GNUNET_malloc (rd[0].data_size);
-  attr_ver = htonl (rh->attrs->list_head->claim->version);
-  GNUNET_memcpy (rd_buf,
-                 &attr_ver,
-                 sizeof (uint32_t));
-  GNUNET_memcpy (rd_buf+sizeof (uint32_t),
-                 enc_buf,
-                 enc_size);
-  rd[0].data = rd_buf;
-  rd[0].record_type = GNUNET_GNSRECORD_TYPE_ID_ATTR;
-  rd[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
-  rd[0].expiration_time = rd_old[0].expiration_time;
-  rh->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
-                                              &rh->identity,
-                                              rh->attrs->list_head->claim->name,
-                                              1,
-                                              rd,
-                                              &attr_reenc_cont,
-                                              rh);
-  GNUNET_free (enc_buf);
-  GNUNET_free (rd_buf);
+  return GNUNET_OK;
 }
 
 
 /**
- * Revoke next attribte by reencryption with
- * new ABE master
+ * Handle a consume ticket message
+ *
+ * @param cls our client handle
+ * @cm the message to handle
  */
 static void
-reenc_next_attribute (void *cls)
+handle_consume_ticket_message (void *cls, const struct ConsumeTicketMessage *cm)
 {
-  struct TicketRevocationHandle *rh = cls;
-  if (NULL == rh->attrs->list_head)
-  {
-    revocation_reissue_tickets (rh);
-    return;
-  }
-  /* First check if attribute still exists */
-  rh->ns_qe = GNUNET_NAMESTORE_records_lookup (ns_handle,
-                                               &rh->identity,
-                                               rh->attrs->list_head->claim->name,
-                                               &check_attr_error,
-                                               rh,
-                                               &check_attr_cb,
-                                               rh);
+  struct ConsumeTicketOperation *cop;
+  struct IdpClient *idp = cls;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received CONSUME_TICKET message\n");
+  cop = GNUNET_new (struct ConsumeTicketOperation);
+  cop->r_id = ntohl (cm->id);
+  cop->client = idp;
+  cop->ch
+    = RECLAIM_TICKETS_consume (&cm->identity, &cm->ticket, &consume_result_cb, cop);
+  GNUNET_CONTAINER_DLL_insert (idp->consume_op_head, idp->consume_op_tail, cop);
+  GNUNET_SERVICE_client_continue (idp->client);
 }
 
+/*****************************************
+ * Attribute store
+ *****************************************/
+
 
 /**
- * Namestore callback after revoked attribute
- * is stored
+ * Attribute store result handler
+ *
+ * @param cls our attribute store handle
+ * @param success GNUNET_OK if successful
+ * @param emsg error message (NULL if success=GNUNET_OK)
  */
 static void
-attr_reenc_cont (void *cls,
-                 int32_t success,
-                 const char *emsg)
+attr_store_cont (void *cls, int32_t success, const char *emsg)
 {
-  struct TicketRevocationHandle *rh = cls;
-  struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
+  struct AttributeStoreHandle *ash = cls;
+  struct GNUNET_MQ_Envelope *env;
+  struct SuccessResultMessage *acr_msg;
 
-  rh->ns_qe = NULL;
-  if (GNUNET_SYSERR == success)
-  {
+  ash->ns_qe = NULL;
+  GNUNET_CONTAINER_DLL_remove (ash->client->store_op_head,
+                               ash->client->store_op_tail,
+                               ash);
+
+  if (GNUNET_SYSERR == success) {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Failed to reencrypt attribute %s\n",
+                "Failed to store attribute %s\n",
                 emsg);
+    cleanup_as_handle (ash);
     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
     return;
   }
-  if (NULL == rh->attrs->list_head)
-  {
-    revocation_reissue_tickets (rh);
-    return;
-  }
-  le = rh->attrs->list_head;
-  GNUNET_CONTAINER_DLL_remove (rh->attrs->list_head,
-                               rh->attrs->list_tail,
-                               le);
-  GNUNET_assert (NULL != rh->rvk_attrs);
-  GNUNET_CONTAINER_DLL_insert (rh->rvk_attrs->list_head,
-                               rh->rvk_attrs->list_tail,
-                               le);
 
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Re-encrypting next attribute\n");
-  reenc_next_attribute (rh);
+  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);
+  cleanup_as_handle (ash);
 }
 
 
+/**
+ * Add a new attribute
+ *
+ * @param cls the AttributeStoreHandle
+ */
 static void
-process_attributes_to_update (void *cls,
-                              const struct GNUNET_RECLAIM_Ticket *ticket,
-                              const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs)
+attr_store_task (void *cls)
 {
-  struct TicketRevocationHandle *rh = cls;
-
-  rh->attrs = GNUNET_RECLAIM_ATTRIBUTE_list_dup (attrs);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Revocation Phase I: Collecting attributes\n");
-  /* Reencrypt all attributes with new key */
-  if (NULL == rh->attrs->list_head)
-  {
-    /* No attributes to reencrypt */
-    send_revocation_finished (rh, GNUNET_OK);
-    cleanup_revoke_ticket_handle (rh);
-    return;
-  } else {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Revocation Phase II: Re-encrypting attributes\n");
-    reenc_next_attribute (rh);
-  }
+  struct AttributeStoreHandle *ash = cls;
+  struct GNUNET_GNSRECORD_Data rd[1];
+  char *buf;
+  char *label;
+  size_t buf_size;
 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Storing attribute\n");
+  buf_size = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (ash->claim);
+  buf = GNUNET_malloc (buf_size);
+  // Give the ash a new id if unset
+  if (0 == ash->claim->id)
+    ash->claim->id
+      = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
+  GNUNET_RECLAIM_ATTRIBUTE_serialize (ash->claim, buf);
+  label
+    = GNUNET_STRINGS_data_to_string_alloc (&ash->claim->id, sizeof (uint64_t));
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypting with label %s\n", label);
+
+  rd[0].data_size = buf_size;
+  rd[0].data = buf;
+  rd[0].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR;
+  rd[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
+  rd[0].expiration_time = ash->exp.rel_value_us;
+  ash->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
+                                               &ash->identity,
+                                               label,
+                                               1,
+                                               rd,
+                                               &attr_store_cont,
+                                               ash);
+  GNUNET_free (buf);
+  GNUNET_free (label);
 }
 
 
-
-static void
-get_ticket_after_abe_bootstrap (void *cls,
-                                struct GNUNET_ABE_AbeMasterKey *abe_key)
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Finished ABE bootstrap\n");
-  struct TicketRevocationHandle *rh = cls;
-  rh->abe_key = abe_key;
-  TKT_database->get_ticket_attributes (TKT_database->cls,
-                                       &rh->ticket,
-                                       &process_attributes_to_update,
-                                       rh);
-}
-
+/**
+ * Check an attribute store message
+ *
+ * @param cls unused
+ * @param sam the message to check
+ */
 static int
-check_revoke_ticket_message(void *cls,
-                            const struct RevokeTicketMessage *im)
+check_attribute_store_message (void *cls,
+                               const struct AttributeStoreMessage *sam)
 {
   uint16_t size;
 
-  size = ntohs (im->header.size);
-  if (size <= sizeof (struct RevokeTicketMessage))
-  {
+  size = ntohs (sam->header.size);
+  if (size <= sizeof (struct AttributeStoreMessage)) {
     GNUNET_break (0);
     return GNUNET_SYSERR;
   }
   return GNUNET_OK;
 }
 
-static void
-handle_revoke_ticket_message (void *cls,
-                              const struct RevokeTicketMessage *rm)
-{
-  struct TicketRevocationHandle *rh;
-  struct IdpClient *idp = cls;
-  struct GNUNET_RECLAIM_Ticket *ticket;
-
-  rh = GNUNET_new (struct TicketRevocationHandle);
-  ticket = (struct GNUNET_RECLAIM_Ticket*)&rm[1];
-  rh->rvk_attrs = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList);
-  rh->ticket = *ticket;
-  rh->r_id = ntohl (rm->id);
-  rh->client = idp;
-  rh->identity = rm->identity;
-  GNUNET_CRYPTO_ecdsa_key_get_public (&rh->identity,
-                                      &rh->ticket.identity);
-  GNUNET_CONTAINER_DLL_insert (idp->revoke_op_head,
-                               idp->revoke_op_tail,
-                               rh);
-  bootstrap_abe (&rh->identity, &get_ticket_after_abe_bootstrap, rh, GNUNET_NO);
-  GNUNET_SERVICE_client_continue (idp->client);
-
-}
 
 /**
- * Cleanup ticket consume handle
- * @param handle the handle to clean up
+ * Handle an attribute store message
+ *
+ * @param cls our client
+ * @param sam the message to handle
  */
 static void
-cleanup_consume_ticket_handle (struct ConsumeTicketHandle *handle)
+handle_attribute_store_message (void *cls,
+                                const struct AttributeStoreMessage *sam)
 {
-  struct ParallelLookup *lu;  
-  struct ParallelLookup *tmp;
-  if (NULL != handle->lookup_request)
-    GNUNET_GNS_lookup_cancel (handle->lookup_request);
-  for (lu = handle->parallel_lookups_head;
-       NULL != lu;) {
-    GNUNET_GNS_lookup_cancel (lu->lookup_request);
-    GNUNET_free (lu->label);
-    tmp = lu->next;
-    GNUNET_CONTAINER_DLL_remove (handle->parallel_lookups_head,
-                                 handle->parallel_lookups_tail,
-                                 lu);
-    GNUNET_free (lu);
-    lu = tmp;
-  }
-
-  if (NULL != handle->key)
-    GNUNET_ABE_cpabe_delete_key (handle->key,
-                                 GNUNET_YES);
-  if (NULL != handle->attrs)
-    GNUNET_RECLAIM_ATTRIBUTE_list_destroy (handle->attrs);
-  GNUNET_free (handle);
-}
+  struct AttributeStoreHandle *ash;
+  struct IdpClient *idp = cls;
+  size_t data_len;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ATTRIBUTE_STORE message\n");
 
+  data_len = ntohs (sam->attr_len);
 
+  ash = GNUNET_new (struct AttributeStoreHandle);
+  ash->claim = GNUNET_RECLAIM_ATTRIBUTE_deserialize ((char *)&sam[1], data_len);
 
-static int
-check_consume_ticket_message(void *cls,
-                             const struct ConsumeTicketMessage *cm)
-{
-  uint16_t size;
+  ash->r_id = ntohl (sam->id);
+  ash->identity = sam->identity;
+  ash->exp.rel_value_us = GNUNET_ntohll (sam->exp);
+  GNUNET_CRYPTO_ecdsa_key_get_public (&sam->identity, &ash->identity_pkey);
 
-  size = ntohs (cm->header.size);
-  if (size <= sizeof (struct ConsumeTicketMessage))
-  {
-    GNUNET_break (0);
-    return GNUNET_SYSERR;
-  }
-  return GNUNET_OK;
+  GNUNET_SERVICE_client_continue (idp->client);
+  ash->client = idp;
+  GNUNET_CONTAINER_DLL_insert (idp->store_op_head, idp->store_op_tail, ash);
+  GNUNET_SCHEDULER_add_now (&attr_store_task, ash);
 }
 
+
+/**
+ * Send a deletion success response
+ *
+ * @param adh our attribute deletion handle
+ * @param success the success status
+ */
 static void
-process_parallel_lookup2 (void *cls, uint32_t rd_count,
-                          const struct GNUNET_GNSRECORD_Data *rd)
+send_delete_response (struct AttributeDeleteHandle *adh, int32_t success)
 {
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Parallel lookup finished (count=%u)\n", rd_count);
-  struct ParallelLookup *parallel_lookup = cls;
-  struct ConsumeTicketHandle *handle = parallel_lookup->handle;
-  struct ConsumeTicketResultMessage *crm;
   struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *attr_le;
-  struct GNUNET_TIME_Absolute decrypt_duration;
-  char *data;
-  char *data_tmp;
-  ssize_t attr_len;
-  size_t attrs_len;
+  struct SuccessResultMessage *acr_msg;
 
-  GNUNET_CONTAINER_DLL_remove (handle->parallel_lookups_head,
-                               handle->parallel_lookups_tail,
-                               parallel_lookup);
-  GNUNET_free (parallel_lookup->label);
-
-  GNUNET_STATISTICS_update (stats,
-                            "attribute_lookup_time_total",
-                            GNUNET_TIME_absolute_get_duration (parallel_lookup->lookup_start_time).rel_value_us,
-                            GNUNET_YES);
-  GNUNET_STATISTICS_update (stats,
-                            "attribute_lookups_count",
-                            1,
-                            GNUNET_YES);
-
-
-  GNUNET_free (parallel_lookup);
-  if (1 != rd_count)
-    GNUNET_break(0);//TODO
-  if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
-  {
-    decrypt_duration = GNUNET_TIME_absolute_get ();
-    attr_len = GNUNET_ABE_cpabe_decrypt (rd->data + sizeof (uint32_t),
-                                         rd->data_size - sizeof (uint32_t),
-                                         handle->key,
-                                         (void**)&data);
-    if (GNUNET_SYSERR != attr_len) 
-    {
-      GNUNET_STATISTICS_update (stats,
-                                "abe_decrypt_time_total",
-                                GNUNET_TIME_absolute_get_duration (decrypt_duration).rel_value_us,
-                                GNUNET_YES);
-      GNUNET_STATISTICS_update (stats,
-                                "abe_decrypt_count",
-                                1,
-                                GNUNET_YES);
-
-      attr_le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry);
-      attr_le->claim = GNUNET_RECLAIM_ATTRIBUTE_deserialize (data,
-                                                              attr_len);
-      attr_le->claim->version = ntohl(*(uint32_t*)rd->data);
-      GNUNET_CONTAINER_DLL_insert (handle->attrs->list_head,
-                                   handle->attrs->list_tail,
-                                   attr_le);
-      GNUNET_free (data);
-    }
-  }
-  if (NULL != handle->parallel_lookups_head)
-    return; //Wait for more
-  /* Else we are done */
-
-  /* Store ticket in DB */
-  if (GNUNET_OK != TKT_database->store_ticket (TKT_database->cls,
-                                               &handle->ticket,
-                                               handle->attrs))
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Unable to store ticket after consume\n");
-    GNUNET_break (0);
-  }
+  GNUNET_CONTAINER_DLL_remove (adh->client->delete_op_head,
+                               adh->client->delete_op_tail,
+                               adh);
 
-  GNUNET_SCHEDULER_cancel (handle->kill_task);
-  attrs_len = GNUNET_RECLAIM_ATTRIBUTE_list_serialize_get_size (handle->attrs);
-  env = GNUNET_MQ_msg_extra (crm,
-                             attrs_len,
-                             GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT);
-  crm->id = htonl (handle->r_id);
-  crm->attrs_len = htons (attrs_len);
-  crm->identity = handle->ticket.identity;
-  data_tmp = (char *) &crm[1];
-  GNUNET_RECLAIM_ATTRIBUTE_list_serialize (handle->attrs,
-                                            data_tmp);
-  GNUNET_MQ_send (handle->client->mq, env);
-  GNUNET_CONTAINER_DLL_remove (handle->client->consume_op_head,
-                               handle->client->consume_op_tail,
-                               handle);
-  cleanup_consume_ticket_handle (handle);
+  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);
 }
 
-void
-abort_parallel_lookups2 (void *cls)
-{
-  struct ConsumeTicketHandle *handle = cls;
-  struct ParallelLookup *lu;
-  struct ParallelLookup *tmp;
-  struct AttributeResultMessage *arm;
-  struct GNUNET_MQ_Envelope *env;
 
-  handle->kill_task = NULL;
-  for (lu = handle->parallel_lookups_head;
-       NULL != lu;) {
-    GNUNET_GNS_lookup_cancel (lu->lookup_request);
-    GNUNET_free (lu->label);
-    tmp = lu->next;
-    GNUNET_CONTAINER_DLL_remove (handle->parallel_lookups_head,
-                                 handle->parallel_lookups_tail,
-                                 lu);
-    GNUNET_free (lu);
-    lu = tmp;
+/**
+ * Namestore iteration within attribute deletion.
+ * We need to reissue tickets with the deleted attribute removed.
+ *
+ * @param cls our attribute deletion handle
+ * @param zone the private key of the ticket issuer
+ * @param label the label of the record
+ * @param rd_count number of records
+ * @param rd record data
+ */
+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;
   }
-  env = GNUNET_MQ_msg (arm,
-                       GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT);
-  arm->id = htonl (handle->r_id);
-  arm->attr_len = htons (0);
-  GNUNET_MQ_send (handle->client->mq, env);
-
+  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);
 }
 
 
+/**
+ * Recursion prototype for function
+ * @param cls our deletion handle
+ */
 static void
-process_consume_abe_key (void *cls, uint32_t rd_count,
-                         const struct GNUNET_GNSRECORD_Data *rd)
-{
-  struct ConsumeTicketHandle *handle = cls;
-  struct GNUNET_HashCode new_key_hash;
-  struct GNUNET_CRYPTO_SymmetricSessionKey enc_key;
-  struct GNUNET_CRYPTO_SymmetricInitializationVector enc_iv;
-  struct GNUNET_CRYPTO_EcdhePublicKey *ecdh_key;
-  struct ParallelLookup *parallel_lookup;
-  size_t size;
-  char *buf;
-  char *scope;
+update_tickets (void *cls);
 
-  handle->lookup_request = NULL;
-  if (1 != rd_count)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Number of keys %d != 1.",
-                rd_count);
-    cleanup_consume_ticket_handle (handle);
-    GNUNET_CONTAINER_DLL_remove (handle->client->consume_op_head,
-                                 handle->client->consume_op_tail,
-                                 handle);
-    GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
-    return;
-  }
 
-  //Decrypt
-  ecdh_key = (struct GNUNET_CRYPTO_EcdhePublicKey *)rd->data;
-
-  buf = GNUNET_malloc (rd->data_size - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
-
-  //Calculate symmetric key from ecdh parameters
-  GNUNET_assert (GNUNET_OK == 
-                 GNUNET_CRYPTO_ecdsa_ecdh (&handle->identity,
-                                           ecdh_key,
-                                           &new_key_hash));
-  create_sym_key_from_ecdh (&new_key_hash,
-                            &enc_key,
-                            &enc_iv);
-  size = GNUNET_CRYPTO_symmetric_decrypt (rd->data + sizeof (struct GNUNET_CRYPTO_EcdhePublicKey),
-                                          rd->data_size - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey),
-                                          &enc_key,
-                                          &enc_iv,
-                                          buf);
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Decrypted bytes: %zd Expected bytes: %zd\n",
-              size, rd->data_size - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
-  GNUNET_STATISTICS_update (stats,
-                            "abe_key_lookup_time_total",
-                            GNUNET_TIME_absolute_get_duration (handle->lookup_start_time).rel_value_us,
-                            GNUNET_YES);
-  GNUNET_STATISTICS_update (stats,
-                            "abe_key_lookups_count",
-                            1,
-                            GNUNET_YES);
-  scopes = GNUNET_strdup (buf);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Scopes %s\n", scopes);
-  handle->key = GNUNET_ABE_cpabe_deserialize_key ((void*)(buf + strlen (scopes) + 1),
-                                                  rd->data_size - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)
-                                                  - strlen (scopes) - 1);
-
-  for (scope = strtok (scopes, ","); NULL != scope; scope = strtok (NULL, ","))
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Looking up %s\n", scope);
-    parallel_lookup = GNUNET_new (struct ParallelLookup);
-    parallel_lookup->handle = handle;
-    parallel_lookup->label = GNUNET_strdup (scope);
-    parallel_lookup->lookup_start_time = GNUNET_TIME_absolute_get();
-    parallel_lookup->lookup_request
-      = GNUNET_GNS_lookup (gns_handle,
-                           scope,
-                           &handle->ticket.identity,
-                           GNUNET_GNSRECORD_TYPE_ID_ATTR,
-                           GNUNET_GNS_LO_DEFAULT,
-                           &process_parallel_lookup2,
-                           parallel_lookup);
-    GNUNET_CONTAINER_DLL_insert (handle->parallel_lookups_head,
-                                 handle->parallel_lookups_tail,
-                                 parallel_lookup);
-  }
-  GNUNET_free (scopes);
-  GNUNET_free (buf);
-  handle->kill_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES,3),
-                                                    &abort_parallel_lookups2,
-                                                    handle);
+/**
+ * Callback called when a ticket was updated
+ *
+ * @param cls our attribute deletion handle
+ * @param success GNUNET_OK if successful
+ * @param emsg error message (NULL if success=GNUNET_OK)
+ */
+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);
 }
 
 
+/**
+ * Update tickets: Remove shared attribute which has just been deleted.
+ * This method is called recursively until all tickets are processed.
+ * Eventually, the updated tickets are stored using ``update_tickets''.
+ *
+ * @param cls our attribute deletion handle
+ */
 static void
-handle_consume_ticket_message (void *cls,
-                               const struct ConsumeTicketMessage *cm)
+update_tickets (void *cls)
 {
-  struct ConsumeTicketHandle *ch;
-  struct IdpClient *idp = cls;
-  char* rnd_label;
-
-  ch = GNUNET_new (struct ConsumeTicketHandle);
-  ch->r_id = ntohl (cm->id);
-  ch->client = idp;
-  ch->identity = cm->identity;
-  ch->attrs = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList);
-  GNUNET_CRYPTO_ecdsa_key_get_public (&ch->identity,
-                                      &ch->identity_pub);
-  ch->ticket = *((struct GNUNET_RECLAIM_Ticket*)&cm[1]);
-  rnd_label = GNUNET_STRINGS_data_to_string_alloc (&ch->ticket.rnd,
-                                                   sizeof (uint64_t));
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Looking for ABE key under %s\n", rnd_label);
-  ch->lookup_start_time = GNUNET_TIME_absolute_get ();
-  ch->lookup_request
-    = GNUNET_GNS_lookup (gns_handle,
-                         rnd_label,
-                         &ch->ticket.identity,
-                         GNUNET_GNSRECORD_TYPE_ABE_KEY,
-                         GNUNET_GNS_LO_DEFAULT,
-                         &process_consume_abe_key,
-                         ch);
-  GNUNET_CONTAINER_DLL_insert (idp->consume_op_head,
-                               idp->consume_op_tail,
-                               ch);
-  GNUNET_free (rnd_label);
-  GNUNET_SERVICE_client_continue (idp->client);
+  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];
+  if (GNUNET_OK != GNUNET_GNSRECORD_records_deserialize (le->data_size,
+                                        le->data,
+                                        le->rd_count,
+                                        rd))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Unable to deserialize record data!\n");
+    send_delete_response (adh, GNUNET_SYSERR);
+    cleanup_adh (adh);
+    return;
+  }
+  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);
 }
 
+
 /**
- * Cleanup attribute store handle
+ * Done collecting affected tickets, start updating.
  *
- * @param handle handle to clean up
+ * @param cls our attribute deletion handle
  */
 static void
-cleanup_as_handle (struct AttributeStoreHandle *handle)
+ticket_iter_fin (void *cls)
 {
-  if (NULL != handle->ns_qe)
-    GNUNET_NAMESTORE_cancel (handle->ns_qe);
-  if (NULL != handle->claim)
-    GNUNET_free (handle->claim);
-  if (NULL != handle->abe_key)
-    GNUNET_ABE_cpabe_delete_master_key (handle->abe_key);
-  GNUNET_free (handle);
+  struct AttributeDeleteHandle *adh = cls;
+  adh->ns_it = NULL;
+  GNUNET_SCHEDULER_add_now (&update_tickets, adh);
 }
 
+
+/**
+ * Error collecting affected tickets. Abort.
+ *
+ * @param cls our attribute deletion handle
+ */
 static void
-attr_store_cont (void *cls,
-                 int32_t success,
-                 const char *emsg)
+ticket_iter_err (void *cls)
 {
-  struct AttributeStoreHandle *as_handle = cls;
-  struct GNUNET_MQ_Envelope *env;
-  struct AttributeStoreResultMessage *acr_msg;
-
-  as_handle->ns_qe = NULL;
-  GNUNET_CONTAINER_DLL_remove (as_handle->client->store_op_head,
-                               as_handle->client->store_op_tail,
-                               as_handle);
+  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);
+}
 
-  if (GNUNET_SYSERR == success)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Failed to store attribute %s\n",
-                emsg);
-    cleanup_as_handle (as_handle);
-    GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
-    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);
-  acr_msg->id = htonl (as_handle->r_id);
-  acr_msg->op_result = htonl (GNUNET_OK);
-  GNUNET_MQ_send (as_handle->client->mq,
-                  env);
-  cleanup_as_handle (as_handle);
+/**
+ * Start processing tickets which may still contain reference to deleted
+ * attribute.
+ *
+ * @param cls attribute deletion handle
+ */
+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);
 }
 
+
+/**
+ * Attribute deleted callback
+ *
+ * @param cls our handle
+ * @param success success status
+ * @param emsg error message (NULL if success=GNUNET_OK)
+ */
 static void
-attr_store_task (void *cls)
+attr_delete_cont (void *cls, int32_t success, const char *emsg)
 {
-  struct AttributeStoreHandle *as_handle = cls;
-  struct GNUNET_GNSRECORD_Data rd[1];
-  char* buf;
-  char* policy;
-  char* enc_buf;
-  char* rd_buf;
-  size_t enc_size;
-  size_t buf_size;
-  uint32_t attr_ver;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Storing attribute\n");
-  buf_size = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (as_handle->claim);
-  buf = GNUNET_malloc (buf_size);
-
-  GNUNET_RECLAIM_ATTRIBUTE_serialize (as_handle->claim,
-                                       buf);
-
-  GNUNET_asprintf (&policy,
-                   "%s_%lu",
-                   as_handle->claim->name,
-                   as_handle->claim->version);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Encrypting with policy %s\n", policy);
-  /**
-   * Encrypt the attribute value and store in namestore
-   */
-  enc_size = GNUNET_ABE_cpabe_encrypt (buf,
-                                       buf_size,
-                                       policy, //Policy
-                                       as_handle->abe_key,
-                                       (void**)&enc_buf);
-  if (GNUNET_SYSERR == enc_size)
-  {
+  struct AttributeDeleteHandle *adh = cls;
+  adh->ns_qe = NULL;
+  if (GNUNET_SYSERR == success) {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Failed to encrypt with policy %s\n",
-                policy);
-    GNUNET_CONTAINER_DLL_remove (as_handle->client->store_op_head,
-                                 as_handle->client->store_op_tail,
-                                 as_handle);
-
-    cleanup_as_handle (as_handle);
-    GNUNET_free (buf);
-    GNUNET_free (policy);
-    GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
+                "Error deleting attribute %s\n",
+                adh->label);
+    send_delete_response (adh, GNUNET_SYSERR);
+    cleanup_adh (adh);
     return;
   }
-  GNUNET_free (buf);
-  GNUNET_free (policy);
-  rd[0].data_size = enc_size + sizeof (uint32_t);
-  rd_buf = GNUNET_malloc (rd[0].data_size);
-  attr_ver = htonl (as_handle->claim->version);
-  GNUNET_memcpy (rd_buf,
-                 &attr_ver,
-                 sizeof (uint32_t));
-  GNUNET_memcpy (rd_buf+sizeof (uint32_t),
-                 enc_buf,
-                 enc_size);
-  rd[0].data = rd_buf;
-  rd[0].record_type = GNUNET_GNSRECORD_TYPE_ID_ATTR;
-  rd[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
-  rd[0].expiration_time = as_handle->exp.rel_value_us;
-  as_handle->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
-                                                     &as_handle->identity,
-                                                     as_handle->claim->name,
-                                                     1,
-                                                     rd,
-                                                     &attr_store_cont,
-                                                     as_handle);
-  GNUNET_free (enc_buf);
-  GNUNET_free (rd_buf);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating tickets...\n");
+  GNUNET_SCHEDULER_add_now (&start_ticket_update, adh);
 }
 
 
-static void
-store_after_abe_bootstrap (void *cls,
-                           struct GNUNET_ABE_AbeMasterKey *abe_key)
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Finished ABE bootstrap\n");
-  struct AttributeStoreHandle *ash = cls;
-  ash->abe_key = abe_key;
-  GNUNET_SCHEDULER_add_now (&attr_store_task, ash);
-}
-
+/**
+ * Check attribute delete message format
+ *
+ * @cls unused
+ * @dam message to check
+ */
 static int
-check_attribute_store_message(void *cls,
-                              const struct AttributeStoreMessage *sam)
+check_attribute_delete_message (void *cls,
+                                const struct AttributeDeleteMessage *dam)
 {
   uint16_t size;
 
-  size = ntohs (sam->header.size);
-  if (size <= sizeof (struct AttributeStoreMessage))
-  {
+  size = ntohs (dam->header.size);
+  if (size <= sizeof (struct AttributeDeleteMessage)) {
     GNUNET_break (0);
     return GNUNET_SYSERR;
   }
@@ -2098,58 +1249,53 @@ check_attribute_store_message(void *cls,
 }
 
 
+/**
+ * Handle attribute deletion
+ *
+ * @param cls our client
+ * @param dam deletion message
+ */
 static void
-handle_attribute_store_message (void *cls,
-                                const struct AttributeStoreMessage *sam)
+handle_attribute_delete_message (void *cls,
+                                 const struct AttributeDeleteMessage *dam)
 {
-  struct AttributeStoreHandle *as_handle;
+  struct AttributeDeleteHandle *adh;
   struct IdpClient *idp = cls;
   size_t data_len;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Received ATTRIBUTE_STORE message\n");
-
-  data_len = ntohs (sam->attr_len);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ATTRIBUTE_DELETE message\n");
 
-  as_handle = GNUNET_new (struct AttributeStoreHandle);
-  as_handle->claim = GNUNET_RECLAIM_ATTRIBUTE_deserialize ((char*)&sam[1],
-                                                            data_len);
+  data_len = ntohs (dam->attr_len);
 
-  as_handle->r_id = ntohl (sam->id);
-  as_handle->identity = sam->identity;
-  as_handle->exp.rel_value_us = GNUNET_ntohll (sam->exp);
-  GNUNET_CRYPTO_ecdsa_key_get_public (&sam->identity,
-                                      &as_handle->identity_pkey);
+  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);
-  as_handle->client = idp;
-  GNUNET_CONTAINER_DLL_insert (idp->store_op_head,
-                               idp->store_op_tail,
-                               as_handle);
-  bootstrap_abe (&as_handle->identity, &store_after_abe_bootstrap, as_handle, GNUNET_NO);
+  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);
 }
 
-static void
-cleanup_attribute_iter_handle (struct AttributeIterator *ai)
-{
-  if (NULL != ai->abe_key)
-    GNUNET_ABE_cpabe_delete_master_key (ai->abe_key);
-  GNUNET_free (ai);
-}
 
-static void
-attr_iter_error (void *cls)
-{
-  struct AttributeIterator *ai = cls;
-  //TODO
-  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-              "Failed to iterate over attributes\n");
-  GNUNET_CONTAINER_DLL_remove (ai->client->attr_iter_head,
-                               ai->client->attr_iter_tail,
-                               ai);
-  cleanup_attribute_iter_handle (ai);
-  GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
-}
+/*************************************************
+ * Attrubute iteration
+ *************************************************/
 
+
+/**
+ * Done iterating over attributes
+ *
+ * @param cls our iterator handle
+ */
 static void
 attr_iter_finished (void *cls)
 {
@@ -2157,17 +1303,41 @@ attr_iter_finished (void *cls)
   struct GNUNET_MQ_Envelope *env;
   struct AttributeResultMessage *arm;
 
-  env = GNUNET_MQ_msg (arm,
-                       GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending ATTRIBUTE_RESULT message\n");
+  env = GNUNET_MQ_msg (arm, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT);
   arm->id = htonl (ai->request_id);
   arm->attr_len = htons (0);
   GNUNET_MQ_send (ai->client->mq, env);
   GNUNET_CONTAINER_DLL_remove (ai->client->attr_iter_head,
                                ai->client->attr_iter_tail,
                                ai);
-  cleanup_attribute_iter_handle (ai);
+  GNUNET_free (ai);
+}
+
+/**
+ * Error iterating over attributes. Abort.
+ *
+ * @param cls our attribute iteration handle
+ */
+static void
+attr_iter_error (void *cls)
+{
+  struct AttributeIterator *ai = cls;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to iterate over attributes\n");
+  attr_iter_finished (ai);
 }
 
+
+/**
+ * Got record. Return if it is an attribute.
+ *
+ * @param cls our attribute iterator
+ * @param zone zone we are iterating
+ * @param label label of the records
+ * @param rd_count record count
+ * @param rd records
+ */
 static void
 attr_iter_cb (void *cls,
               const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
@@ -2177,98 +1347,38 @@ attr_iter_cb (void *cls,
 {
   struct AttributeIterator *ai = cls;
   struct AttributeResultMessage *arm;
-  struct GNUNET_ABE_AbeKey *key;
   struct GNUNET_MQ_Envelope *env;
-  ssize_t msg_extra_len;
-  char* attr_ser;
-  char* attrs[2];
-  char* data_tmp;
-  char* policy;
-  uint32_t attr_ver;
-
-  if (rd_count != 1)
-  {
-    GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it,
-                                         1);
-    return;
-  }
+  char *data_tmp;
 
-  if (GNUNET_GNSRECORD_TYPE_ID_ATTR != rd->record_type)
-  {
-    GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it,
-                                         1);
+  if (rd_count != 1) {
+    GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1);
     return;
   }
-  attr_ver = ntohl(*((uint32_t*)rd->data));
-  GNUNET_asprintf (&policy, "%s_%lu",
-                   label, attr_ver);
-  attrs[0] = policy;
-  attrs[1] = 0;
-  key = GNUNET_ABE_cpabe_create_key (ai->abe_key,
-                                     attrs);
-  msg_extra_len = GNUNET_ABE_cpabe_decrypt (rd->data+sizeof (uint32_t),
-                                            rd->data_size-sizeof (uint32_t),
-                                            key,
-                                            (void**)&attr_ser);
-  if (GNUNET_SYSERR == msg_extra_len)
-  {
-    GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it,
-                                         1);
+
+  if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR != rd->record_type) {
+    GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1);
     return;
   }
-
-  GNUNET_ABE_cpabe_delete_key (key,
-                               GNUNET_YES);
-  //GNUNET_free (policy);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Found attribute: %s\n", label);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found attribute under: %s\n", label);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending ATTRIBUTE_RESULT message\n");
   env = GNUNET_MQ_msg_extra (arm,
-                             msg_extra_len,
+                             rd->data_size,
                              GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT);
   arm->id = htonl (ai->request_id);
-  arm->attr_len = htons (msg_extra_len);
-  GNUNET_CRYPTO_ecdsa_key_get_public (zone,
-                                      &arm->identity);
-  data_tmp = (char *) &arm[1];
-  GNUNET_memcpy (data_tmp,
-                 attr_ser,
-                 msg_extra_len);
+  arm->attr_len = htons (rd->data_size);
+  GNUNET_CRYPTO_ecdsa_key_get_public (zone, &arm->identity);
+  data_tmp = (char *)&arm[1];
+  GNUNET_memcpy (data_tmp, rd->data, rd->data_size);
   GNUNET_MQ_send (ai->client->mq, env);
-  GNUNET_free (attr_ser);
-  GNUNET_ABE_cpabe_delete_master_key (ai->abe_key);
-  ai->abe_key = NULL;
-}
-
-
-void
-iterate_after_abe_bootstrap (void *cls,
-                             struct GNUNET_ABE_AbeMasterKey *abe_key)
-{
-  struct AttributeIterator *ai = cls;
-  ai->abe_key = abe_key;
-  ai->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
-                                                     &ai->identity,
-                                                     &attr_iter_error,
-                                                     ai,
-                                                     &attr_iter_cb,
-                                                     ai,
-                                                     &attr_iter_finished,
-                                                     ai);
-}
-
-
-static void
-iterate_next_after_abe_bootstrap (void *cls,
-                                  struct GNUNET_ABE_AbeMasterKey *abe_key)
-{
-  struct AttributeIterator *ai = cls;
-  ai->abe_key = abe_key;
-  GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it,
-                                       1);
 }
 
 
-
+/**
+ * Iterate over zone to get attributes
+ *
+ * @param cls our client
+ * @param ais_msg the iteration message to start
+ */
 static void
 handle_iteration_start (void *cls,
                         const struct AttributeIterationStartMessage *ais_msg)
@@ -2283,14 +1393,25 @@ handle_iteration_start (void *cls,
   ai->client = idp;
   ai->identity = ais_msg->identity;
 
-  GNUNET_CONTAINER_DLL_insert (idp->attr_iter_head,
-                               idp->attr_iter_tail,
-                               ai);
-  bootstrap_abe (&ai->identity, &iterate_after_abe_bootstrap, ai, GNUNET_NO);
+  GNUNET_CONTAINER_DLL_insert (idp->attr_iter_head, idp->attr_iter_tail, ai);
+  ai->ns_it = GNUNET_NAMESTORE_zone_iteration_start (nsh,
+                                                     &ai->identity,
+                                                     &attr_iter_error,
+                                                     ai,
+                                                     &attr_iter_cb,
+                                                     ai,
+                                                     &attr_iter_finished,
+                                                     ai);
   GNUNET_SERVICE_client_continue (idp->client);
 }
 
 
+/**
+ * Handle iteration stop message from client
+ *
+ * @param cls the client
+ * @param ais_msg the stop message
+ */
 static void
 handle_iteration_stop (void *cls,
                        const struct AttributeIterationStopMessage *ais_msg)
@@ -2306,20 +1427,23 @@ handle_iteration_stop (void *cls,
   for (ai = idp->attr_iter_head; NULL != ai; ai = ai->next)
     if (ai->request_id == rid)
       break;
-  if (NULL == ai)
-  {
+  if (NULL == ai) {
     GNUNET_break (0);
     GNUNET_SERVICE_client_drop (idp->client);
     return;
   }
-  GNUNET_CONTAINER_DLL_remove (idp->attr_iter_head,
-                               idp->attr_iter_tail,
-                               ai);
+  GNUNET_CONTAINER_DLL_remove (idp->attr_iter_head, idp->attr_iter_tail, ai);
   GNUNET_free (ai);
   GNUNET_SERVICE_client_continue (idp->client);
 }
 
 
+/**
+ * Client requests next attribute from iterator
+ *
+ * @param cls the client
+ * @param ais_msg the message
+ */
 static void
 handle_iteration_next (void *cls,
                        const struct AttributeIterationNextMessage *ais_msg)
@@ -2334,151 +1458,58 @@ handle_iteration_next (void *cls,
   for (ai = idp->attr_iter_head; NULL != ai; ai = ai->next)
     if (ai->request_id == rid)
       break;
-  if (NULL == ai)
-  {
+  if (NULL == ai) {
     GNUNET_break (0);
     GNUNET_SERVICE_client_drop (idp->client);
     return;
   }
-  bootstrap_abe (&ai->identity,
-                 &iterate_next_after_abe_bootstrap,
-                 ai,
-                 GNUNET_NO);
+  GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1);
   GNUNET_SERVICE_client_continue (idp->client);
 }
 
-/**
- * Ticket iteration processor result
- */
-enum ZoneIterationResult
-{
-  /**
-   * Iteration start.
-   */
-  IT_START = 0,
-
-  /**
-   * Found tickets,
-   * Continue to iterate with next iteration_next call
-   */
-  IT_SUCCESS_MORE_AVAILABLE = 1,
-
-  /**
-   * Iteration complete
-   */
-  IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE = 2
-};
-
-
-/**
- * Context for ticket iteration
- */
-struct TicketIterationProcResult
-{
-  /**
-   * The ticket iteration handle
-   */
-  struct TicketIteration *ti;
-
-  /**
-   * Iteration result: iteration done?
-   * #IT_SUCCESS_MORE_AVAILABLE:  if there may be more results overall but
-   * we got one for now and have sent it to the client
-   * #IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE: if there are no further results,
-   * #IT_START: if we are still trying to find a result.
-   */
-  int res_iteration_finished;
-
-};
-
-static void
-cleanup_ticket_iter_handle (struct TicketIteration *ti)
-{
-  GNUNET_free (ti);
-}
+/******************************************************
+ * Ticket iteration
+ ******************************************************/
 
 /**
- * Process ticket from database
+ * Got a ticket. Return to client
  *
- * @param cls struct TicketIterationProcResult
+ * @param cls our ticket iterator
  * @param ticket the ticket
- * @param attrs the attributes
- */
-static void
-ticket_iterate_proc (void *cls,
-                     const struct GNUNET_RECLAIM_Ticket *ticket,
-                     const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs)
-{
-  struct TicketIterationProcResult *proc = cls;
-
-  if (NULL == ticket)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Iteration done\n");
-    proc->res_iteration_finished = IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE;
-    return;
-  }
-  proc->res_iteration_finished = IT_SUCCESS_MORE_AVAILABLE;
-  send_ticket_result (proc->ti->client,
-                      proc->ti->r_id,
-                      ticket,
-                      attrs);
-
-}
-
-/**
- * Perform ticket iteration step
- *
- * @param ti ticket iterator to process
  */
 static void
-run_ticket_iteration_round (struct TicketIteration *ti)
+ticket_iter_cb (void *cls, struct GNUNET_RECLAIM_Ticket *ticket)
 {
-  struct TicketIterationProcResult proc;
+  struct TicketIteration *ti = cls;
   struct GNUNET_MQ_Envelope *env;
   struct TicketResultMessage *trm;
-  int ret;
 
-  memset (&proc, 0, sizeof (proc));
-  proc.ti = ti;
-  proc.res_iteration_finished = IT_START;
-  while (IT_START == proc.res_iteration_finished)
-  {
-    if (GNUNET_SYSERR ==
-        (ret = TKT_database->iterate_tickets (TKT_database->cls,
-                                              &ti->identity,
-                                              ti->is_audience,
-                                              ti->offset,
-                                              &ticket_iterate_proc,
-                                              &proc)))
-    {
-      GNUNET_break (0);
-      break;
-    }
-    if (GNUNET_NO == ret)
-      proc.res_iteration_finished = IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE;
-    ti->offset++;
-  }
-  if (IT_SUCCESS_MORE_AVAILABLE == proc.res_iteration_finished)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "More results available\n");
-    return; /* more later */
+  env = GNUNET_MQ_msg (trm, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT);
+  if (NULL == ticket) {
+    /* send empty response to indicate end of list */
+    GNUNET_CONTAINER_DLL_remove (ti->client->ticket_iter_head,
+                                 ti->client->ticket_iter_tail,
+                                 ti);
+  } else {
+    trm->ticket = *ticket;
   }
-  /* send empty response to indicate end of list */
-  env = GNUNET_MQ_msg (trm,
-                       GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT);
   trm->id = htonl (ti->r_id);
-  GNUNET_MQ_send (ti->client->mq,
-                  env);
-  GNUNET_CONTAINER_DLL_remove (ti->client->ticket_iter_head,
-                               ti->client->ticket_iter_tail,
-                               ti);
-  cleanup_ticket_iter_handle (ti);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending TICKET_RESULT message\n");
+  GNUNET_MQ_send (ti->client->mq, env);
+  if (NULL == ticket)
+    GNUNET_free (ti);
 }
 
+
+/**
+ * Client requests a ticket iteration
+ *
+ * @param cls the client
+ * @param tis_msg the iteration request message
+ */
 static void
-handle_ticket_iteration_start (void *cls,
+handle_ticket_iteration_start (
+                               void *cls,
                                const struct TicketIterationStartMessage *tis_msg)
 {
   struct IdpClient *client = cls;
@@ -2488,19 +1519,23 @@ handle_ticket_iteration_start (void *cls,
               "Received TICKET_ITERATION_START message\n");
   ti = GNUNET_new (struct TicketIteration);
   ti->r_id = ntohl (tis_msg->id);
-  ti->offset = 0;
   ti->client = client;
-  ti->identity = tis_msg->identity;
-  ti->is_audience = ntohl (tis_msg->is_audience);
 
   GNUNET_CONTAINER_DLL_insert (client->ticket_iter_head,
                                client->ticket_iter_tail,
                                ti);
-  run_ticket_iteration_round (ti);
+  ti->iter
+    = RECLAIM_TICKETS_iteration_start (&tis_msg->identity, &ticket_iter_cb, ti);
   GNUNET_SERVICE_client_continue (client->client);
 }
 
 
+/**
+ * Client has had enough tickets
+ *
+ * @param cls the client
+ * @param tis_msg the stop message
+ */
 static void
 handle_ticket_iteration_stop (void *cls,
                               const struct TicketIterationStopMessage *tis_msg)
@@ -2516,20 +1551,26 @@ handle_ticket_iteration_stop (void *cls,
   for (ti = client->ticket_iter_head; NULL != ti; ti = ti->next)
     if (ti->r_id == rid)
       break;
-  if (NULL == ti)
-  {
+  if (NULL == ti) {
     GNUNET_break (0);
     GNUNET_SERVICE_client_drop (client->client);
     return;
   }
+  RECLAIM_TICKETS_iteration_stop (ti->iter);
   GNUNET_CONTAINER_DLL_remove (client->ticket_iter_head,
                                client->ticket_iter_tail,
                                ti);
-  cleanup_ticket_iter_handle (ti);
+  GNUNET_free (ti);
   GNUNET_SERVICE_client_continue (client->client);
 }
 
 
+/**
+ * Client requests next result.
+ *
+ * @param cls the client
+ * @param tis_msg the message
+ */
 static void
 handle_ticket_iteration_next (void *cls,
                               const struct TicketIterationNextMessage *tis_msg)
@@ -2544,24 +1585,21 @@ handle_ticket_iteration_next (void *cls,
   for (ti = client->ticket_iter_head; NULL != ti; ti = ti->next)
     if (ti->r_id == rid)
       break;
-  if (NULL == ti)
-  {
+  if (NULL == ti) {
     GNUNET_break (0);
     GNUNET_SERVICE_client_drop (client->client);
     return;
   }
-  run_ticket_iteration_round (ti);
+  RECLAIM_TICKETS_iteration_next (ti->iter);
   GNUNET_SERVICE_client_continue (client->client);
 }
 
 
-
-
 /**
  * Main function that will be run
  *
  * @param cls closure
- * @param c the configuration used 
+ * @param c the configuration used
  * @param server the service handle
  */
 static void
@@ -2569,71 +1607,25 @@ run (void *cls,
      const struct GNUNET_CONFIGURATION_Handle *c,
      struct GNUNET_SERVICE_Handle *server)
 {
-  char *database;
   cfg = c;
 
-  stats = GNUNET_STATISTICS_create ("reclaim", cfg);
-
-  //Connect to identity and namestore services
-  ns_handle = GNUNET_NAMESTORE_connect (cfg);
-  if (NULL == ns_handle)
-  {
-    GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to namestore");
-  }
-
-  gns_handle = GNUNET_GNS_connect (cfg);
-  if (NULL == gns_handle)
-  {
-    GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to gns");
-  }
-  credential_handle = GNUNET_CREDENTIAL_connect (cfg);
-  if (NULL == credential_handle)
-  {
-    GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to credential");
-  }
-  identity_handle = GNUNET_IDENTITY_connect (cfg,
-                                             NULL,
-                                             NULL);
-  /* Loading DB plugin */
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_string (cfg,
-                                             "reclaim",
-                                             "database",
-                                             &database))
+  if (GNUNET_OK != RECLAIM_TICKETS_init (cfg)) {
     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);
+                "Unable to initialize TICKETS subsystem.\n");
     GNUNET_SCHEDULER_shutdown ();
     return;
   }
-
-  if (GNUNET_OK ==
-      GNUNET_CONFIGURATION_get_value_time (cfg,
-                                           "reclaim",
-                                           "TOKEN_EXPIRATION_INTERVAL",
-                                           &token_expiration_interval))
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Time window for zone iteration: %s\n",
-                GNUNET_STRINGS_relative_time_to_string (token_expiration_interval,
-                                                        GNUNET_YES));
-  } else {
-    token_expiration_interval = DEFAULT_TOKEN_EXPIRATION_INTERVAL;
+  // Connect to identity and namestore services
+  nsh = GNUNET_NAMESTORE_connect (cfg);
+  if (NULL == nsh) {
+    GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
+                         "error connecting to namestore");
   }
 
   GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
 }
 
+
 /**
  * Called whenever a client is disconnected.
  *
@@ -2647,63 +1639,11 @@ client_disconnect_cb (void *cls,
                       void *app_ctx)
 {
   struct IdpClient *idp = app_ctx;
-  struct AttributeIterator *ai;
-  struct TicketIteration *ti;
-  struct TicketRevocationHandle *rh;
-  struct TicketIssueHandle *iss;
-  struct ConsumeTicketHandle *ct;
-  struct AttributeStoreHandle *as;
-
-  //TODO other operations
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Client %p disconnected\n",
-              client);
-
-  while (NULL != (iss = idp->issue_op_head))
-  {
-    GNUNET_CONTAINER_DLL_remove (idp->issue_op_head,
-                                 idp->issue_op_tail,
-                                 iss);
-    cleanup_ticket_issue_handle (iss);
-  }
-  while (NULL != (ct = idp->consume_op_head))
-  {
-    GNUNET_CONTAINER_DLL_remove (idp->consume_op_head,
-                                 idp->consume_op_tail,
-                                 ct);
-    cleanup_consume_ticket_handle (ct);
-  }
-  while (NULL != (as = idp->store_op_head))
-  {
-    GNUNET_CONTAINER_DLL_remove (idp->store_op_head,
-                                 idp->store_op_tail,
-                                 as);
-    cleanup_as_handle (as);
-  }
-
-  while (NULL != (ai = idp->attr_iter_head))
-  {
-    GNUNET_CONTAINER_DLL_remove (idp->attr_iter_head,
-                                 idp->attr_iter_tail,
-                                 ai);
-    cleanup_attribute_iter_handle (ai);
-  }
-  while (NULL != (rh = idp->revoke_op_head))
-  {
-    GNUNET_CONTAINER_DLL_remove (idp->revoke_op_head,
-                                 idp->revoke_op_tail,
-                                 rh);
-    cleanup_revoke_ticket_handle (rh);
-  }
-  while (NULL != (ti = idp->ticket_iter_head))
-  {
-    GNUNET_CONTAINER_DLL_remove (idp->ticket_iter_head,
-                                 idp->ticket_iter_tail,
-                                 ti);
-    cleanup_ticket_iter_handle (ti);
-  }
-  GNUNET_free (idp);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p disconnected\n", client);
+  GNUNET_CONTAINER_DLL_remove (client_list_head,
+                               client_list_tail,
+                               idp);
+  cleanup_client (idp);
 }
 
 
@@ -2721,66 +1661,71 @@ client_connect_cb (void *cls,
                    struct GNUNET_MQ_Handle *mq)
 {
   struct IdpClient *idp;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Client %p connected\n",
-              client);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", client);
   idp = GNUNET_new (struct IdpClient);
   idp->client = client;
   idp->mq = mq;
+  GNUNET_CONTAINER_DLL_insert (client_list_head,
+                               client_list_tail,
+                               idp);
   return idp;
 }
 
 
-
 /**
  * Define "main" method using service macro.
  */
-GNUNET_SERVICE_MAIN
-("reclaim",
- GNUNET_SERVICE_OPTION_NONE,
- &run,
- &client_connect_cb,
- &client_disconnect_cb,
- NULL,
- GNUNET_MQ_hd_var_size (attribute_store_message,
-                        GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE,
-                        struct AttributeStoreMessage,
-                        NULL),
- GNUNET_MQ_hd_fixed_size (iteration_start, 
-                          GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_START,
-                          struct AttributeIterationStartMessage,
-                          NULL),
- GNUNET_MQ_hd_fixed_size (iteration_next, 
-                          GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_NEXT,
-                          struct AttributeIterationNextMessage,
-                          NULL),
- GNUNET_MQ_hd_fixed_size (iteration_stop, 
-                          GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_STOP,
-                          struct AttributeIterationStopMessage,
-                          NULL),
- GNUNET_MQ_hd_var_size (issue_ticket_message,
-                        GNUNET_MESSAGE_TYPE_RECLAIM_ISSUE_TICKET,
-                        struct IssueTicketMessage,
-                        NULL),
- GNUNET_MQ_hd_var_size (consume_ticket_message,
-                        GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET,
-                        struct ConsumeTicketMessage,
-                        NULL),
- GNUNET_MQ_hd_fixed_size (ticket_iteration_start, 
-                          GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_START,
-                          struct TicketIterationStartMessage,
-                          NULL),
- GNUNET_MQ_hd_fixed_size (ticket_iteration_next, 
-                          GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_NEXT,
-                          struct TicketIterationNextMessage,
-                          NULL),
- GNUNET_MQ_hd_fixed_size (ticket_iteration_stop, 
-                          GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_STOP,
-                          struct TicketIterationStopMessage,
-                          NULL),
- GNUNET_MQ_hd_var_size (revoke_ticket_message,
-                        GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET,
-                        struct RevokeTicketMessage,
-                        NULL),
- GNUNET_MQ_handler_end());
+GNUNET_SERVICE_MAIN (
+                     "reclaim",
+                     GNUNET_SERVICE_OPTION_NONE,
+                     &run,
+                     &client_connect_cb,
+                     &client_disconnect_cb,
+                     NULL,
+                     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),
+                     GNUNET_MQ_hd_fixed_size (iteration_next,
+                                              GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_NEXT,
+                                              struct AttributeIterationNextMessage,
+                                              NULL),
+                     GNUNET_MQ_hd_fixed_size (iteration_stop,
+                                              GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_STOP,
+                                              struct AttributeIterationStopMessage,
+                                              NULL),
+                     GNUNET_MQ_hd_var_size (issue_ticket_message,
+                                            GNUNET_MESSAGE_TYPE_RECLAIM_ISSUE_TICKET,
+                                            struct IssueTicketMessage,
+                                            NULL),
+                     GNUNET_MQ_hd_var_size (consume_ticket_message,
+                                            GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET,
+                                            struct ConsumeTicketMessage,
+                                            NULL),
+                     GNUNET_MQ_hd_fixed_size (ticket_iteration_start,
+                                              GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_START,
+                                              struct TicketIterationStartMessage,
+                                              NULL),
+                     GNUNET_MQ_hd_fixed_size (ticket_iteration_next,
+                                              GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_NEXT,
+                                              struct TicketIterationNextMessage,
+                                              NULL),
+                     GNUNET_MQ_hd_fixed_size (ticket_iteration_stop,
+                                              GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_STOP,
+                                              struct TicketIterationStopMessage,
+                                              NULL),
+                     GNUNET_MQ_hd_var_size (revoke_ticket_message,
+                                            GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET,
+                                            struct RevokeTicketMessage,
+                                            NULL),
+                     GNUNET_MQ_handler_end ());
 /* end of gnunet-service-reclaim.c */