use NULL value in load_path_suffix to NOT load any files
[oweals/gnunet.git] / src / reclaim / reclaim_api.c
1 /*
2    This file is part of GNUnet.
3    Copyright (C) 2016 GNUnet e.V.
4
5    GNUnet is free software: you can redistribute it and/or modify it
6    under the terms of the GNU Affero General Public License as published
7    by the Free Software Foundation, either version 3 of the License,
8    or (at your option) any later version.
9
10    GNUnet is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Affero General Public License for more details.
14
15    You should have received a copy of the GNU Affero General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18    SPDX-License-Identifier: AGPL3.0-or-later
19  */
20
21 /**
22  * @file reclaim/reclaim_api.c
23  * @brief api to interact with the reclaim service
24  * @author Martin Schanzenbach
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_constants.h"
29 #include "gnunet_mq_lib.h"
30 #include "gnunet_protocols.h"
31 #include "gnunet_reclaim_attribute_lib.h"
32 #include "gnunet_reclaim_service.h"
33 #include "reclaim.h"
34
35 #define LOG(kind, ...) GNUNET_log_from (kind, "reclaim-api", __VA_ARGS__)
36
37
38 /**
39  * Handle for an operation with the service.
40  */
41 struct GNUNET_RECLAIM_Operation
42 {
43   /**
44    * Main handle.
45    */
46   struct GNUNET_RECLAIM_Handle *h;
47
48   /**
49    * We keep operations in a DLL.
50    */
51   struct GNUNET_RECLAIM_Operation *next;
52
53   /**
54    * We keep operations in a DLL.
55    */
56   struct GNUNET_RECLAIM_Operation *prev;
57
58   /**
59    * Message to send to the service.
60    * Allocated at the end of this struct.
61    */
62   const struct GNUNET_MessageHeader *msg;
63
64   /**
65    * Continuation to invoke after attribute store call
66    */
67   GNUNET_RECLAIM_ContinuationWithStatus as_cb;
68
69   /**
70    * Attribute result callback
71    */
72   GNUNET_RECLAIM_AttributeResult ar_cb;
73
74   /**
75    * Revocation result callback
76    */
77   GNUNET_RECLAIM_ContinuationWithStatus rvk_cb;
78
79   /**
80    * Ticket result callback
81    */
82   GNUNET_RECLAIM_TicketCallback tr_cb;
83
84   /**
85    * Envelope with the message for this queue entry.
86    */
87   struct GNUNET_MQ_Envelope *env;
88
89   /**
90    * request id
91    */
92   uint32_t r_id;
93
94   /**
95    * Closure for @e cont or @e cb.
96    */
97   void *cls;
98 };
99
100
101 /**
102  * Handle for a ticket iterator operation
103  */
104 struct GNUNET_RECLAIM_TicketIterator
105 {
106   /**
107    * Kept in a DLL.
108    */
109   struct GNUNET_RECLAIM_TicketIterator *next;
110
111   /**
112    * Kept in a DLL.
113    */
114   struct GNUNET_RECLAIM_TicketIterator *prev;
115
116   /**
117    * Main handle to access the idp.
118    */
119   struct GNUNET_RECLAIM_Handle *h;
120
121   /**
122    * Function to call on completion.
123    */
124   GNUNET_SCHEDULER_TaskCallback finish_cb;
125
126   /**
127    * Closure for @e finish_cb.
128    */
129   void *finish_cb_cls;
130
131   /**
132    * The continuation to call with the results
133    */
134   GNUNET_RECLAIM_TicketCallback tr_cb;
135
136   /**
137    * Closure for @e tr_cb.
138    */
139   void *cls;
140
141   /**
142    * Function to call on errors.
143    */
144   GNUNET_SCHEDULER_TaskCallback error_cb;
145
146   /**
147    * Closure for @e error_cb.
148    */
149   void *error_cb_cls;
150
151   /**
152    * Envelope of the message to send to the service, if not yet
153    * sent.
154    */
155   struct GNUNET_MQ_Envelope *env;
156
157   /**
158    * The operation id this zone iteration operation has
159    */
160   uint32_t r_id;
161 };
162
163
164 /**
165  * Handle for a attribute iterator operation
166  */
167 struct GNUNET_RECLAIM_AttributeIterator
168 {
169   /**
170    * Kept in a DLL.
171    */
172   struct GNUNET_RECLAIM_AttributeIterator *next;
173
174   /**
175    * Kept in a DLL.
176    */
177   struct GNUNET_RECLAIM_AttributeIterator *prev;
178
179   /**
180    * Main handle to access the service.
181    */
182   struct GNUNET_RECLAIM_Handle *h;
183
184   /**
185    * Function to call on completion.
186    */
187   GNUNET_SCHEDULER_TaskCallback finish_cb;
188
189   /**
190    * Closure for @e finish_cb.
191    */
192   void *finish_cb_cls;
193
194   /**
195    * The continuation to call with the results
196    */
197   GNUNET_RECLAIM_AttributeResult proc;
198
199   /**
200    * Closure for @e proc.
201    */
202   void *proc_cls;
203
204   /**
205    * Function to call on errors.
206    */
207   GNUNET_SCHEDULER_TaskCallback error_cb;
208
209   /**
210    * Closure for @e error_cb.
211    */
212   void *error_cb_cls;
213
214   /**
215    * Envelope of the message to send to the service, if not yet
216    * sent.
217    */
218   struct GNUNET_MQ_Envelope *env;
219
220   /**
221    * Private key of the zone.
222    */
223   struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
224
225   /**
226    * The operation id this zone iteration operation has
227    */
228   uint32_t r_id;
229 };
230
231
232 /**
233  * Handle to the service.
234  */
235 struct GNUNET_RECLAIM_Handle
236 {
237   /**
238    * Configuration to use.
239    */
240   const struct GNUNET_CONFIGURATION_Handle *cfg;
241
242   /**
243    * Socket (if available).
244    */
245   struct GNUNET_CLIENT_Connection *client;
246
247   /**
248    * Closure for 'cb'.
249    */
250   void *cb_cls;
251
252   /**
253    * Head of active operations.
254    */
255   struct GNUNET_RECLAIM_Operation *op_head;
256
257   /**
258    * Tail of active operations.
259    */
260   struct GNUNET_RECLAIM_Operation *op_tail;
261
262   /**
263    * Head of active iterations
264    */
265   struct GNUNET_RECLAIM_AttributeIterator *it_head;
266
267   /**
268    * Tail of active iterations
269    */
270   struct GNUNET_RECLAIM_AttributeIterator *it_tail;
271
272   /**
273    * Head of active iterations
274    */
275   struct GNUNET_RECLAIM_TicketIterator *ticket_it_head;
276
277   /**
278    * Tail of active iterations
279    */
280   struct GNUNET_RECLAIM_TicketIterator *ticket_it_tail;
281
282   /**
283    * Currently pending transmission request, or NULL for none.
284    */
285   struct GNUNET_CLIENT_TransmitHandle *th;
286
287   /**
288    * Task doing exponential back-off trying to reconnect.
289    */
290   struct GNUNET_SCHEDULER_Task *reconnect_task;
291
292   /**
293    * Time for next connect retry.
294    */
295   struct GNUNET_TIME_Relative reconnect_backoff;
296
297   /**
298    * Connection to service (if available).
299    */
300   struct GNUNET_MQ_Handle *mq;
301
302   /**
303    * Request Id generator.  Incremented by one for each request.
304    */
305   uint32_t r_id_gen;
306
307   /**
308    * Are we polling for incoming messages right now?
309    */
310   int in_receive;
311 };
312
313
314 /**
315  * Try again to connect to the service.
316  *
317  * @param h handle to the reclaim service.
318  */
319 static void
320 reconnect (struct GNUNET_RECLAIM_Handle *h);
321
322
323 /**
324  * Reconnect
325  *
326  * @param cls the handle
327  */
328 static void
329 reconnect_task (void *cls)
330 {
331   struct GNUNET_RECLAIM_Handle *handle = cls;
332
333   handle->reconnect_task = NULL;
334   reconnect (handle);
335 }
336
337
338 /**
339  * Disconnect from service and then reconnect.
340  *
341  * @param handle our service
342  */
343 static void
344 force_reconnect (struct GNUNET_RECLAIM_Handle *handle)
345 {
346   GNUNET_MQ_destroy (handle->mq);
347   handle->mq = NULL;
348   handle->reconnect_backoff =
349     GNUNET_TIME_STD_BACKOFF (handle->reconnect_backoff);
350   handle->reconnect_task =
351     GNUNET_SCHEDULER_add_delayed (handle->reconnect_backoff,
352                                   &reconnect_task,
353                                   handle);
354 }
355
356
357 /**
358  * Free @a it.
359  *
360  * @param it entry to free
361  */
362 static void
363 free_it (struct GNUNET_RECLAIM_AttributeIterator *it)
364 {
365   struct GNUNET_RECLAIM_Handle *h = it->h;
366
367   GNUNET_CONTAINER_DLL_remove (h->it_head, h->it_tail, it);
368   if (NULL != it->env)
369     GNUNET_MQ_discard (it->env);
370   GNUNET_free (it);
371 }
372
373
374 /**
375  * Free @a op
376  *
377  * @param op the operation to free
378  */
379 static void
380 free_op (struct GNUNET_RECLAIM_Operation *op)
381 {
382   if (NULL == op)
383     return;
384   if (NULL != op->env)
385     GNUNET_MQ_discard (op->env);
386   GNUNET_free (op);
387 }
388
389
390 /**
391  * Generic error handler, called with the appropriate error code and
392  * the same closure specified at the creation of the message queue.
393  * Not every message queue implementation supports an error handler.
394  *
395  * @param cls closure with the `struct GNUNET_GNS_Handle *`
396  * @param error error code
397  */
398 static void
399 mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
400 {
401   struct GNUNET_RECLAIM_Handle *handle = cls;
402
403   force_reconnect (handle);
404 }
405
406
407 /**
408  * Handle an incoming message of type
409  * #GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE
410  *
411  * @param cls
412  * @param msg the message we received
413  */
414 static void
415 handle_success_response (void *cls, const struct SuccessResultMessage *msg)
416 {
417   struct GNUNET_RECLAIM_Handle *h = cls;
418   struct GNUNET_RECLAIM_Operation *op;
419   uint32_t r_id = ntohl (msg->id);
420   int res;
421   const char *emsg;
422
423   for (op = h->op_head; NULL != op; op = op->next)
424     if (op->r_id == r_id)
425       break;
426   if (NULL == op)
427     return;
428
429   res = ntohl (msg->op_result);
430   LOG (GNUNET_ERROR_TYPE_DEBUG,
431        "Received SUCCESS_RESPONSE with result %d\n",
432        res);
433
434   /* TODO: add actual error message to response... */
435   if (GNUNET_SYSERR == res)
436     emsg = _ ("failed to store record\n");
437   else
438     emsg = NULL;
439   if (NULL != op->as_cb)
440     op->as_cb (op->cls, res, emsg);
441   GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
442   free_op (op);
443 }
444
445
446 /**
447  * Handle an incoming message of type
448  * #GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT
449  *
450  * @param cls
451  * @param msg the message we received
452  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
453  */
454 static int
455 check_consume_ticket_result (void *cls,
456                              const struct ConsumeTicketResultMessage *msg)
457 {
458   size_t msg_len;
459   size_t attrs_len;
460
461   msg_len = ntohs (msg->header.size);
462   attrs_len = ntohs (msg->attrs_len);
463   if (msg_len != sizeof(struct ConsumeTicketResultMessage) + attrs_len)
464   {
465     GNUNET_break (0);
466     return GNUNET_SYSERR;
467   }
468   return GNUNET_OK;
469 }
470
471
472 /**
473  * Handle an incoming message of type
474  * #GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT
475  *
476  * @param cls
477  * @param msg the message we received
478  */
479 static void
480 handle_consume_ticket_result (void *cls,
481                               const struct ConsumeTicketResultMessage *msg)
482 {
483   struct GNUNET_RECLAIM_Handle *h = cls;
484   struct GNUNET_RECLAIM_Operation *op;
485   size_t attrs_len;
486   uint32_t r_id = ntohl (msg->id);
487
488   attrs_len = ntohs (msg->attrs_len);
489   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing ticket result.\n");
490
491
492   for (op = h->op_head; NULL != op; op = op->next)
493     if (op->r_id == r_id)
494       break;
495   if (NULL == op)
496     return;
497
498   {
499     struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
500     struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
501     struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le2;
502     attrs =
503       GNUNET_RECLAIM_ATTRIBUTE_list_deserialize ((char *) &msg[1], attrs_len);
504     if (NULL != op->ar_cb)
505     {
506       if (NULL == attrs)
507       {
508         op->ar_cb (op->cls, &msg->identity, NULL, NULL, NULL);
509       }
510       else
511       {
512         for (le = attrs->list_head; NULL != le; le = le->next)
513         {
514           if (le->reference != NULL && le->attest == NULL)
515           {
516             for (le2 = attrs->list_head; NULL != le2; le2 = le2->next)
517             {
518               if (le2->attest != NULL && le2->attest->id == le->reference->id_attest)
519               {
520                 op->ar_cb (op->cls, &msg->identity, le->claim, le2->attest, le->reference);
521                 break;
522               }
523
524             }
525           }
526         }
527         GNUNET_RECLAIM_ATTRIBUTE_list_destroy (attrs);
528         attrs = NULL;
529       }
530       op->ar_cb (op->cls, NULL, NULL, NULL, NULL);
531     }
532     GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
533     free_op (op);
534     GNUNET_free_non_null (attrs);
535     return;
536   }
537   GNUNET_assert (0);
538 }
539
540
541 /**
542  * Handle an incoming message of type
543  * #GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT
544  *
545  * @param cls
546  * @param msg the message we received
547  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
548  */
549 static int
550 check_attribute_result (void *cls, const struct AttributeResultMessage *msg)
551 {
552   size_t msg_len;
553   size_t attr_len;
554
555   msg_len = ntohs (msg->header.size);
556   attr_len = ntohs (msg->attr_len);
557   if (msg_len != sizeof(struct AttributeResultMessage) + attr_len)
558   {
559     GNUNET_break (0);
560     return GNUNET_SYSERR;
561   }
562   return GNUNET_OK;
563 }
564
565
566 /**
567  * Handle an incoming message of type
568  * #GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT
569  *
570  * @param cls
571  * @param msg the message we received
572  */
573 static void
574 handle_attribute_result (void *cls, const struct AttributeResultMessage *msg)
575 {
576   static struct GNUNET_CRYPTO_EcdsaPrivateKey identity_dummy;
577   struct GNUNET_RECLAIM_Handle *h = cls;
578   struct GNUNET_RECLAIM_AttributeIterator *it;
579   struct GNUNET_RECLAIM_Operation *op;
580   size_t attr_len;
581   uint32_t r_id = ntohl (msg->id);
582
583   attr_len = ntohs (msg->attr_len);
584   LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing attribute result.\n");
585
586
587   for (it = h->it_head; NULL != it; it = it->next)
588     if (it->r_id == r_id)
589       break;
590   for (op = h->op_head; NULL != op; op = op->next)
591     if (op->r_id == r_id)
592       break;
593   if ((NULL == it) && (NULL == op))
594     return;
595
596   if ((0 ==
597        (memcmp (&msg->identity, &identity_dummy, sizeof(identity_dummy)))))
598   {
599     if ((NULL == it) && (NULL == op))
600     {
601       GNUNET_break (0);
602       force_reconnect (h);
603       return;
604     }
605     if (NULL != it)
606     {
607       if (NULL != it->finish_cb)
608         it->finish_cb (it->finish_cb_cls);
609       free_it (it);
610     }
611     if (NULL != op)
612     {
613       if (NULL != op->ar_cb)
614         op->ar_cb (op->cls, NULL, NULL, NULL, NULL);
615       GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
616       free_op (op);
617     }
618     return;
619   }
620
621   {
622     struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr;
623     attr = GNUNET_RECLAIM_ATTRIBUTE_deserialize ((char *) &msg[1], attr_len);
624     if (NULL != it)
625     {
626       if (NULL != it->proc)
627         it->proc (it->proc_cls, &msg->identity, attr, NULL, NULL);
628     }
629     else if (NULL != op)
630     {
631       if (NULL != op->ar_cb)
632         op->ar_cb (op->cls, &msg->identity, attr, NULL, NULL);
633     }
634     GNUNET_free (attr);
635     return;
636   }
637   GNUNET_assert (0);
638 }
639
640 /**
641    * Handle an incoming message of type
642    * #GNUNET_MESSAGE_TYPE_RECLAIM_ATTESTATION_RESULT
643    *
644    * @param cls
645    * @param msg the message we received
646    * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
647    */
648 static int
649 check_attestation_result (void *cls, const struct AttributeResultMessage *msg)
650 {
651   size_t msg_len;
652   size_t attr_len;
653
654   msg_len = ntohs (msg->header.size);
655   attr_len = ntohs (msg->attr_len);
656   if (msg_len != sizeof(struct AttributeResultMessage) + attr_len)
657   {
658     GNUNET_break (0);
659     return GNUNET_SYSERR;
660   }
661   return GNUNET_OK;
662 }
663
664
665 /**
666  * Handle an incoming message of type
667  * #GNUNET_MESSAGE_TYPE_RECLAIM_ATTESTATION_RESULT
668  *
669  * @param cls
670  * @param msg the message we received
671  */
672 static void
673 handle_attestation_result (void *cls, const struct AttributeResultMessage *msg)
674 {
675   static struct GNUNET_CRYPTO_EcdsaPrivateKey identity_dummy;
676   struct GNUNET_RECLAIM_Handle *h = cls;
677   struct GNUNET_RECLAIM_AttributeIterator *it;
678   struct GNUNET_RECLAIM_Operation *op;
679   size_t attr_len;
680   uint32_t r_id = ntohl (msg->id);
681
682   attr_len = ntohs (msg->attr_len);
683   LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing attestation result.\n");
684
685
686   for (it = h->it_head; NULL != it; it = it->next)
687     if (it->r_id == r_id)
688       break;
689   for (op = h->op_head; NULL != op; op = op->next)
690     if (op->r_id == r_id)
691       break;
692   if ((NULL == it) && (NULL == op))
693     return;
694
695   if ((0 ==
696        (memcmp (&msg->identity, &identity_dummy, sizeof(identity_dummy)))))
697   {
698     if ((NULL == it) && (NULL == op))
699     {
700       GNUNET_break (0);
701       force_reconnect (h);
702       return;
703     }
704     if (NULL != it)
705     {
706       if (NULL != it->finish_cb)
707         it->finish_cb (it->finish_cb_cls);
708       free_it (it);
709     }
710     if (NULL != op)
711     {
712       if (NULL != op->ar_cb)
713         op->ar_cb (op->cls, NULL, NULL, NULL, NULL);
714       GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
715       free_op (op);
716     }
717     return;
718   }
719
720   {
721     struct GNUNET_RECLAIM_ATTESTATION_Claim *attr;
722     attr = GNUNET_RECLAIM_ATTESTATION_deserialize ((char *) &msg[1], attr_len);
723     if (NULL != it)
724     {
725       if (NULL != it->proc)
726         it->proc (it->proc_cls, &msg->identity, NULL, attr, NULL);
727     }
728     else if (NULL != op)
729     {
730       if (NULL != op->ar_cb)
731         op->ar_cb (op->cls, &msg->identity, NULL, attr, NULL);
732     }
733     GNUNET_free (attr);
734     return;
735   }
736   GNUNET_assert (0);
737 }
738
739 /**
740    * Handle an incoming message of type
741    * #GNUNET_MESSAGE_TYPE_RECLAIM_REFERENCE_RESULT
742    *
743    * @param cls
744    * @param msg the message we received
745    * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
746    */
747 static int
748 check_reference_result (void *cls, const struct ReferenceResultMessage *msg)
749 {
750   size_t msg_len;
751   size_t attr_len;
752   size_t ref_len;
753
754   msg_len = ntohs (msg->header.size);
755   attr_len = ntohs (msg->attest_len);
756   ref_len = ntohs (msg->ref_len);
757   if (msg_len != sizeof(struct ReferenceResultMessage) + attr_len + ref_len)
758   {
759     GNUNET_break (0);
760     return GNUNET_SYSERR;
761   }
762   return GNUNET_OK;
763 }
764
765 /**
766 * Handle an incoming message of type
767 * #GNUNET_MESSAGE_TYPE_RECLAIM_REFERENCE_RESULT
768 *
769 * @param cls
770 * @param msg the message we received
771 */
772 static void
773 handle_reference_result (void *cls, const struct ReferenceResultMessage *msg)
774 {
775   static struct GNUNET_CRYPTO_EcdsaPrivateKey identity_dummy;
776   struct GNUNET_RECLAIM_Handle *h = cls;
777   struct GNUNET_RECLAIM_AttributeIterator *it;
778   struct GNUNET_RECLAIM_Operation *op;
779   size_t attest_len;
780   size_t ref_len;
781   uint32_t r_id = ntohl (msg->id);
782   attest_len = ntohs (msg->attest_len);
783   ref_len = ntohs (msg->ref_len);
784   LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing reference result.\n");
785   for (it = h->it_head; NULL != it; it = it->next)
786     if (it->r_id == r_id)
787       break;
788   for (op = h->op_head; NULL != op; op = op->next)
789     if (op->r_id == r_id)
790       break;
791   if ((NULL == it) && (NULL == op))
792     return;
793
794   if ((0 ==
795        (memcmp (&msg->identity, &identity_dummy, sizeof(identity_dummy)))))
796   {
797     if ((NULL == it) && (NULL == op))
798     {
799       GNUNET_break (0);
800       force_reconnect (h);
801       return;
802     }
803     if (NULL != it)
804     {
805       if (NULL != it->finish_cb)
806         it->finish_cb (it->finish_cb_cls);
807       free_it (it);
808     }
809     if (NULL != op)
810     {
811       if (NULL != op->ar_cb)
812         op->ar_cb (op->cls, NULL, NULL, NULL, NULL);
813       GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
814       free_op (op);
815     }
816     return;
817   }
818
819   {
820     struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *ref;
821     struct GNUNET_RECLAIM_ATTESTATION_Claim *attest;
822     attest = GNUNET_RECLAIM_ATTESTATION_deserialize ((char *) &msg[1],
823                                                      attest_len);
824     ref = GNUNET_RECLAIM_ATTESTATION_REF_deserialize ((char *) &msg[1]
825                                                       + attest_len,
826                                                       ref_len);
827     if (NULL != it)
828     {
829       if (NULL != it->proc)
830         it->proc (it->proc_cls, &msg->identity, NULL, attest, ref);
831     }
832     else if (NULL != op)
833     {
834       if (NULL != op->ar_cb)
835         op->ar_cb (op->cls, &msg->identity, NULL, attest, ref);
836     }
837     GNUNET_free (ref);
838     GNUNET_free (attest);
839     return;
840   }
841   GNUNET_assert (0);
842 }
843
844 /**
845  * Handle an incoming message of type
846  * #GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT
847  *
848  * @param cls
849  * @param msg the message we received
850  */
851 static void
852 handle_ticket_result (void *cls, const struct TicketResultMessage *msg)
853 {
854   struct GNUNET_RECLAIM_Handle *handle = cls;
855   struct GNUNET_RECLAIM_Operation *op;
856   struct GNUNET_RECLAIM_TicketIterator *it;
857   uint32_t r_id = ntohl (msg->id);
858   static const struct GNUNET_RECLAIM_Ticket ticket;
859
860   for (op = handle->op_head; NULL != op; op = op->next)
861     if (op->r_id == r_id)
862       break;
863   for (it = handle->ticket_it_head; NULL != it; it = it->next)
864     if (it->r_id == r_id)
865       break;
866   if ((NULL == op) && (NULL == it))
867     return;
868   if (NULL != op)
869   {
870     GNUNET_CONTAINER_DLL_remove (handle->op_head, handle->op_tail, op);
871     if (0 ==
872         memcmp (&msg->ticket, &ticket, sizeof(struct GNUNET_RECLAIM_Ticket)))
873     {
874       if (NULL != op->tr_cb)
875         op->tr_cb (op->cls, NULL);
876     }
877     else
878     {
879       if (NULL != op->tr_cb)
880         op->tr_cb (op->cls, &msg->ticket);
881     }
882     free_op (op);
883     return;
884   }
885   else if (NULL != it)
886   {
887     if (0 ==
888         memcmp (&msg->ticket, &ticket, sizeof(struct GNUNET_RECLAIM_Ticket)))
889     {
890       GNUNET_CONTAINER_DLL_remove (handle->ticket_it_head,
891                                    handle->ticket_it_tail,
892                                    it);
893       it->finish_cb (it->finish_cb_cls);
894       GNUNET_free (it);
895     }
896     else
897     {
898       if (NULL != it->tr_cb)
899         it->tr_cb (it->cls, &msg->ticket);
900     }
901     return;
902   }
903   GNUNET_break (0);
904 }
905
906
907 /**
908  * Handle an incoming message of type
909  * #GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET_RESULT
910  *
911  * @param cls
912  * @param msg the message we received
913  */
914 static void
915 handle_revoke_ticket_result (void *cls,
916                              const struct RevokeTicketResultMessage *msg)
917 {
918   struct GNUNET_RECLAIM_Handle *h = cls;
919   struct GNUNET_RECLAIM_Operation *op;
920   uint32_t r_id = ntohl (msg->id);
921   int32_t success;
922
923   LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing revocation result.\n");
924
925
926   for (op = h->op_head; NULL != op; op = op->next)
927     if (op->r_id == r_id)
928       break;
929   if (NULL == op)
930     return;
931   success = ntohl (msg->success);
932   {
933     if (NULL != op->rvk_cb)
934     {
935       op->rvk_cb (op->cls, success, NULL);
936     }
937     GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
938     free_op (op);
939     return;
940   }
941   GNUNET_assert (0);
942 }
943
944
945 /**
946  * Try again to connect to the service.
947  *
948  * @param h handle to the reclaim service.
949  */
950 static void
951 reconnect (struct GNUNET_RECLAIM_Handle *h)
952 {
953   struct GNUNET_MQ_MessageHandler handlers[] =
954   { GNUNET_MQ_hd_fixed_size (success_response,
955                              GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE,
956                              struct SuccessResultMessage,
957                              h),
958     GNUNET_MQ_hd_var_size (attribute_result,
959                            GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT,
960                            struct AttributeResultMessage,
961                            h),
962     GNUNET_MQ_hd_var_size (attestation_result,
963                            GNUNET_MESSAGE_TYPE_RECLAIM_ATTESTATION_RESULT,
964                            struct AttributeResultMessage,
965                            h),
966     GNUNET_MQ_hd_var_size (reference_result,
967                            GNUNET_MESSAGE_TYPE_RECLAIM_REFERENCE_RESULT,
968                            struct ReferenceResultMessage,
969                            h),
970     GNUNET_MQ_hd_fixed_size (ticket_result,
971                              GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT,
972                              struct TicketResultMessage,
973                              h),
974     GNUNET_MQ_hd_var_size (consume_ticket_result,
975                            GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT,
976                            struct ConsumeTicketResultMessage,
977                            h),
978     GNUNET_MQ_hd_fixed_size (revoke_ticket_result,
979                              GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET_RESULT,
980                              struct RevokeTicketResultMessage,
981                              h),
982     GNUNET_MQ_handler_end () };
983   struct GNUNET_RECLAIM_Operation *op;
984
985   GNUNET_assert (NULL == h->mq);
986   LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to reclaim service.\n");
987
988   h->mq =
989     GNUNET_CLIENT_connect (h->cfg, "reclaim", handlers, &mq_error_handler, h);
990   if (NULL == h->mq)
991     return;
992   for (op = h->op_head; NULL != op; op = op->next)
993     GNUNET_MQ_send_copy (h->mq, op->env);
994 }
995
996
997 /**
998  * Connect to the reclaim service.
999  *
1000  * @param cfg the configuration to use
1001  * @return handle to use
1002  */
1003 struct GNUNET_RECLAIM_Handle *
1004 GNUNET_RECLAIM_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
1005 {
1006   struct GNUNET_RECLAIM_Handle *h;
1007
1008   h = GNUNET_new (struct GNUNET_RECLAIM_Handle);
1009   h->cfg = cfg;
1010   reconnect (h);
1011   if (NULL == h->mq)
1012   {
1013     GNUNET_free (h);
1014     return NULL;
1015   }
1016   return h;
1017 }
1018
1019
1020 /**
1021  * Cancel an operation. Note that the operation MAY still
1022  * be executed; this merely cancels the continuation; if the request
1023  * was already transmitted, the service may still choose to complete
1024  * the operation.
1025  *
1026  * @param op operation to cancel
1027  */
1028 void
1029 GNUNET_RECLAIM_cancel (struct GNUNET_RECLAIM_Operation *op)
1030 {
1031   struct GNUNET_RECLAIM_Handle *h = op->h;
1032
1033   GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
1034   free_op (op);
1035 }
1036
1037
1038 /**
1039  * Disconnect from service
1040  *
1041  * @param h handle to destroy
1042  */
1043 void
1044 GNUNET_RECLAIM_disconnect (struct GNUNET_RECLAIM_Handle *h)
1045 {
1046   GNUNET_assert (NULL != h);
1047   if (NULL != h->mq)
1048   {
1049     GNUNET_MQ_destroy (h->mq);
1050     h->mq = NULL;
1051   }
1052   if (NULL != h->reconnect_task)
1053   {
1054     GNUNET_SCHEDULER_cancel (h->reconnect_task);
1055     h->reconnect_task = NULL;
1056   }
1057   GNUNET_assert (NULL == h->op_head);
1058   GNUNET_free (h);
1059 }
1060
1061
1062 /**
1063  * Store an attribute.  If the attribute is already present,
1064  * it is replaced with the new attribute.
1065  *
1066  * @param h handle to the re:claimID service
1067  * @param pkey private key of the identity
1068  * @param attr the attribute value
1069  * @param exp_interval the relative expiration interval for the attribute
1070  * @param cont continuation to call when done
1071  * @param cont_cls closure for @a cont
1072  * @return handle to abort the request
1073  */
1074 struct GNUNET_RECLAIM_Operation *
1075 GNUNET_RECLAIM_attribute_store (
1076   struct GNUNET_RECLAIM_Handle *h,
1077   const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
1078   const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr,
1079   const struct GNUNET_TIME_Relative *exp_interval,
1080   GNUNET_RECLAIM_ContinuationWithStatus cont,
1081   void *cont_cls)
1082 {
1083   struct GNUNET_RECLAIM_Operation *op;
1084   struct AttributeStoreMessage *sam;
1085   size_t attr_len;
1086
1087   op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1088   op->h = h;
1089   op->as_cb = cont;
1090   op->cls = cont_cls;
1091   op->r_id = h->r_id_gen++;
1092   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
1093   attr_len = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (attr);
1094   op->env = GNUNET_MQ_msg_extra (sam,
1095                                  attr_len,
1096                                  GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE);
1097   sam->identity = *pkey;
1098   sam->id = htonl (op->r_id);
1099   sam->exp = GNUNET_htonll (exp_interval->rel_value_us);
1100
1101   GNUNET_RECLAIM_ATTRIBUTE_serialize (attr, (char *) &sam[1]);
1102
1103   sam->attr_len = htons (attr_len);
1104   if (NULL != h->mq)
1105     GNUNET_MQ_send_copy (h->mq, op->env);
1106   return op;
1107 }
1108
1109
1110 /**
1111  * Delete an attribute. Tickets used to share this attribute are updated
1112  * accordingly.
1113  *
1114  * @param h handle to the re:claimID service
1115  * @param pkey Private key of the identity to add an attribute to
1116  * @param attr The attribute
1117  * @param cont Continuation to call when done
1118  * @param cont_cls Closure for @a cont
1119  * @return handle Used to to abort the request
1120  */
1121 struct GNUNET_RECLAIM_Operation *
1122 GNUNET_RECLAIM_attribute_delete (
1123   struct GNUNET_RECLAIM_Handle *h,
1124   const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
1125   const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr,
1126   GNUNET_RECLAIM_ContinuationWithStatus cont,
1127   void *cont_cls)
1128 {
1129   struct GNUNET_RECLAIM_Operation *op;
1130   struct AttributeDeleteMessage *dam;
1131   size_t attr_len;
1132
1133   op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1134   op->h = h;
1135   op->as_cb = cont;
1136   op->cls = cont_cls;
1137   op->r_id = h->r_id_gen++;
1138   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
1139   attr_len = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (attr);
1140   op->env = GNUNET_MQ_msg_extra (dam,
1141                                  attr_len,
1142                                  GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_DELETE);
1143   dam->identity = *pkey;
1144   dam->id = htonl (op->r_id);
1145   GNUNET_RECLAIM_ATTRIBUTE_serialize (attr, (char *) &dam[1]);
1146
1147   dam->attr_len = htons (attr_len);
1148   if (NULL != h->mq)
1149     GNUNET_MQ_send_copy (h->mq, op->env);
1150   return op;
1151 }
1152
1153 /**
1154    * Store an attestation.  If the attestation is already present,
1155    * it is replaced with the new attestation.
1156    *
1157    * @param h handle to the re:claimID service
1158    * @param pkey private key of the identity
1159    * @param attr the attestation value
1160    * @param exp_interval the relative expiration interval for the attestation
1161    * @param cont continuation to call when done
1162    * @param cont_cls closure for @a cont
1163    * @return handle to abort the request
1164    */
1165 struct GNUNET_RECLAIM_Operation *
1166 GNUNET_RECLAIM_attestation_store (
1167   struct GNUNET_RECLAIM_Handle *h,
1168   const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
1169   const struct GNUNET_RECLAIM_ATTESTATION_Claim *attr,
1170   const struct GNUNET_TIME_Relative *exp_interval,
1171   GNUNET_RECLAIM_ContinuationWithStatus cont,
1172   void *cont_cls)
1173 {
1174   struct GNUNET_RECLAIM_Operation *op;
1175   struct AttributeStoreMessage *sam;
1176   size_t attr_len;
1177
1178   op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1179   op->h = h;
1180   op->as_cb = cont;
1181   op->cls = cont_cls;
1182   op->r_id = h->r_id_gen++;
1183   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
1184   attr_len = GNUNET_RECLAIM_ATTESTATION_serialize_get_size (attr);
1185   op->env = GNUNET_MQ_msg_extra (sam,
1186                                  attr_len,
1187                                  GNUNET_MESSAGE_TYPE_RECLAIM_ATTESTATION_STORE);
1188   sam->identity = *pkey;
1189   sam->id = htonl (op->r_id);
1190   sam->exp = GNUNET_htonll (exp_interval->rel_value_us);
1191
1192   GNUNET_RECLAIM_ATTESTATION_serialize (attr, (char *) &sam[1]);
1193
1194   sam->attr_len = htons (attr_len);
1195   if (NULL != h->mq)
1196     GNUNET_MQ_send_copy (h->mq, op->env);
1197   return op;
1198 }
1199
1200 /**
1201    * Delete an attestation. Tickets used to share this attestation are updated
1202    * accordingly.
1203    *
1204    * @param h handle to the re:claimID service
1205    * @param pkey Private key of the identity to add an attribute to
1206    * @param attr The attestation
1207    * @param cont Continuation to call when done
1208    * @param cont_cls Closure for @a cont
1209    * @return handle Used to to abort the request
1210    */
1211 struct GNUNET_RECLAIM_Operation *
1212 GNUNET_RECLAIM_attestation_delete (
1213   struct GNUNET_RECLAIM_Handle *h,
1214   const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
1215   const struct GNUNET_RECLAIM_ATTESTATION_Claim *attr,
1216   GNUNET_RECLAIM_ContinuationWithStatus cont,
1217   void *cont_cls)
1218 {
1219   struct GNUNET_RECLAIM_Operation *op;
1220   struct AttributeDeleteMessage *dam;
1221   size_t attr_len;
1222
1223   op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1224   op->h = h;
1225   op->as_cb = cont;
1226   op->cls = cont_cls;
1227   op->r_id = h->r_id_gen++;
1228   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
1229   attr_len = GNUNET_RECLAIM_ATTESTATION_serialize_get_size (attr);
1230   op->env = GNUNET_MQ_msg_extra (dam,
1231                                  attr_len,
1232                                  GNUNET_MESSAGE_TYPE_RECLAIM_ATTESTATION_DELETE);
1233   dam->identity = *pkey;
1234   dam->id = htonl (op->r_id);
1235   GNUNET_RECLAIM_ATTESTATION_serialize (attr, (char *) &dam[1]);
1236
1237   dam->attr_len = htons (attr_len);
1238   if (NULL != h->mq)
1239     GNUNET_MQ_send_copy (h->mq, op->env);
1240   return op;
1241 }
1242
1243 /**
1244    * Store an attestation reference.  If the reference is already present,
1245    * it is replaced with the new reference.
1246    *
1247    * @param h handle to the re:claimID service
1248    * @param pkey private key of the identity
1249    * @param attr the reference value
1250    * @param exp_interval the relative expiration interval for the reference
1251    * @param cont continuation to call when done
1252    * @param cont_cls closure for @a cont
1253    * @return handle to abort the request
1254    */
1255 struct GNUNET_RECLAIM_Operation *
1256 GNUNET_RECLAIM_attestation_reference_store (
1257   struct GNUNET_RECLAIM_Handle *h,
1258   const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
1259   const struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *attr,
1260   const struct GNUNET_TIME_Relative *exp_interval,
1261   GNUNET_RECLAIM_ContinuationWithStatus cont,
1262   void *cont_cls)
1263 {
1264   struct GNUNET_RECLAIM_Operation *op;
1265   struct AttributeStoreMessage *sam;
1266   size_t attr_len;
1267   op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1268   op->h = h;
1269   op->as_cb = cont;
1270   op->cls = cont_cls;
1271   op->r_id = h->r_id_gen++;
1272   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
1273   attr_len = GNUNET_RECLAIM_ATTESTATION_REF_serialize_get_size (attr);
1274   op->env = GNUNET_MQ_msg_extra (sam,
1275                                  attr_len,
1276                                  GNUNET_MESSAGE_TYPE_RECLAIM_REFERENCE_STORE);
1277   sam->identity = *pkey;
1278   sam->id = htonl (op->r_id);
1279   sam->exp = GNUNET_htonll (exp_interval->rel_value_us);
1280
1281   GNUNET_RECLAIM_ATTESTATION_REF_serialize (attr, (char *) &sam[1]);
1282
1283   sam->attr_len = htons (attr_len);
1284   if (NULL != h->mq)
1285     GNUNET_MQ_send_copy (h->mq, op->env);
1286   return op;
1287 }
1288
1289 /**
1290  * Delete an attestation reference. Tickets used to share this reference are updated
1291  * accordingly.
1292  *
1293  * @param h handle to the re:claimID service
1294  * @param pkey Private key of the identity to delete the reference from
1295  * @param attr The reference
1296  * @param cont Continuation to call when done
1297  * @param cont_cls Closure for @a cont
1298  * @return handle Used to to abort the request
1299  */
1300 struct GNUNET_RECLAIM_Operation *
1301 GNUNET_RECLAIM_attestation_reference_delete (
1302   struct GNUNET_RECLAIM_Handle *h,
1303   const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
1304   const struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *attr,
1305   GNUNET_RECLAIM_ContinuationWithStatus cont,
1306   void *cont_cls)
1307 {
1308
1309   struct GNUNET_RECLAIM_Operation *op;
1310   struct AttributeDeleteMessage *dam;
1311   size_t attr_len;
1312
1313   op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1314   op->h = h;
1315   op->as_cb = cont;
1316   op->cls = cont_cls;
1317   op->r_id = h->r_id_gen++;
1318   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
1319   attr_len = GNUNET_RECLAIM_ATTESTATION_REF_serialize_get_size (attr);
1320   op->env = GNUNET_MQ_msg_extra (dam,
1321                                  attr_len,
1322                                  GNUNET_MESSAGE_TYPE_RECLAIM_REFERENCE_DELETE);
1323   dam->identity = *pkey;
1324   dam->id = htonl (op->r_id);
1325   GNUNET_RECLAIM_ATTESTATION_REF_serialize (attr, (char *) &dam[1]);
1326
1327   dam->attr_len = htons (attr_len);
1328   if (NULL != h->mq)
1329     GNUNET_MQ_send_copy (h->mq, op->env);
1330   return op;
1331 }
1332
1333 /**
1334  * List all attributes for a local identity.
1335  * This MUST lock the `struct GNUNET_RECLAIM_Handle`
1336  * for any other calls than #GNUNET_RECLAIM_get_attributes_next() and
1337  * #GNUNET_RECLAIM_get_attributes_stop. @a proc will be called once
1338  * immediately, and then again after
1339  * #GNUNET_RECLAIM_get_attributes_next() is invoked.
1340  *
1341  * On error (disconnect), @a error_cb will be invoked.
1342  * On normal completion, @a finish_cb proc will be
1343  * invoked.
1344  *
1345  * @param h Handle to the re:claimID service
1346  * @param identity Identity to iterate over
1347  * @param error_cb Function to call on error (i.e. disconnect),
1348  *        the handle is afterwards invalid
1349  * @param error_cb_cls Closure for @a error_cb
1350  * @param proc Function to call on each attribute
1351  * @param proc_cls Closure for @a proc
1352  * @param finish_cb Function to call on completion
1353  *        the handle is afterwards invalid
1354  * @param finish_cb_cls Closure for @a finish_cb
1355  * @return an iterator Handle to use for iteration
1356  */
1357 struct GNUNET_RECLAIM_AttributeIterator *
1358 GNUNET_RECLAIM_get_attributes_start (
1359   struct GNUNET_RECLAIM_Handle *h,
1360   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1361   GNUNET_SCHEDULER_TaskCallback error_cb,
1362   void *error_cb_cls,
1363   GNUNET_RECLAIM_AttributeResult proc,
1364   void *proc_cls,
1365   GNUNET_SCHEDULER_TaskCallback finish_cb,
1366   void *finish_cb_cls)
1367 {
1368   struct GNUNET_RECLAIM_AttributeIterator *it;
1369   struct GNUNET_MQ_Envelope *env;
1370   struct AttributeIterationStartMessage *msg;
1371   uint32_t rid;
1372
1373   rid = h->r_id_gen++;
1374   it = GNUNET_new (struct GNUNET_RECLAIM_AttributeIterator);
1375   it->h = h;
1376   it->error_cb = error_cb;
1377   it->error_cb_cls = error_cb_cls;
1378   it->finish_cb = finish_cb;
1379   it->finish_cb_cls = finish_cb_cls;
1380   it->proc = proc;
1381   it->proc_cls = proc_cls;
1382   it->r_id = rid;
1383   it->identity = *identity;
1384   GNUNET_CONTAINER_DLL_insert_tail (h->it_head, h->it_tail, it);
1385   env =
1386     GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_START);
1387   msg->id = htonl (rid);
1388   msg->identity = *identity;
1389   if (NULL == h->mq)
1390     it->env = env;
1391   else
1392     GNUNET_MQ_send (h->mq, env);
1393   return it;
1394 }
1395
1396
1397 /**
1398  * Calls the record processor specified in #GNUNET_RECLAIM_get_attributes_start
1399  * for the next record.
1400  *
1401  * @param it the iterator
1402  */
1403 void
1404 GNUNET_RECLAIM_get_attributes_next (struct GNUNET_RECLAIM_AttributeIterator *it)
1405 {
1406   struct GNUNET_RECLAIM_Handle *h = it->h;
1407   struct AttributeIterationNextMessage *msg;
1408   struct GNUNET_MQ_Envelope *env;
1409
1410   env =
1411     GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_NEXT);
1412   msg->id = htonl (it->r_id);
1413   GNUNET_MQ_send (h->mq, env);
1414 }
1415
1416
1417 /**
1418  * Stops iteration and releases the handle for further calls. Must
1419  * be called on any iteration that has not yet completed prior to calling
1420  * #GNUNET_RECLAIM_disconnect.
1421  *
1422  * @param it the iterator
1423  */
1424 void
1425 GNUNET_RECLAIM_get_attributes_stop (struct GNUNET_RECLAIM_AttributeIterator *it)
1426 {
1427   struct GNUNET_RECLAIM_Handle *h = it->h;
1428   struct GNUNET_MQ_Envelope *env;
1429   struct AttributeIterationStopMessage *msg;
1430
1431   if (NULL != h->mq)
1432   {
1433     env =
1434       GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_STOP);
1435     msg->id = htonl (it->r_id);
1436     GNUNET_MQ_send (h->mq, env);
1437   }
1438   free_it (it);
1439 }
1440
1441
1442 /**
1443  * Issues a ticket to another relying party. The identity may use
1444  * @GNUNET_RECLAIM_ticket_consume to consume the ticket
1445  * and retrieve the attributes specified in the attribute list.
1446  *
1447  * @param h the reclaim to use
1448  * @param iss the issuing identity (= the user)
1449  * @param rp the subject of the ticket (= the relying party)
1450  * @param attrs the attributes that the relying party is given access to
1451  * @param cb the callback
1452  * @param cb_cls the callback closure
1453  * @return handle to abort the operation
1454  */
1455 struct GNUNET_RECLAIM_Operation *
1456 GNUNET_RECLAIM_ticket_issue (
1457   struct GNUNET_RECLAIM_Handle *h,
1458   const struct GNUNET_CRYPTO_EcdsaPrivateKey *iss,
1459   const struct GNUNET_CRYPTO_EcdsaPublicKey *rp,
1460   const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
1461   GNUNET_RECLAIM_TicketCallback cb,
1462   void *cb_cls)
1463 {
1464   struct GNUNET_RECLAIM_Operation *op;
1465   struct IssueTicketMessage *tim;
1466   size_t attr_len;
1467
1468   fprintf (stderr, "Issuing ticket\n");
1469   op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1470   op->h = h;
1471   op->tr_cb = cb;
1472   op->cls = cb_cls;
1473   op->r_id = h->r_id_gen++;
1474   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
1475   attr_len = GNUNET_RECLAIM_ATTRIBUTE_list_serialize_get_size (attrs);
1476   op->env = GNUNET_MQ_msg_extra (tim,
1477                                  attr_len,
1478                                  GNUNET_MESSAGE_TYPE_RECLAIM_ISSUE_TICKET);
1479   tim->identity = *iss;
1480   tim->rp = *rp;
1481   tim->id = htonl (op->r_id);
1482
1483   GNUNET_RECLAIM_ATTRIBUTE_list_serialize (attrs, (char *) &tim[1]);
1484
1485   tim->attr_len = htons (attr_len);
1486   if (NULL != h->mq)
1487     GNUNET_MQ_send_copy (h->mq, op->env);
1488   return op;
1489 }
1490
1491
1492 /**
1493  * Consumes an issued ticket. The ticket is persisted
1494  * and used to retrieve identity information from the issuer
1495  *
1496  * @param h the reclaim to use
1497  * @param identity the identity that is the subject of the issued ticket (the
1498  * relying party)
1499  * @param ticket the issued ticket to consume
1500  * @param cb the callback to call
1501  * @param cb_cls the callback closure
1502  * @return handle to abort the operation
1503  */
1504 struct GNUNET_RECLAIM_Operation *
1505 GNUNET_RECLAIM_ticket_consume (
1506   struct GNUNET_RECLAIM_Handle *h,
1507   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1508   const struct GNUNET_RECLAIM_Ticket *ticket,
1509   GNUNET_RECLAIM_AttributeResult cb,
1510   void *cb_cls)
1511 {
1512   struct GNUNET_RECLAIM_Operation *op;
1513   struct ConsumeTicketMessage *ctm;
1514
1515   op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1516   op->h = h;
1517   op->ar_cb = cb;
1518   op->cls = cb_cls;
1519   op->r_id = h->r_id_gen++;
1520   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
1521   op->env = GNUNET_MQ_msg (ctm, GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET);
1522   ctm->identity = *identity;
1523   ctm->id = htonl (op->r_id);
1524   ctm->ticket = *ticket;
1525   if (NULL != h->mq)
1526     GNUNET_MQ_send_copy (h->mq, op->env);
1527   return op;
1528 }
1529
1530
1531 /**
1532  * Lists all tickets that have been issued to remote
1533  * identites (relying parties)
1534  *
1535  * @param h the reclaim to use
1536  * @param identity the issuing identity
1537  * @param error_cb function to call on error (i.e. disconnect),
1538  *        the handle is afterwards invalid
1539  * @param error_cb_cls closure for @a error_cb
1540  * @param proc function to call on each ticket; it
1541  *        will be called repeatedly with a value (if available)
1542  * @param proc_cls closure for @a proc
1543  * @param finish_cb function to call on completion
1544  *        the handle is afterwards invalid
1545  * @param finish_cb_cls closure for @a finish_cb
1546  * @return an iterator handle to use for iteration
1547  */
1548 struct GNUNET_RECLAIM_TicketIterator *
1549 GNUNET_RECLAIM_ticket_iteration_start (
1550   struct GNUNET_RECLAIM_Handle *h,
1551   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1552   GNUNET_SCHEDULER_TaskCallback error_cb,
1553   void *error_cb_cls,
1554   GNUNET_RECLAIM_TicketCallback proc,
1555   void *proc_cls,
1556   GNUNET_SCHEDULER_TaskCallback finish_cb,
1557   void *finish_cb_cls)
1558 {
1559   struct GNUNET_RECLAIM_TicketIterator *it;
1560   struct GNUNET_MQ_Envelope *env;
1561   struct TicketIterationStartMessage *msg;
1562   uint32_t rid;
1563
1564   rid = h->r_id_gen++;
1565   it = GNUNET_new (struct GNUNET_RECLAIM_TicketIterator);
1566   it->h = h;
1567   it->error_cb = error_cb;
1568   it->error_cb_cls = error_cb_cls;
1569   it->finish_cb = finish_cb;
1570   it->finish_cb_cls = finish_cb_cls;
1571   it->tr_cb = proc;
1572   it->cls = proc_cls;
1573   it->r_id = rid;
1574   GNUNET_CONTAINER_DLL_insert_tail (h->ticket_it_head, h->ticket_it_tail, it);
1575   env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_START);
1576   msg->id = htonl (rid);
1577   msg->identity = *identity;
1578   if (NULL == h->mq)
1579     it->env = env;
1580   else
1581     GNUNET_MQ_send (h->mq, env);
1582   return it;
1583 }
1584
1585
1586 /**
1587  * Calls the ticket processor specified in
1588  * #GNUNET_RECLAIM_ticket_iteration_start for the next record.
1589  *
1590  * @param it the iterator
1591  */
1592 void
1593 GNUNET_RECLAIM_ticket_iteration_next (struct GNUNET_RECLAIM_TicketIterator *it)
1594 {
1595   struct GNUNET_RECLAIM_Handle *h = it->h;
1596   struct TicketIterationNextMessage *msg;
1597   struct GNUNET_MQ_Envelope *env;
1598
1599   env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_NEXT);
1600   msg->id = htonl (it->r_id);
1601   GNUNET_MQ_send (h->mq, env);
1602 }
1603
1604
1605 /**
1606  * Stops iteration and releases the handle for further calls.  Must
1607  * be called on any iteration that has not yet completed prior to calling
1608  * #GNUNET_RECLAIM_disconnect.
1609  *
1610  * @param it the iterator
1611  */
1612 void
1613 GNUNET_RECLAIM_ticket_iteration_stop (struct GNUNET_RECLAIM_TicketIterator *it)
1614 {
1615   struct GNUNET_RECLAIM_Handle *h = it->h;
1616   struct GNUNET_MQ_Envelope *env;
1617   struct TicketIterationStopMessage *msg;
1618
1619   if (NULL != h->mq)
1620   {
1621     env =
1622       GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_STOP);
1623     msg->id = htonl (it->r_id);
1624     GNUNET_MQ_send (h->mq, env);
1625   }
1626   GNUNET_free (it);
1627 }
1628
1629
1630 /**
1631  * Revoked an issued ticket. The relying party will be unable to retrieve
1632  * attributes. Other issued tickets remain unaffected.
1633  * This includes tickets issued to other relying parties as well as to
1634  * other tickets issued to the audience specified in this ticket.
1635  *
1636  * @param h the identity provider to use
1637  * @param identity the issuing identity
1638  * @param ticket the ticket to revoke
1639  * @param cb the callback
1640  * @param cb_cls the callback closure
1641  * @return handle to abort the operation
1642  */
1643 struct GNUNET_RECLAIM_Operation *
1644 GNUNET_RECLAIM_ticket_revoke (
1645   struct GNUNET_RECLAIM_Handle *h,
1646   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1647   const struct GNUNET_RECLAIM_Ticket *ticket,
1648   GNUNET_RECLAIM_ContinuationWithStatus cb,
1649   void *cb_cls)
1650 {
1651   struct GNUNET_RECLAIM_Operation *op;
1652   struct RevokeTicketMessage *msg;
1653   uint32_t rid;
1654
1655   rid = h->r_id_gen++;
1656   op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1657   op->h = h;
1658   op->rvk_cb = cb;
1659   op->cls = cb_cls;
1660   op->r_id = rid;
1661   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
1662   op->env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET);
1663   msg->id = htonl (rid);
1664   msg->identity = *identity;
1665   msg->ticket = *ticket;
1666   if (NULL != h->mq)
1667   {
1668     GNUNET_MQ_send (h->mq, op->env);
1669     op->env = NULL;
1670   }
1671   return op;
1672 }
1673
1674
1675 /* end of reclaim_api.c */