move to 256-bit identifier; some cleanups
[oweals/gnunet.git] / src / reclaim / gnunet-service-reclaim.c
1 /*
2    This file is part of GNUnet.
3    Copyright (C) 2012-2015 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  * @author Martin Schanzenbach
22  * @file src/reclaim/gnunet-service-reclaim.c
23  * @brief reclaim Service
24  *
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet-service-reclaim_tickets.h"
29 #include "gnunet_constants.h"
30 #include "gnunet_gnsrecord_lib.h"
31 #include "gnunet_protocols.h"
32 #include "gnunet_reclaim_attribute_lib.h"
33 #include "gnunet_reclaim_service.h"
34 #include "gnunet_signatures.h"
35 #include "reclaim.h"
36
37
38 /**
39  * Namestore handle
40  */
41 static struct GNUNET_NAMESTORE_Handle *nsh;
42
43 /**
44  * Timeout task
45  */
46 static struct GNUNET_SCHEDULER_Task *timeout_task;
47
48 /**
49  * Our configuration.
50  */
51 static const struct GNUNET_CONFIGURATION_Handle *cfg;
52
53 /**
54  * An idp client
55  */
56 struct IdpClient;
57
58 /**
59  * A ticket iteration operation.
60  */
61 struct TicketIteration
62 {
63   /**
64    * DLL
65    */
66   struct TicketIteration *next;
67
68   /**
69    * DLL
70    */
71   struct TicketIteration *prev;
72
73   /**
74    * Client which intiated this zone iteration
75    */
76   struct IdpClient *client;
77
78   /**
79    * The operation id fot the iteration in the response for the client
80    */
81   uint32_t r_id;
82
83   /**
84    * The ticket iterator
85    */
86   struct RECLAIM_TICKETS_Iterator *iter;
87 };
88
89
90 /**
91  * An attribute iteration operation.
92  */
93 struct AttributeIterator
94 {
95   /**
96    * Next element in the DLL
97    */
98   struct AttributeIterator *next;
99
100   /**
101    * Previous element in the DLL
102    */
103   struct AttributeIterator *prev;
104
105   /**
106    * IDP client which intiated this zone iteration
107    */
108   struct IdpClient *client;
109
110   /**
111    * Key of the zone we are iterating over.
112    */
113   struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
114
115   /**
116    * Namestore iterator
117    */
118   struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
119
120   /**
121    * The operation id fot the zone iteration in the response for the client
122    */
123   uint32_t request_id;
124 };
125
126
127 /**
128  * An idp client
129  */
130 struct IdpClient
131 {
132   /**
133    * DLL
134    */
135   struct IdpClient *prev;
136
137   /**
138    * DLL
139    */
140   struct IdpClient *next;
141
142   /**
143    * The client
144    */
145   struct GNUNET_SERVICE_Client *client;
146
147   /**
148    * Message queue for transmission to @e client
149    */
150   struct GNUNET_MQ_Handle *mq;
151
152   /**
153    * Head of the DLL of
154    * Attribute iteration operations in
155    * progress initiated by this client
156    */
157   struct AttributeIterator *attr_iter_head;
158
159   /**
160    * Tail of the DLL of
161    * Attribute iteration operations
162    * in progress initiated by this client
163    */
164   struct AttributeIterator *attr_iter_tail;
165
166   /**
167    * Head of DLL of ticket iteration ops
168    */
169   struct TicketIteration *ticket_iter_head;
170
171   /**
172    * Tail of DLL of ticket iteration ops
173    */
174   struct TicketIteration *ticket_iter_tail;
175
176   /**
177    * Head of DLL of ticket revocation ops
178    */
179   struct TicketRevocationOperation *revoke_op_head;
180
181   /**
182    * Tail of DLL of ticket revocation ops
183    */
184   struct TicketRevocationOperation *revoke_op_tail;
185
186   /**
187    * Head of DLL of ticket issue ops
188    */
189   struct TicketIssueOperation *issue_op_head;
190
191   /**
192    * Tail of DLL of ticket issue ops
193    */
194   struct TicketIssueOperation *issue_op_tail;
195
196   /**
197    * Head of DLL of ticket consume ops
198    */
199   struct ConsumeTicketOperation *consume_op_head;
200
201   /**
202    * Tail of DLL of ticket consume ops
203    */
204   struct ConsumeTicketOperation *consume_op_tail;
205
206   /**
207    * Head of DLL of attribute store ops
208    */
209   struct AttributeStoreHandle *store_op_head;
210
211   /**
212    * Tail of DLL of attribute store ops
213    */
214   struct AttributeStoreHandle *store_op_tail;
215   /**
216    * Head of DLL of attribute delete ops
217    */
218   struct AttributeDeleteHandle *delete_op_head;
219
220   /**
221    * Tail of DLL of attribute delete ops
222    */
223   struct AttributeDeleteHandle *delete_op_tail;
224 };
225
226
227 /**
228  * Handle for attribute deletion request
229  */
230 struct AttributeDeleteHandle
231 {
232   /**
233    * DLL
234    */
235   struct AttributeDeleteHandle *next;
236
237   /**
238    * DLL
239    */
240   struct AttributeDeleteHandle *prev;
241
242   /**
243    * Client connection
244    */
245   struct IdpClient *client;
246
247   /**
248    * Identity
249    */
250   struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
251
252
253   /**
254    * QueueEntry
255    */
256   struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
257
258   /**
259    * Iterator
260    */
261   struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
262
263   /**
264    * The attribute to delete
265    */
266   struct GNUNET_RECLAIM_ATTRIBUTE_Claim *claim;
267
268   /**
269    * The attestation to delete
270    */
271   struct GNUNET_RECLAIM_ATTESTATION_Claim *attest;
272
273   /**
274   * The reference to delete
275   */
276   struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *reference;
277   /**
278    * Tickets to update
279    */
280   struct TicketRecordsEntry *tickets_to_update_head;
281
282   /**
283    * Tickets to update
284    */
285   struct TicketRecordsEntry *tickets_to_update_tail;
286
287   /**
288    * Attribute label
289    */
290   char *label;
291
292   /**
293    * request id
294    */
295   uint32_t r_id;
296 };
297
298
299 /**
300  * Handle for attribute store request
301  */
302 struct AttributeStoreHandle
303 {
304   /**
305    * DLL
306    */
307   struct AttributeStoreHandle *next;
308
309   /**
310    * DLL
311    */
312   struct AttributeStoreHandle *prev;
313
314   /**
315    * Client connection
316    */
317   struct IdpClient *client;
318
319   /**
320    * Identity
321    */
322   struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
323
324   /**
325    * Identity pubkey
326    */
327   struct GNUNET_CRYPTO_EcdsaPublicKey identity_pkey;
328
329   /**
330    * QueueEntry
331    */
332   struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
333
334   /**
335    * The attribute to store
336    */
337   struct GNUNET_RECLAIM_ATTRIBUTE_Claim *claim;
338
339   /**
340   * The attestation to store
341   */
342   struct GNUNET_RECLAIM_ATTESTATION_Claim *attest;
343
344   /**
345   * The reference to store
346   */
347   struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *reference;
348
349   /**
350    * The attribute expiration interval
351    */
352   struct GNUNET_TIME_Relative exp;
353
354   /**
355    * request id
356    */
357   uint32_t r_id;
358 };
359
360
361 /**
362  * Handle for ticket consume request
363  */
364 struct ConsumeTicketOperation
365 {
366   /**
367    * DLL
368    */
369   struct ConsumeTicketOperation *next;
370
371   /**
372    * DLL
373    */
374   struct ConsumeTicketOperation *prev;
375
376   /**
377    * Client connection
378    */
379   struct IdpClient *client;
380
381   /**
382    * request id
383    */
384   uint32_t r_id;
385
386   /**
387    * Ticket consume handle
388    */
389   struct RECLAIM_TICKETS_ConsumeHandle *ch;
390 };
391
392
393 /**
394  * Ticket revocation request handle
395  */
396 struct TicketRevocationOperation
397 {
398   /**
399    * DLL
400    */
401   struct TicketRevocationOperation *prev;
402
403   /**
404    * DLL
405    */
406   struct TicketRevocationOperation *next;
407
408   /**
409    * Client connection
410    */
411   struct IdpClient *client;
412
413   /**
414    * Revocation handle
415    */
416   struct RECLAIM_TICKETS_RevokeHandle *rh;
417
418   /**
419    * request id
420    */
421   uint32_t r_id;
422 };
423
424
425 /**
426  * Ticket issue operation handle
427  */
428 struct TicketIssueOperation
429 {
430   /**
431    * DLL
432    */
433   struct TicketIssueOperation *prev;
434
435   /**
436    * DLL
437    */
438   struct TicketIssueOperation *next;
439
440   /**
441    * Client connection
442    */
443   struct IdpClient *client;
444
445   /**
446    * request id
447    */
448   uint32_t r_id;
449 };
450
451
452 /**
453  * Client list
454  */
455 static struct IdpClient *client_list_head = NULL;
456
457 /**
458  * Client list
459  */
460 static struct IdpClient *client_list_tail = NULL;
461
462
463 /**
464  * Cleanup attribute delete handle
465  *
466  * @param adh the attribute to cleanup
467  */
468 static void
469 cleanup_adh (struct AttributeDeleteHandle *adh)
470 {
471   struct TicketRecordsEntry *le;
472
473   if (NULL != adh->ns_it)
474     GNUNET_NAMESTORE_zone_iteration_stop (adh->ns_it);
475   if (NULL != adh->ns_qe)
476     GNUNET_NAMESTORE_cancel (adh->ns_qe);
477   if (NULL != adh->label)
478     GNUNET_free (adh->label);
479   if (NULL != adh->claim)
480     GNUNET_free (adh->claim);
481   if (NULL != adh->attest)
482     GNUNET_free (adh->attest);
483   if (NULL != adh->reference)
484     GNUNET_free (adh->reference);
485   while (NULL != (le = adh->tickets_to_update_head))
486   {
487     GNUNET_CONTAINER_DLL_remove (adh->tickets_to_update_head,
488                                  adh->tickets_to_update_tail,
489                                  le);
490     if (NULL != le->label)
491       GNUNET_free (le->label);
492     if (NULL != le->data)
493       GNUNET_free (le->data);
494     GNUNET_free (le);
495   }
496   GNUNET_free (adh);
497 }
498
499
500 /**
501  * Cleanup attribute store handle
502  *
503  * @param handle handle to clean up
504  */
505 static void
506 cleanup_as_handle (struct AttributeStoreHandle *ash)
507 {
508   if (NULL != ash->ns_qe)
509     GNUNET_NAMESTORE_cancel (ash->ns_qe);
510   if (NULL != ash->claim)
511     GNUNET_free (ash->claim);
512   if (NULL != ash->attest)
513     GNUNET_free (ash->attest);
514   if (NULL != ash->reference)
515     GNUNET_free (ash->reference);
516   GNUNET_free (ash);
517 }
518
519
520 /**
521  * Cleanup client
522  *
523  * @param idp the client to clean up
524  */
525 static void
526 cleanup_client (struct IdpClient *idp)
527 {
528   struct AttributeIterator *ai;
529   struct TicketIteration *ti;
530   struct TicketRevocationOperation *rop;
531   struct TicketIssueOperation *iss;
532   struct ConsumeTicketOperation *ct;
533   struct AttributeStoreHandle *as;
534   struct AttributeDeleteHandle *adh;
535
536   while (NULL != (iss = idp->issue_op_head))
537   {
538     GNUNET_CONTAINER_DLL_remove (idp->issue_op_head, idp->issue_op_tail, iss);
539     GNUNET_free (iss);
540   }
541   while (NULL != (ct = idp->consume_op_head))
542   {
543     GNUNET_CONTAINER_DLL_remove (idp->consume_op_head,
544                                  idp->consume_op_tail,
545                                  ct);
546     if (NULL != ct->ch)
547       RECLAIM_TICKETS_consume_cancel (ct->ch);
548     GNUNET_free (ct);
549   }
550   while (NULL != (as = idp->store_op_head))
551   {
552     GNUNET_CONTAINER_DLL_remove (idp->store_op_head, idp->store_op_tail, as);
553     cleanup_as_handle (as);
554   }
555   while (NULL != (adh = idp->delete_op_head))
556   {
557     GNUNET_CONTAINER_DLL_remove (idp->delete_op_head, idp->delete_op_tail, adh);
558     cleanup_adh (adh);
559   }
560
561   while (NULL != (ai = idp->attr_iter_head))
562   {
563     GNUNET_CONTAINER_DLL_remove (idp->attr_iter_head, idp->attr_iter_tail, ai);
564     GNUNET_free (ai);
565   }
566   while (NULL != (rop = idp->revoke_op_head))
567   {
568     GNUNET_CONTAINER_DLL_remove (idp->revoke_op_head, idp->revoke_op_tail, rop);
569     if (NULL != rop->rh)
570       RECLAIM_TICKETS_revoke_cancel (rop->rh);
571     GNUNET_free (rop);
572   }
573   while (NULL != (ti = idp->ticket_iter_head))
574   {
575     GNUNET_CONTAINER_DLL_remove (idp->ticket_iter_head,
576                                  idp->ticket_iter_tail,
577                                  ti);
578     if (NULL != ti->iter)
579       RECLAIM_TICKETS_iteration_stop (ti->iter);
580     GNUNET_free (ti);
581   }
582   GNUNET_free (idp);
583 }
584
585
586 /**
587  * Cleanup task
588  */
589 static void
590 cleanup ()
591 {
592   struct IdpClient *cl;
593
594   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
595
596   while (NULL != (cl = client_list_head))
597   {
598     GNUNET_CONTAINER_DLL_remove (client_list_head,
599                                  client_list_tail,
600                                  cl);
601     cleanup_client (cl);
602   }
603   RECLAIM_TICKETS_deinit ();
604   if (NULL != timeout_task)
605     GNUNET_SCHEDULER_cancel (timeout_task);
606   if (NULL != nsh)
607     GNUNET_NAMESTORE_disconnect (nsh);
608 }
609
610
611 /**
612  * Shutdown task
613  *
614  * @param cls NULL
615  */
616 static void
617 do_shutdown (void *cls)
618 {
619   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down...\n");
620   cleanup ();
621 }
622
623
624 /**
625  * Sends a ticket result message to the client
626  *
627  * @param client the client to send to
628  * @param r_id the request message ID to reply to
629  * @param ticket the ticket to include (may be NULL)
630  * @param success the success status of the request
631  */
632 static void
633 send_ticket_result (const struct IdpClient *client,
634                     uint32_t r_id,
635                     const struct GNUNET_RECLAIM_Ticket *ticket,
636                     uint32_t success)
637 {
638   struct TicketResultMessage *irm;
639   struct GNUNET_MQ_Envelope *env;
640
641   env = GNUNET_MQ_msg (irm,
642                        GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT);
643   if (NULL != ticket)
644   {
645     irm->ticket = *ticket;
646   }
647   // TODO add success member
648   irm->id = htonl (r_id);
649   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending TICKET_RESULT message\n");
650   GNUNET_MQ_send (client->mq, env);
651 }
652
653
654 /**
655  * Issue ticket result
656  *
657  * @param cls out ticket issue operation handle
658  * @param ticket the issued ticket
659  * @param success issue success status (GNUNET_OK if successful)
660  * @param emsg error message (NULL of success is GNUNET_OK)
661  */
662 static void
663 issue_ticket_result_cb (void *cls,
664                         struct GNUNET_RECLAIM_Ticket *ticket,
665                         int32_t success,
666                         const char *emsg)
667 {
668   struct TicketIssueOperation *tio = cls;
669
670   if (GNUNET_OK != success)
671   {
672     send_ticket_result (tio->client, tio->r_id, NULL, GNUNET_SYSERR);
673     GNUNET_CONTAINER_DLL_remove (tio->client->issue_op_head,
674                                  tio->client->issue_op_tail,
675                                  tio);
676     GNUNET_free (tio);
677     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error issuing ticket: %s\n", emsg);
678     return;
679   }
680   send_ticket_result (tio->client, tio->r_id, ticket, GNUNET_SYSERR);
681   GNUNET_CONTAINER_DLL_remove (tio->client->issue_op_head,
682                                tio->client->issue_op_tail,
683                                tio);
684   GNUNET_free (tio);
685 }
686
687
688 /**
689  * Check issue ticket message
690  *
691  * @cls unused
692  * @im message to check
693  * @return GNUNET_OK if message is ok
694  */
695 static int
696 check_issue_ticket_message (void *cls, const struct IssueTicketMessage *im)
697 {
698   uint16_t size;
699
700   size = ntohs (im->header.size);
701   if (size <= sizeof(struct IssueTicketMessage))
702   {
703     GNUNET_break (0);
704     return GNUNET_SYSERR;
705   }
706   return GNUNET_OK;
707 }
708
709
710 /**
711  * Handle ticket issue message
712  *
713  * @param cls our client
714  * @param im the message
715  */
716 static void
717 handle_issue_ticket_message (void *cls, const struct IssueTicketMessage *im)
718 {
719   struct TicketIssueOperation *tio;
720   struct IdpClient *idp = cls;
721   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
722   size_t attrs_len;
723
724   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ISSUE_TICKET message\n");
725   tio = GNUNET_new (struct TicketIssueOperation);
726   attrs_len = ntohs (im->attr_len);
727   attrs = GNUNET_RECLAIM_ATTRIBUTE_list_deserialize ((char *) &im[1],
728                                                      attrs_len);
729   tio->r_id = ntohl (im->id);
730   tio->client = idp;
731   GNUNET_CONTAINER_DLL_insert (idp->issue_op_head, idp->issue_op_tail, tio);
732   RECLAIM_TICKETS_issue (&im->identity,
733                          attrs,
734                          &im->rp,
735                          &issue_ticket_result_cb,
736                          tio);
737   GNUNET_SERVICE_client_continue (idp->client);
738   GNUNET_RECLAIM_ATTRIBUTE_list_destroy (attrs);
739 }
740
741
742 /**********************************************************
743 * Revocation
744 **********************************************************/
745
746 /**
747  * Handles revocation result
748  *
749  * @param cls our revocation operation handle
750  * @param success revocation result (GNUNET_OK if successful)
751  */
752 static void
753 revoke_result_cb (void *cls, int32_t success)
754 {
755   struct TicketRevocationOperation *rop = cls;
756   struct GNUNET_MQ_Envelope *env;
757   struct RevokeTicketResultMessage *trm;
758
759   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
760               "Sending REVOKE_TICKET_RESULT message\n");
761   rop->rh = NULL;
762   env = GNUNET_MQ_msg (trm, GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET_RESULT);
763   trm->id = htonl (rop->r_id);
764   trm->success = htonl (success);
765   GNUNET_MQ_send (rop->client->mq, env);
766   GNUNET_CONTAINER_DLL_remove (rop->client->revoke_op_head,
767                                rop->client->revoke_op_tail,
768                                rop);
769   GNUNET_free (rop);
770 }
771
772
773 /**
774  * Check revocation message format
775  *
776  * @param cls unused
777  * @param im the message to check
778  * @return GNUNET_OK if message is ok
779  */
780 static int
781 check_revoke_ticket_message (void *cls, const struct RevokeTicketMessage *im)
782 {
783   uint16_t size;
784
785   size = ntohs (im->header.size);
786   if (size != sizeof(struct RevokeTicketMessage))
787   {
788     GNUNET_break (0);
789     return GNUNET_SYSERR;
790   }
791   return GNUNET_OK;
792 }
793
794
795 /**
796  * Handle a revocation message to a ticket.
797  *
798  * @param cls our client
799  * @param rm the message to handle
800  */
801 static void
802 handle_revoke_ticket_message (void *cls, const struct RevokeTicketMessage *rm)
803 {
804   struct TicketRevocationOperation *rop;
805   struct IdpClient *idp = cls;
806
807   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received REVOKE_TICKET message\n");
808   rop = GNUNET_new (struct TicketRevocationOperation);
809   rop->r_id = ntohl (rm->id);
810   rop->client = idp;
811   GNUNET_CONTAINER_DLL_insert (idp->revoke_op_head, idp->revoke_op_tail, rop);
812   rop->rh
813     = RECLAIM_TICKETS_revoke (&rm->ticket, &rm->identity, &revoke_result_cb,
814                               rop);
815   GNUNET_SERVICE_client_continue (idp->client);
816 }
817
818
819 /**
820  * Handle a ticket consume result
821  *
822  * @param cls our consume ticket operation handle
823  * @param identity the attribute authority
824  * @param attrs the attribute/claim list
825  * @param success GNUNET_OK if successful
826  * @param emsg error message (NULL if success=GNUNET_OK)
827  */
828 static void
829 consume_result_cb (void *cls,
830                    const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
831                    const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
832                    int32_t success,
833                    const char *emsg)
834 {
835   struct ConsumeTicketOperation *cop = cls;
836   struct ConsumeTicketResultMessage *crm;
837   struct GNUNET_MQ_Envelope *env;
838   char *data_tmp;
839   size_t attrs_len;
840
841   if (GNUNET_OK != success)
842   {
843     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error consuming ticket: %s\n", emsg);
844   }
845   attrs_len = GNUNET_RECLAIM_ATTRIBUTE_list_serialize_get_size (attrs);
846   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
847               "Sending CONSUME_TICKET_RESULT message\n");
848   env = GNUNET_MQ_msg_extra (crm,
849                              attrs_len,
850                              GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT);
851   crm->id = htonl (cop->r_id);
852   crm->attrs_len = htons (attrs_len);
853   crm->identity = *identity;
854   crm->result = htonl (success);
855   data_tmp = (char *) &crm[1];
856   GNUNET_RECLAIM_ATTRIBUTE_list_serialize (attrs, data_tmp);
857   GNUNET_MQ_send (cop->client->mq, env);
858   GNUNET_CONTAINER_DLL_remove (cop->client->consume_op_head,
859                                cop->client->consume_op_tail,
860                                cop);
861   GNUNET_free (cop);
862 }
863
864
865 /**
866  * Check a consume ticket message
867  *
868  * @param cls unused
869  * @param cm the message to handle
870  */
871 static int
872 check_consume_ticket_message (void *cls, const struct ConsumeTicketMessage *cm)
873 {
874   uint16_t size;
875
876   size = ntohs (cm->header.size);
877   if (size != sizeof(struct ConsumeTicketMessage))
878   {
879     GNUNET_break (0);
880     return GNUNET_SYSERR;
881   }
882   return GNUNET_OK;
883 }
884
885
886 /**
887  * Handle a consume ticket message
888  *
889  * @param cls our client handle
890  * @cm the message to handle
891  */
892 static void
893 handle_consume_ticket_message (void *cls, const struct ConsumeTicketMessage *cm)
894 {
895   struct ConsumeTicketOperation *cop;
896   struct IdpClient *idp = cls;
897
898   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received CONSUME_TICKET message\n");
899   cop = GNUNET_new (struct ConsumeTicketOperation);
900   cop->r_id = ntohl (cm->id);
901   cop->client = idp;
902   cop->ch
903     = RECLAIM_TICKETS_consume (&cm->identity, &cm->ticket, &consume_result_cb,
904                                cop);
905   GNUNET_CONTAINER_DLL_insert (idp->consume_op_head, idp->consume_op_tail, cop);
906   GNUNET_SERVICE_client_continue (idp->client);
907 }
908
909
910 /*****************************************
911 * Attribute store
912 *****************************************/
913
914
915 /**
916  * Attribute store result handler
917  *
918  * @param cls our attribute store handle
919  * @param success GNUNET_OK if successful
920  * @param emsg error message (NULL if success=GNUNET_OK)
921  */
922 static void
923 attr_store_cont (void *cls, int32_t success, const char *emsg)
924 {
925   struct AttributeStoreHandle *ash = cls;
926   struct GNUNET_MQ_Envelope *env;
927   struct SuccessResultMessage *acr_msg;
928
929   ash->ns_qe = NULL;
930   GNUNET_CONTAINER_DLL_remove (ash->client->store_op_head,
931                                ash->client->store_op_tail,
932                                ash);
933
934   if (GNUNET_SYSERR == success)
935   {
936     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
937                 "Failed to store attribute %s\n",
938                 emsg);
939     cleanup_as_handle (ash);
940     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
941     return;
942   }
943
944   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending SUCCESS_RESPONSE message\n");
945   env = GNUNET_MQ_msg (acr_msg, GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE);
946   acr_msg->id = htonl (ash->r_id);
947   acr_msg->op_result = htonl (GNUNET_OK);
948   GNUNET_MQ_send (ash->client->mq, env);
949   cleanup_as_handle (ash);
950 }
951
952
953 /**
954  * Add a new attribute
955  *
956  * @param cls the AttributeStoreHandle
957  */
958 static void
959 attr_store_task (void *cls)
960 {
961   struct AttributeStoreHandle *ash = cls;
962   struct GNUNET_GNSRECORD_Data rd[1];
963   char *buf;
964   char *label;
965   size_t buf_size;
966
967   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Storing attribute\n");
968   buf_size = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (ash->claim);
969   buf = GNUNET_malloc (buf_size);
970   // Give the ash a new id if unset
971   if (GNUNET_YES == GNUNET_RECLAIM_id_is_zero (&ash->claim->id))
972     GNUNET_RECLAIM_id_generate (&ash->claim->id);
973   GNUNET_RECLAIM_ATTRIBUTE_serialize (ash->claim, buf);
974   label
975     = GNUNET_STRINGS_data_to_string_alloc (&ash->claim->id,
976                                            sizeof (ash->reference->id));
977   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypting with label %s\n", label);
978
979   rd[0].data_size = buf_size;
980   rd[0].data = buf;
981   rd[0].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR;
982   rd[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
983   rd[0].expiration_time = ash->exp.rel_value_us;
984   ash->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
985                                                &ash->identity,
986                                                label,
987                                                1,
988                                                rd,
989                                                &attr_store_cont,
990                                                ash);
991   GNUNET_free (buf);
992   GNUNET_free (label);
993 }
994
995
996 /**
997  * Check an attribute store message
998  *
999  * @param cls unused
1000  * @param sam the message to check
1001  */
1002 static int
1003 check_attribute_store_message (void *cls,
1004                                const struct AttributeStoreMessage *sam)
1005 {
1006   uint16_t size;
1007
1008   size = ntohs (sam->header.size);
1009   if (size <= sizeof(struct AttributeStoreMessage))
1010   {
1011     GNUNET_break (0);
1012     return GNUNET_SYSERR;
1013   }
1014   return GNUNET_OK;
1015 }
1016
1017
1018 /**
1019  * Handle an attribute store message
1020  *
1021  * @param cls our client
1022  * @param sam the message to handle
1023  */
1024 static void
1025 handle_attribute_store_message (void *cls,
1026                                 const struct AttributeStoreMessage *sam)
1027 {
1028   struct AttributeStoreHandle *ash;
1029   struct IdpClient *idp = cls;
1030   size_t data_len;
1031
1032   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ATTRIBUTE_STORE message\n");
1033
1034   data_len = ntohs (sam->attr_len);
1035
1036   ash = GNUNET_new (struct AttributeStoreHandle);
1037   ash->claim = GNUNET_RECLAIM_ATTRIBUTE_deserialize ((char *) &sam[1],
1038                                                      data_len);
1039
1040   ash->r_id = ntohl (sam->id);
1041   ash->identity = sam->identity;
1042   ash->exp.rel_value_us = GNUNET_ntohll (sam->exp);
1043   GNUNET_CRYPTO_ecdsa_key_get_public (&sam->identity, &ash->identity_pkey);
1044
1045   GNUNET_SERVICE_client_continue (idp->client);
1046   ash->client = idp;
1047   GNUNET_CONTAINER_DLL_insert (idp->store_op_head, idp->store_op_tail, ash);
1048   GNUNET_SCHEDULER_add_now (&attr_store_task, ash);
1049 }
1050
1051
1052 /**
1053  * Attestation store result handler
1054  *
1055  * @param cls our attribute store handle
1056  * @param success GNUNET_OK if successful
1057  * @param emsg error message (NULL if success=GNUNET_OK)
1058  */
1059 static void
1060 attest_store_cont (void *cls, int32_t success, const char *emsg)
1061 {
1062   struct AttributeStoreHandle *ash = cls;
1063   struct GNUNET_MQ_Envelope *env;
1064   struct SuccessResultMessage *acr_msg;
1065
1066   ash->ns_qe = NULL;
1067   GNUNET_CONTAINER_DLL_remove (ash->client->store_op_head,
1068                                ash->client->store_op_tail,
1069                                ash);
1070
1071   if (GNUNET_SYSERR == success)
1072   {
1073     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1074                 "Failed to store attestation %s\n",
1075                 emsg);
1076     cleanup_as_handle (ash);
1077     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1078     return;
1079   }
1080
1081   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending SUCCESS_RESPONSE message\n");
1082   env = GNUNET_MQ_msg (acr_msg, GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE);
1083   acr_msg->id = htonl (ash->r_id);
1084   acr_msg->op_result = htonl (GNUNET_OK);
1085   GNUNET_MQ_send (ash->client->mq, env);
1086   cleanup_as_handle (ash);
1087 }
1088
1089
1090 /**
1091      * Send a reference error response
1092      *
1093      * @param ash our attribute store handle
1094      * @param success the success status
1095      */
1096 static void
1097 send_ref_error (struct AttributeStoreHandle  *ash)
1098 {
1099   struct GNUNET_MQ_Envelope *env;
1100   struct SuccessResultMessage *acr_msg;
1101
1102   ash->ns_qe = NULL;
1103   GNUNET_CONTAINER_DLL_remove (ash->client->store_op_head,
1104                                ash->client->store_op_tail,
1105                                ash);
1106
1107   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending SUCCESS_RESPONSE message\n");
1108   env = GNUNET_MQ_msg (acr_msg, GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE);
1109   acr_msg->id = htonl (ash->r_id);
1110   acr_msg->op_result = htonl (GNUNET_SYSERR);
1111   GNUNET_MQ_send (ash->client->mq, env);
1112   cleanup_as_handle (ash);
1113 }
1114
1115
1116 /**
1117  * Error looking up potential attestation. Abort.
1118  *
1119  * @param cls our attribute store handle
1120  */
1121 static void
1122 attest_error (void *cls)
1123 {
1124   struct AttributeStoreHandle *ash = cls;
1125   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1126               "Failed to check for existing Attestation\n");
1127   cleanup_as_handle (ash);
1128   GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1129   return;
1130 }
1131
1132
1133 /**
1134 * Check for existing record before storing reference
1135 *
1136 * @param cls our attribute store handle
1137 * @param zone zone we are iterating
1138 * @param label label of the records
1139 * @param rd_count record count
1140 * @param rd records
1141 */
1142 static void
1143 attest_add_cb (void *cls,
1144                const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1145                const char *label,
1146                unsigned int rd_count,
1147                const struct GNUNET_GNSRECORD_Data *rd)
1148 {
1149   struct AttributeStoreHandle *ash = cls;
1150   char *buf;
1151   size_t buf_size;
1152   buf_size = GNUNET_RECLAIM_ATTESTATION_serialize_get_size (ash->attest);
1153   buf = GNUNET_malloc (buf_size);
1154   GNUNET_RECLAIM_ATTESTATION_serialize (ash->attest, buf);
1155   if (0 == rd_count)
1156   {
1157     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1158                 "Storing new Attestation\n");
1159     struct GNUNET_GNSRECORD_Data rd_new[1];
1160     rd_new[0].data_size = buf_size;
1161     rd_new[0].data = buf;
1162     rd_new[0].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_ATTEST_ATTR;
1163     rd_new[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1164     rd_new[0].expiration_time = ash->exp.rel_value_us;
1165     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypting with label %s\n", label);
1166     ash->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
1167                                                  &ash->identity,
1168                                                  label,
1169                                                  1,
1170                                                  rd_new,
1171                                                  &attest_store_cont,
1172                                                  ash);
1173     GNUNET_free (buf);
1174     return;
1175   }
1176   if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTEST_ATTR != rd[0].record_type)
1177   {
1178     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1179                 "Existing Attestation location is not an Attestation\n");
1180     send_ref_error (ash);
1181     return;
1182   }
1183   struct GNUNET_GNSRECORD_Data rd_new[rd_count];
1184   for (int i = 0; i<rd_count; i++)
1185   {
1186     rd_new[i] = rd[i];
1187   }
1188   rd_new[0].data_size = buf_size;
1189   rd_new[0].data = buf;
1190   rd_new[0].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_ATTEST_ATTR;
1191   rd_new[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1192   rd_new[0].expiration_time = ash->exp.rel_value_us;
1193   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypting with label %s\n", label);
1194   ash->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
1195                                                &ash->identity,
1196                                                label,
1197                                                rd_count,
1198                                                rd_new,
1199                                                &attest_store_cont,
1200                                                ash);
1201   GNUNET_free (buf);
1202 }
1203
1204
1205 /**
1206  * Add a new attestation
1207  *
1208  * @param cls the AttributeStoreHandle
1209  */
1210 static void
1211 attest_store_task (void *cls)
1212 {
1213   struct AttributeStoreHandle *ash = cls;
1214   char *label;
1215
1216   // Give the ash a new id if unset
1217   if (GNUNET_YES == GNUNET_RECLAIM_id_is_zero (&ash->attest->id))
1218     GNUNET_RECLAIM_id_generate (&ash->attest->id);
1219   label = GNUNET_STRINGS_data_to_string_alloc (&ash->attest->id,
1220                                                sizeof (ash->attest->id));
1221   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1222               "Looking up existing data under label %s\n", label);
1223 // Test for the content of the existing ID
1224   ash->ns_qe = GNUNET_NAMESTORE_records_lookup (nsh,
1225                                                 &ash->identity,
1226                                                 label,
1227                                                 &attest_error,
1228                                                 ash,
1229                                                 &attest_add_cb,
1230                                                 ash);
1231   GNUNET_free (label);
1232 }
1233
1234
1235 /**
1236  * Check an attestation store message
1237  *
1238  * @param cls unused
1239  * @param sam the message to check
1240  */
1241 static int
1242 check_attestation_store_message (void *cls,
1243                                  const struct AttributeStoreMessage *sam)
1244 {
1245   uint16_t size;
1246
1247   size = ntohs (sam->header.size);
1248   if (size <= sizeof(struct AttributeStoreMessage))
1249   {
1250     GNUNET_break (0);
1251     return GNUNET_SYSERR;
1252   }
1253   return GNUNET_OK;
1254 }
1255
1256
1257 /**
1258 * Handle an attestation store message
1259 *
1260 * @param cls our client
1261 * @param sam the message to handle
1262 */
1263 static void
1264 handle_attestation_store_message (void *cls,
1265                                   const struct AttributeStoreMessage *sam)
1266 {
1267   struct AttributeStoreHandle *ash;
1268   struct IdpClient *idp = cls;
1269   size_t data_len;
1270
1271   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ATTESTATION_STORE message\n");
1272
1273   data_len = ntohs (sam->attr_len);
1274
1275   ash = GNUNET_new (struct AttributeStoreHandle);
1276   ash->attest = GNUNET_RECLAIM_ATTESTATION_deserialize ((char *) &sam[1],
1277                                                         data_len);
1278
1279   ash->r_id = ntohl (sam->id);
1280   ash->identity = sam->identity;
1281   ash->exp.rel_value_us = GNUNET_ntohll (sam->exp);
1282   GNUNET_CRYPTO_ecdsa_key_get_public (&sam->identity, &ash->identity_pkey);
1283
1284   GNUNET_SERVICE_client_continue (idp->client);
1285   ash->client = idp;
1286   GNUNET_CONTAINER_DLL_insert (idp->store_op_head, idp->store_op_tail, ash);
1287   GNUNET_SCHEDULER_add_now (&attest_store_task, ash);
1288 }
1289
1290
1291 /**
1292  * Error looking up potential reference value. Abort.
1293  *
1294  * @param cls our attribute store handle
1295  */
1296 static void
1297 ref_error (void *cls)
1298 {
1299   struct AttributeStoreHandle *ash = cls;
1300   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1301               "Failed to find Attestation entry for Attestation reference\n");
1302   cleanup_as_handle (ash);
1303   GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1304   return;
1305 }
1306
1307
1308 /**
1309  * Error looking up potential reference value. Abort.
1310  *
1311  * @param cls our attribute delete handle
1312  */
1313 static void
1314 ref_del_error (void *cls)
1315 {
1316   struct AttributeDeleteHandle *adh = cls;
1317   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1318               "Failed to find Attestation entry for Attestation reference\n");
1319   cleanup_adh (adh);
1320   GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1321   return;
1322 }
1323
1324
1325 /**
1326 * Reference store result handler
1327 *
1328 * @param cls our attribute store handle
1329 * @param success GNUNET_OK if successful
1330 * @param emsg error message (NULL if success=GNUNET_OK)
1331 */
1332 static void
1333 reference_store_cont (void *cls, int32_t success, const char *emsg)
1334 {
1335   struct AttributeStoreHandle *ash = cls;
1336   struct GNUNET_MQ_Envelope *env;
1337   struct SuccessResultMessage *acr_msg;
1338
1339   ash->ns_qe = NULL;
1340   GNUNET_CONTAINER_DLL_remove (ash->client->store_op_head,
1341                                ash->client->store_op_tail,
1342                                ash);
1343
1344   if (GNUNET_SYSERR == success)
1345   {
1346     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1347                 "Failed to store reference %s\n",
1348                 emsg);
1349     cleanup_as_handle (ash);
1350     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1351     return;
1352   }
1353
1354   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending SUCCESS_RESPONSE message\n");
1355   env = GNUNET_MQ_msg (acr_msg, GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE);
1356   acr_msg->id = htonl (ash->r_id);
1357   acr_msg->op_result = htonl (GNUNET_OK);
1358   GNUNET_MQ_send (ash->client->mq, env);
1359   cleanup_as_handle (ash);
1360 }
1361
1362
1363 /**
1364 * Check for existing record before storing reference
1365 *
1366 * @param cls our attribute store handle
1367 * @param zone zone we are iterating
1368 * @param label label of the records
1369 * @param rd_count record count
1370 * @param rd records
1371 */
1372 static void
1373 ref_add_cb (void *cls,
1374             const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1375             const char *label,
1376             unsigned int rd_count,
1377             const struct GNUNET_GNSRECORD_Data *rd)
1378 {
1379   struct AttributeStoreHandle *ash = cls;
1380   char *buf;
1381   size_t buf_size;
1382   buf_size = GNUNET_RECLAIM_ATTESTATION_REF_serialize_get_size (ash->reference);
1383   buf = GNUNET_malloc (buf_size);
1384   GNUNET_RECLAIM_ATTESTATION_REF_serialize (ash->reference, buf);
1385   struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *ref;
1386   char *data_tmp;
1387   if (0 == rd_count)
1388   {
1389     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1390                 "Failed to find Attestation entry for Attestation reference\n");
1391     send_ref_error (ash);
1392     return;
1393   }
1394   if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTEST_ATTR != rd[0].record_type)
1395   {
1396     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1397                 "Intended Reference storage location is not an attestation\n");
1398     send_ref_error (ash);
1399     return;
1400   }
1401   struct GNUNET_GNSRECORD_Data rd_new[rd_count + 1];
1402   int i;
1403   for (i = 0; i<rd_count; i++)
1404   {
1405     data_tmp = GNUNET_malloc (rd[i].data_size);
1406     GNUNET_memcpy (data_tmp, rd[i].data, rd[i].data_size);
1407     ref = GNUNET_RECLAIM_ATTESTATION_REF_deserialize (data_tmp, htons (
1408                                                         rd[i].data_size));
1409     rd_new[i] = rd[i];
1410     if ((strcmp (ash->reference->name,ref->name) == 0) &&
1411         (strcmp (ash->reference->reference_value,ref->reference_value)==0) )
1412     {
1413       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1414                   "Reference already stored\n");
1415       reference_store_cont (ash,GNUNET_OK, NULL);
1416       return;
1417     }
1418   }
1419   rd_new[rd_count].data_size = buf_size;
1420   rd_new[rd_count].data = buf;
1421   rd_new[rd_count].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_REFERENCE;
1422   rd_new[rd_count].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1423   rd_new[rd_count].expiration_time = ash->exp.rel_value_us;
1424   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypting with label %s\n", label);
1425   ash->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
1426                                                &ash->identity,
1427                                                label,
1428                                                rd_count + 1,
1429                                                rd_new,
1430                                                &reference_store_cont,
1431                                                ash);
1432   GNUNET_free (buf);
1433 }
1434
1435
1436 /**
1437  * Add a new reference
1438  *
1439  * @param cls the AttributeStoreHandle
1440  */
1441 static void
1442 reference_store_task (void *cls)
1443 {
1444   struct AttributeStoreHandle *ash = cls;
1445   char *label;
1446
1447   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Storing reference\n");
1448
1449   // Give the ash a new id if unset
1450   if (GNUNET_YES == GNUNET_RECLAIM_id_is_zero (&ash->reference->id))
1451   {
1452     if (GNUNET_YES == GNUNET_RECLAIM_id_is_zero (&ash->reference->id_attest))
1453     {
1454       GNUNET_RECLAIM_id_generate (&ash->reference->id);
1455     }
1456     else
1457     {
1458       ash->reference->id = ash->reference->id_attest;
1459     }
1460   }
1461
1462   label = GNUNET_STRINGS_data_to_string_alloc (&ash->reference->id,
1463                                                sizeof (ash->reference->id));
1464   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1465               "Looking up existing data under label %s\n", label);
1466 // Test for the content of the existing ID
1467
1468   ash->ns_qe = GNUNET_NAMESTORE_records_lookup (nsh,
1469                                                 &ash->identity,
1470                                                 label,
1471                                                 &ref_error,
1472                                                 ash,
1473                                                 &ref_add_cb,
1474                                                 ash);
1475   GNUNET_free (label);
1476 }
1477
1478
1479 /**
1480      * Check an attestation reference store message
1481      *
1482      * @param cls unused
1483      * @param sam the message to check
1484      */
1485 static int
1486 check_reference_store_message (void *cls,
1487                                const struct
1488                                AttributeStoreMessage *sam)
1489 {
1490   uint16_t size;
1491
1492   size = ntohs (sam->header.size);
1493   if (size <= sizeof(struct AttributeStoreMessage))
1494   {
1495     GNUNET_break (0);
1496     return GNUNET_SYSERR;
1497   }
1498   return GNUNET_OK;
1499 }
1500
1501
1502 /**
1503     * Handle an attestation reference store message
1504     *
1505     * @param cls our client
1506     * @param sam the message to handle
1507     */
1508 static void
1509 handle_reference_store_message (void *cls,
1510                                 const struct AttributeStoreMessage *sam)
1511 {
1512   struct AttributeStoreHandle *ash;
1513   struct IdpClient *idp = cls;
1514   size_t data_len;
1515
1516   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received REFERENCE_STORE message\n");
1517
1518   data_len = ntohs (sam->attr_len);
1519   ash = GNUNET_new (struct AttributeStoreHandle);
1520   ash->reference = GNUNET_RECLAIM_ATTESTATION_REF_deserialize ((char *) &sam[1],
1521                                                                data_len);
1522   ash->r_id = ntohl (sam->id);
1523   ash->identity = sam->identity;
1524   ash->exp.rel_value_us = GNUNET_ntohll (sam->exp);
1525   GNUNET_CRYPTO_ecdsa_key_get_public (&sam->identity, &ash->identity_pkey);
1526
1527
1528   GNUNET_SERVICE_client_continue (idp->client);
1529   ash->client = idp;
1530   GNUNET_CONTAINER_DLL_insert (idp->store_op_head, idp->store_op_tail, ash);
1531   GNUNET_SCHEDULER_add_now (&reference_store_task, ash);
1532 }
1533
1534
1535 /**
1536  * Send a deletion success response
1537  *
1538  * @param adh our attribute deletion handle
1539  * @param success the success status
1540  */
1541 static void
1542 send_delete_response (struct AttributeDeleteHandle *adh, int32_t success)
1543 {
1544   struct GNUNET_MQ_Envelope *env;
1545   struct SuccessResultMessage *acr_msg;
1546
1547   GNUNET_CONTAINER_DLL_remove (adh->client->delete_op_head,
1548                                adh->client->delete_op_tail,
1549                                adh);
1550
1551   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending SUCCESS_RESPONSE message\n");
1552   env = GNUNET_MQ_msg (acr_msg, GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE);
1553   acr_msg->id = htonl (adh->r_id);
1554   acr_msg->op_result = htonl (success);
1555   GNUNET_MQ_send (adh->client->mq, env);
1556 }
1557
1558
1559 /**
1560  * Namestore iteration within attribute deletion.
1561  * We need to reissue tickets with the deleted attribute removed.
1562  *
1563  * @param cls our attribute deletion handle
1564  * @param zone the private key of the ticket issuer
1565  * @param label the label of the record
1566  * @param rd_count number of records
1567  * @param rd record data
1568  */
1569 static void
1570 ticket_iter (void *cls,
1571              const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1572              const char *label,
1573              unsigned int rd_count,
1574              const struct GNUNET_GNSRECORD_Data *rd)
1575 {
1576   struct AttributeDeleteHandle *adh = cls;
1577   struct TicketRecordsEntry *le;
1578   int has_changed = GNUNET_NO;
1579   for (int i = 0; i < rd_count; i++)
1580   {
1581     if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
1582       continue;
1583     if (adh->claim != NULL)
1584       if (GNUNET_YES != GNUNET_RECLAIM_id_is_equal (rd[i].data,
1585                                                     &adh->claim->id))
1586         continue;
1587     if (adh->attest != NULL)
1588       if (GNUNET_YES != GNUNET_RECLAIM_id_is_equal (rd[i].data,
1589                                                     &adh->attest->id))
1590         continue;
1591     if (adh->reference != NULL)
1592       if (GNUNET_YES != GNUNET_RECLAIM_id_is_equal (rd[i].data,
1593                                                     &adh->reference->id))
1594         continue;
1595     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1596                 "Attribute or Attestation/Reference to delete found (%s)\n",
1597                 adh->label);
1598     has_changed = GNUNET_YES;
1599     break;
1600   }
1601   if (GNUNET_YES == has_changed)
1602   {
1603     le = GNUNET_new (struct TicketRecordsEntry);
1604     le->data_size = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
1605     le->data = GNUNET_malloc (le->data_size);
1606     le->rd_count = rd_count;
1607     le->label = GNUNET_strdup (label);
1608     GNUNET_GNSRECORD_records_serialize (rd_count, rd, le->data_size, le->data);
1609     GNUNET_CONTAINER_DLL_insert (adh->tickets_to_update_head,
1610                                  adh->tickets_to_update_tail,
1611                                  le);
1612   }
1613   GNUNET_NAMESTORE_zone_iterator_next (adh->ns_it, 1);
1614 }
1615
1616
1617 /**
1618  * Recursion prototype for function
1619  * @param cls our deletion handle
1620  */
1621 static void
1622 update_tickets (void *cls);
1623
1624
1625 /**
1626  * Callback called when a ticket was updated
1627  *
1628  * @param cls our attribute deletion handle
1629  * @param success GNUNET_OK if successful
1630  * @param emsg error message (NULL if success=GNUNET_OK)
1631  */
1632 static void
1633 ticket_updated (void *cls, int32_t success, const char *emsg)
1634 {
1635   struct AttributeDeleteHandle *adh = cls;
1636
1637   adh->ns_qe = NULL;
1638   GNUNET_SCHEDULER_add_now (&update_tickets, adh);
1639 }
1640
1641
1642 /**
1643  * Update tickets: Remove shared attribute which has just been deleted.
1644  * This method is called recursively until all tickets are processed.
1645  * Eventually, the updated tickets are stored using ``update_tickets''.
1646  *
1647  * @param cls our attribute deletion handle
1648  */
1649 static void
1650 update_tickets (void *cls)
1651 {
1652   struct AttributeDeleteHandle *adh = cls;
1653   struct TicketRecordsEntry *le;
1654
1655   if (NULL == adh->tickets_to_update_head)
1656   {
1657     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1658                 "Finished updating tickets, success\n");
1659     send_delete_response (adh, GNUNET_OK);
1660     cleanup_adh (adh);
1661     return;
1662   }
1663   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1664               "Updating %s\n",
1665               adh->tickets_to_update_head->label);
1666   le = adh->tickets_to_update_head;
1667   GNUNET_CONTAINER_DLL_remove (adh->tickets_to_update_head,
1668                                adh->tickets_to_update_tail,
1669                                le);
1670   struct GNUNET_GNSRECORD_Data rd[le->rd_count];
1671   struct GNUNET_GNSRECORD_Data rd_new[le->rd_count - 1];
1672   if (GNUNET_OK != GNUNET_GNSRECORD_records_deserialize (le->data_size,
1673                                                          le->data,
1674                                                          le->rd_count,
1675                                                          rd))
1676   {
1677     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1678                 "Unable to deserialize record data!\n");
1679     send_delete_response (adh, GNUNET_SYSERR);
1680     cleanup_adh (adh);
1681     return;
1682   }
1683   int j = 0;
1684   for (int i = 0; i < le->rd_count; i++)
1685   {
1686     if (adh->claim != NULL)
1687       if ((GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF == rd[i].record_type)
1688           && (GNUNET_YES == GNUNET_RECLAIM_id_is_equal (rd[i].data,
1689                                                         &adh->claim->id)))
1690         continue;
1691     if (adh->attest != NULL)
1692       if ((GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF == rd[i].record_type)
1693           && (GNUNET_YES == GNUNET_RECLAIM_id_is_equal (rd[i].data,
1694                                                         &adh->attest->id)))
1695         continue;
1696     if (adh->reference != NULL)
1697       if ((GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF == rd[i].record_type)
1698           && (GNUNET_YES == GNUNET_RECLAIM_id_is_equal (rd[i].data,
1699                                                         &adh->reference->id)))
1700         continue;
1701     rd_new[j] = rd[i];
1702     j++;
1703   }
1704   adh->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
1705                                                &adh->identity,
1706                                                le->label,
1707                                                j,
1708                                                rd_new,
1709                                                &ticket_updated,
1710                                                adh);
1711   GNUNET_free (le->label);
1712   GNUNET_free (le->data);
1713   GNUNET_free (le);
1714 }
1715
1716
1717 /**
1718  * Done collecting affected tickets, start updating.
1719  *
1720  * @param cls our attribute deletion handle
1721  */
1722 static void
1723 ticket_iter_fin (void *cls)
1724 {
1725   struct AttributeDeleteHandle *adh = cls;
1726   adh->ns_it = NULL;
1727   GNUNET_SCHEDULER_add_now (&update_tickets, adh);
1728 }
1729
1730
1731 /**
1732  * Error collecting affected tickets. Abort.
1733  *
1734  * @param cls our attribute deletion handle
1735  */
1736 static void
1737 ticket_iter_err (void *cls)
1738 {
1739   struct AttributeDeleteHandle *adh = cls;
1740
1741   adh->ns_it = NULL;
1742   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1743               "Namestore error on delete %s\n",
1744               adh->label);
1745   send_delete_response (adh, GNUNET_SYSERR);
1746   cleanup_adh (adh);
1747 }
1748
1749
1750 /**
1751  * Start processing tickets which may still contain reference to deleted
1752  * attribute.
1753  *
1754  * @param cls attribute deletion handle
1755  */
1756 static void
1757 start_ticket_update (void *cls)
1758 {
1759   struct AttributeDeleteHandle *adh = cls;
1760
1761   adh->ns_it = GNUNET_NAMESTORE_zone_iteration_start (nsh,
1762                                                       &adh->identity,
1763                                                       &ticket_iter_err,
1764                                                       adh,
1765                                                       &ticket_iter,
1766                                                       adh,
1767                                                       &ticket_iter_fin,
1768                                                       adh);
1769 }
1770
1771
1772 /**
1773  * Attribute deleted callback
1774  *
1775  * @param cls our handle
1776  * @param success success status
1777  * @param emsg error message (NULL if success=GNUNET_OK)
1778  */
1779 static void
1780 attr_delete_cont (void *cls, int32_t success, const char *emsg)
1781 {
1782   struct AttributeDeleteHandle *adh = cls;
1783
1784   adh->ns_qe = NULL;
1785   if (GNUNET_SYSERR == success)
1786   {
1787     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1788                 "Error deleting attribute %s\n",
1789                 adh->label);
1790     send_delete_response (adh, GNUNET_SYSERR);
1791     cleanup_adh (adh);
1792     return;
1793   }
1794   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating tickets...\n");
1795   GNUNET_SCHEDULER_add_now (&start_ticket_update, adh);
1796 }
1797
1798
1799 /**
1800  * Check attribute delete message format
1801  *
1802  * @cls unused
1803  * @dam message to check
1804  */
1805 static int
1806 check_attribute_delete_message (void *cls,
1807                                 const struct AttributeDeleteMessage *dam)
1808 {
1809   uint16_t size;
1810
1811   size = ntohs (dam->header.size);
1812   if (size <= sizeof(struct AttributeDeleteMessage))
1813   {
1814     GNUNET_break (0);
1815     return GNUNET_SYSERR;
1816   }
1817   return GNUNET_OK;
1818 }
1819
1820
1821 /**
1822  * Handle attribute deletion
1823  *
1824  * @param cls our client
1825  * @param dam deletion message
1826  */
1827 static void
1828 handle_attribute_delete_message (void *cls,
1829                                  const struct AttributeDeleteMessage *dam)
1830 {
1831   struct AttributeDeleteHandle *adh;
1832   struct IdpClient *idp = cls;
1833   size_t data_len;
1834
1835   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ATTRIBUTE_DELETE message\n");
1836
1837   data_len = ntohs (dam->attr_len);
1838
1839   adh = GNUNET_new (struct AttributeDeleteHandle);
1840   adh->claim = GNUNET_RECLAIM_ATTRIBUTE_deserialize ((char *) &dam[1],
1841                                                      data_len);
1842   adh->reference = NULL;
1843   adh->attest = NULL;
1844
1845   adh->r_id = ntohl (dam->id);
1846   adh->identity = dam->identity;
1847   adh->label
1848     = GNUNET_STRINGS_data_to_string_alloc (&adh->claim->id,
1849                                            sizeof(adh->claim->id));
1850   GNUNET_SERVICE_client_continue (idp->client);
1851   adh->client = idp;
1852   GNUNET_CONTAINER_DLL_insert (idp->delete_op_head, idp->delete_op_tail, adh);
1853   adh->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
1854                                                &adh->identity,
1855                                                adh->label,
1856                                                0,
1857                                                NULL,
1858                                                &attr_delete_cont,
1859                                                adh);
1860 }
1861
1862
1863 /**
1864    * Attestation deleted callback
1865    *
1866    * @param cls our handle
1867    * @param success success status
1868    * @param emsg error message (NULL if success=GNUNET_OK)
1869    */
1870 static void
1871 attest_delete_cont (void *cls, int32_t success, const char *emsg)
1872 {
1873   struct AttributeDeleteHandle *adh = cls;
1874
1875   adh->ns_qe = NULL;
1876   if (GNUNET_SYSERR == success)
1877   {
1878     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1879                 "Error deleting attestation %s\n",
1880                 adh->label);
1881     send_delete_response (adh, GNUNET_SYSERR);
1882     cleanup_adh (adh);
1883     return;
1884   }
1885   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating tickets...\n");
1886   GNUNET_SCHEDULER_add_now (&start_ticket_update, adh);
1887 }
1888
1889
1890 /**
1891  * Check attestation delete message format
1892  *
1893  * @cls unused
1894  * @dam message to check
1895  */
1896 static int
1897 check_attestation_delete_message (void *cls,
1898                                   const struct AttributeDeleteMessage *dam)
1899 {
1900   uint16_t size;
1901
1902   size = ntohs (dam->header.size);
1903   if (size <= sizeof(struct AttributeDeleteMessage))
1904   {
1905     GNUNET_break (0);
1906     return GNUNET_SYSERR;
1907   }
1908   return GNUNET_OK;
1909 }
1910
1911
1912 /**
1913  * Handle attestation deletion
1914  *
1915  * @param cls our client
1916  * @param dam deletion message
1917  */
1918 static void
1919 handle_attestation_delete_message (void *cls,
1920                                    const struct AttributeDeleteMessage *dam)
1921 {
1922   struct AttributeDeleteHandle *adh;
1923   struct IdpClient *idp = cls;
1924   size_t data_len;
1925
1926   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ATTESTATION_DELETE message\n");
1927
1928   data_len = ntohs (dam->attr_len);
1929
1930   adh = GNUNET_new (struct AttributeDeleteHandle);
1931   adh->attest = GNUNET_RECLAIM_ATTESTATION_deserialize ((char *) &dam[1],
1932                                                         data_len);
1933   adh->reference = NULL;
1934   adh->claim = NULL;
1935
1936   adh->r_id = ntohl (dam->id);
1937   adh->identity = dam->identity;
1938   adh->label
1939     = GNUNET_STRINGS_data_to_string_alloc (&adh->attest->id,
1940                                            sizeof(adh->attest->id));
1941   GNUNET_SERVICE_client_continue (idp->client);
1942   adh->client = idp;
1943   GNUNET_CONTAINER_DLL_insert (idp->delete_op_head, idp->delete_op_tail, adh);
1944   adh->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
1945                                                &adh->identity,
1946                                                adh->label,
1947                                                0,
1948                                                NULL,
1949                                                &attest_delete_cont,
1950                                                adh);
1951 }
1952
1953
1954 /**
1955 * Reference deleted callback
1956 *
1957 * @param cls our handle
1958 * @param success success status
1959 * @param emsg error message (NULL if success=GNUNET_OK)
1960 */
1961 static void
1962 reference_delete_cont (void *cls, int32_t success, const char *emsg)
1963 {
1964   struct AttributeDeleteHandle *adh = cls;
1965
1966   adh->ns_qe = NULL;
1967   if (GNUNET_SYSERR == success)
1968   {
1969     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1970                 "Error deleting reference %s\n",
1971                 adh->label);
1972     send_delete_response (adh, GNUNET_SYSERR);
1973     cleanup_adh (adh);
1974     return;
1975   }
1976   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating tickets...\n");
1977   // GNUNET_SCHEDULER_add_now (&start_ticket_update, adh);
1978   send_delete_response (adh, GNUNET_OK);
1979   cleanup_adh (adh);
1980   return;
1981 }
1982
1983
1984 static void
1985 ref_del_cb (void *cls,
1986             const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1987             const char *label,
1988             unsigned int rd_count,
1989             const struct GNUNET_GNSRECORD_Data *rd)
1990 {
1991
1992   struct AttributeDeleteHandle *adh = cls;
1993   char *data_tmp;
1994   struct GNUNET_GNSRECORD_Data rd_new[rd_count - 1];
1995   struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *ref;
1996   size_t attr_len;
1997
1998   if (0 == rd_count)
1999   {
2000     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2001                 "Failed to find Attestation entry for Attestation reference\n");
2002     cleanup_adh (adh);
2003     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
2004     return;
2005   }
2006   if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTEST_ATTR != rd[0].record_type)
2007   {
2008     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2009                 "Intended Reference location is not an attestation\n");
2010     cleanup_adh (adh);
2011     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
2012     return;
2013   }
2014   rd_new[0] = rd[0];
2015   int i;
2016   int j = 1;
2017   for (i = 1; i<rd_count; i++)
2018   {
2019     data_tmp = GNUNET_malloc (rd[i].data_size);
2020     GNUNET_memcpy (data_tmp, rd[i].data, rd[i].data_size);
2021     attr_len = htons (rd[i].data_size);
2022     ref = GNUNET_RECLAIM_ATTESTATION_REF_deserialize (data_tmp, attr_len);
2023     if (NULL == ref)
2024     {
2025       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2026                   "Unable to parse attestation reference from %s\n",
2027                   data_tmp);
2028       rd_new[j] = rd[i];
2029       j += 1;
2030       continue;
2031     }
2032     if ((strcmp (adh->reference->name,ref->name) == 0) &&
2033         (strcmp (adh->reference->reference_value,ref->reference_value)==0) )
2034     {
2035       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2036                   "Found reference to delete.\n");
2037     }
2038     else
2039     {
2040       rd_new[j] = rd[i];
2041       j += 1;
2042     }
2043     GNUNET_free (data_tmp);
2044   }
2045   adh->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
2046                                                &adh->identity,
2047                                                label,
2048                                                j,
2049                                                rd_new,
2050                                                &reference_delete_cont,
2051                                                adh);
2052 }
2053
2054
2055 /**
2056  * Check an attestation reference delete message
2057  *
2058  * @param cls unused
2059  * @param sam the message to check
2060  */
2061 static int
2062 check_reference_delete_message (void *cls,
2063                                 const struct AttributeDeleteMessage *dam)
2064 {
2065   uint16_t size;
2066
2067   size = ntohs (dam->header.size);
2068   if (size <= sizeof(struct AttributeDeleteMessage))
2069   {
2070     GNUNET_break (0);
2071     return GNUNET_SYSERR;
2072   }
2073   return GNUNET_OK;
2074 }
2075
2076
2077 /**
2078  * Handle reference deletion
2079  *
2080  * @param cls our client
2081  * @param dam deletion message
2082  */
2083 static void
2084 handle_reference_delete_message (void *cls,
2085                                  const struct AttributeDeleteMessage *dam)
2086 {
2087   struct AttributeDeleteHandle *adh;
2088   struct IdpClient *idp = cls;
2089   size_t data_len;
2090
2091   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received REFERENCE_DELETE message\n");
2092   data_len = ntohs (dam->attr_len);
2093   adh = GNUNET_new (struct AttributeDeleteHandle);
2094   adh->reference = GNUNET_RECLAIM_ATTESTATION_REF_deserialize ((char *) &dam[1],
2095                                                                data_len);
2096   adh->attest = NULL;
2097   adh->claim = NULL;
2098
2099   adh->r_id = ntohl (dam->id);
2100   adh->identity = dam->identity;
2101   adh->label
2102     = GNUNET_STRINGS_data_to_string_alloc (&adh->reference->id,
2103                                            sizeof(adh->reference->id));
2104   GNUNET_SERVICE_client_continue (idp->client);
2105   adh->client = idp;
2106   GNUNET_CONTAINER_DLL_insert (idp->delete_op_head, idp->delete_op_tail, adh);
2107   adh->ns_qe = GNUNET_NAMESTORE_records_lookup (nsh,
2108                                                 &adh->identity,
2109                                                 adh->label,
2110                                                 &ref_del_error,
2111                                                 adh,
2112                                                 &ref_del_cb,
2113                                                 adh);
2114 }
2115
2116
2117 /*************************************************
2118 * Attrubute iteration
2119 *************************************************/
2120
2121
2122 /**
2123  * Done iterating over attributes
2124  *
2125  * @param cls our iterator handle
2126  */
2127 static void
2128 attr_iter_finished (void *cls)
2129 {
2130   struct AttributeIterator *ai = cls;
2131   struct GNUNET_MQ_Envelope *env;
2132   struct AttributeResultMessage *arm;
2133
2134   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending ATTRIBUTE_RESULT message\n");
2135   env = GNUNET_MQ_msg (arm, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT);
2136   arm->id = htonl (ai->request_id);
2137   arm->attr_len = htons (0);
2138   GNUNET_MQ_send (ai->client->mq, env);
2139   GNUNET_CONTAINER_DLL_remove (ai->client->attr_iter_head,
2140                                ai->client->attr_iter_tail,
2141                                ai);
2142   GNUNET_free (ai);
2143 }
2144
2145
2146 /**
2147  * Error iterating over attributes. Abort.
2148  *
2149  * @param cls our attribute iteration handle
2150  */
2151 static void
2152 attr_iter_error (void *cls)
2153 {
2154   struct AttributeIterator *ai = cls;
2155
2156   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to iterate over attributes\n");
2157   attr_iter_finished (ai);
2158 }
2159
2160
2161 /**
2162  * Got record. Return if it is an attribute or attestation/reference.
2163  *
2164  * @param cls our attribute iterator
2165  * @param zone zone we are iterating
2166  * @param label label of the records
2167  * @param rd_count record count
2168  * @param rd records
2169  */
2170 static void
2171 attr_iter_cb (void *cls,
2172               const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
2173               const char *label,
2174               unsigned int rd_count,
2175               const struct GNUNET_GNSRECORD_Data *rd)
2176 {
2177   struct AttributeIterator *ai = cls;
2178   struct GNUNET_MQ_Envelope *env;
2179   char *data_tmp;
2180
2181   if (rd_count == 0)
2182   {
2183     GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1);
2184     return;
2185   }
2186   if (rd_count > 1)
2187   {
2188     if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF == rd[0].record_type)
2189     {
2190       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2191                   "Found Ticket. Ignoring.\n");
2192       GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1);
2193       return;
2194     }
2195     else if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTEST_ATTR != rd[0].record_type)
2196     {
2197       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2198                   "Non-Attestation record with multiple entries found: %u\n",
2199                   rd[0].record_type);
2200       GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1);
2201       return;
2202     }
2203   }
2204
2205   for (int i = 0; i<rd_count; i++)
2206   {
2207     if ((GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR != rd[i].record_type) &&
2208         (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTEST_ATTR != rd[i].record_type) &&
2209         (GNUNET_GNSRECORD_TYPE_RECLAIM_REFERENCE != rd[i].record_type))
2210     {
2211       GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1);
2212       return;
2213     }
2214
2215     if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR == rd[i].record_type)
2216     {
2217       struct AttributeResultMessage *arm;
2218       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found attribute under: %s\n",
2219                   label);
2220       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2221                   "Sending ATTRIBUTE_RESULT message\n");
2222       env = GNUNET_MQ_msg_extra (arm,
2223                                  rd[i].data_size,
2224                                  GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT);
2225       arm->id = htonl (ai->request_id);
2226       arm->attr_len = htons (rd[i].data_size);
2227       GNUNET_CRYPTO_ecdsa_key_get_public (zone, &arm->identity);
2228       data_tmp = (char *) &arm[1];
2229       GNUNET_memcpy (data_tmp, rd[i].data, rd[i].data_size);
2230       GNUNET_MQ_send (ai->client->mq, env);
2231     }
2232     else
2233     {
2234       if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTEST_ATTR == rd[i].record_type)
2235       {
2236         struct AttributeResultMessage *arm;
2237         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found attestation under: %s\n",
2238                     label);
2239         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2240                     "Sending ATTESTATION_RESULT message\n");
2241         env = GNUNET_MQ_msg_extra (arm,
2242                                    rd[i].data_size,
2243                                    GNUNET_MESSAGE_TYPE_RECLAIM_ATTESTATION_RESULT);
2244         arm->id = htonl (ai->request_id);
2245         arm->attr_len = htons (rd[i].data_size);
2246         GNUNET_CRYPTO_ecdsa_key_get_public (zone, &arm->identity);
2247         data_tmp = (char *) &arm[1];
2248         GNUNET_memcpy (data_tmp, rd[i].data, rd[i].data_size);
2249         GNUNET_MQ_send (ai->client->mq, env);
2250       }
2251       else
2252       {
2253         struct ReferenceResultMessage *rrm;
2254         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found reference under: %s\n",
2255                     label);
2256         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2257                     "Sending REFERENCE_RESULT message\n");
2258         env = GNUNET_MQ_msg_extra (rrm,
2259                                    rd[i].data_size + rd[0].data_size,
2260                                    GNUNET_MESSAGE_TYPE_RECLAIM_REFERENCE_RESULT);
2261         rrm->id = htonl (ai->request_id);
2262         rrm->attest_len = htons (rd[0].data_size);
2263         rrm->ref_len = htons (rd[i].data_size);
2264         GNUNET_CRYPTO_ecdsa_key_get_public (zone, &rrm->identity);
2265         data_tmp = (char *) &rrm[1];
2266         GNUNET_memcpy (data_tmp, rd[0].data, rd[0].data_size);
2267         data_tmp += rd[0].data_size;
2268         GNUNET_memcpy (data_tmp, rd[i].data, rd[i].data_size);
2269         GNUNET_MQ_send (ai->client->mq, env);
2270       }
2271     }
2272   }
2273 }
2274
2275
2276 /**
2277  * Iterate over zone to get attributes
2278  *
2279  * @param cls our client
2280  * @param ais_msg the iteration message to start
2281  */
2282 static void
2283 handle_iteration_start (void *cls,
2284                         const struct AttributeIterationStartMessage *ais_msg)
2285 {
2286   struct IdpClient *idp = cls;
2287   struct AttributeIterator *ai;
2288
2289   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2290               "Received ATTRIBUTE_ITERATION_START message\n");
2291   ai = GNUNET_new (struct AttributeIterator);
2292   ai->request_id = ntohl (ais_msg->id);
2293   ai->client = idp;
2294   ai->identity = ais_msg->identity;
2295
2296   GNUNET_CONTAINER_DLL_insert (idp->attr_iter_head, idp->attr_iter_tail, ai);
2297   ai->ns_it = GNUNET_NAMESTORE_zone_iteration_start (nsh,
2298                                                      &ai->identity,
2299                                                      &attr_iter_error,
2300                                                      ai,
2301                                                      &attr_iter_cb,
2302                                                      ai,
2303                                                      &attr_iter_finished,
2304                                                      ai);
2305   GNUNET_SERVICE_client_continue (idp->client);
2306 }
2307
2308
2309 /**
2310  * Handle iteration stop message from client
2311  *
2312  * @param cls the client
2313  * @param ais_msg the stop message
2314  */
2315 static void
2316 handle_iteration_stop (void *cls,
2317                        const struct AttributeIterationStopMessage *ais_msg)
2318 {
2319   struct IdpClient *idp = cls;
2320   struct AttributeIterator *ai;
2321   uint32_t rid;
2322
2323   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2324               "Received `%s' message\n",
2325               "ATTRIBUTE_ITERATION_STOP");
2326   rid = ntohl (ais_msg->id);
2327   for (ai = idp->attr_iter_head; NULL != ai; ai = ai->next)
2328     if (ai->request_id == rid)
2329       break;
2330   if (NULL == ai)
2331   {
2332     GNUNET_break (0);
2333     GNUNET_SERVICE_client_drop (idp->client);
2334     return;
2335   }
2336   GNUNET_CONTAINER_DLL_remove (idp->attr_iter_head, idp->attr_iter_tail, ai);
2337   GNUNET_free (ai);
2338   GNUNET_SERVICE_client_continue (idp->client);
2339 }
2340
2341
2342 /**
2343  * Client requests next attribute from iterator
2344  *
2345  * @param cls the client
2346  * @param ais_msg the message
2347  */
2348 static void
2349 handle_iteration_next (void *cls,
2350                        const struct AttributeIterationNextMessage *ais_msg)
2351 {
2352   struct IdpClient *idp = cls;
2353   struct AttributeIterator *ai;
2354   uint32_t rid;
2355
2356   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2357               "Received ATTRIBUTE_ITERATION_NEXT message\n");
2358   rid = ntohl (ais_msg->id);
2359   for (ai = idp->attr_iter_head; NULL != ai; ai = ai->next)
2360     if (ai->request_id == rid)
2361       break;
2362   if (NULL == ai)
2363   {
2364     GNUNET_break (0);
2365     GNUNET_SERVICE_client_drop (idp->client);
2366     return;
2367   }
2368   GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1);
2369   GNUNET_SERVICE_client_continue (idp->client);
2370 }
2371
2372
2373 /******************************************************
2374 * Ticket iteration
2375 ******************************************************/
2376
2377 /**
2378  * Got a ticket. Return to client
2379  *
2380  * @param cls our ticket iterator
2381  * @param ticket the ticket
2382  */
2383 static void
2384 ticket_iter_cb (void *cls, struct GNUNET_RECLAIM_Ticket *ticket)
2385 {
2386   struct TicketIteration *ti = cls;
2387   struct GNUNET_MQ_Envelope *env;
2388   struct TicketResultMessage *trm;
2389
2390   env = GNUNET_MQ_msg (trm, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT);
2391   if (NULL == ticket)
2392   {
2393     /* send empty response to indicate end of list */
2394     GNUNET_CONTAINER_DLL_remove (ti->client->ticket_iter_head,
2395                                  ti->client->ticket_iter_tail,
2396                                  ti);
2397   }
2398   else
2399   {
2400     trm->ticket = *ticket;
2401   }
2402   trm->id = htonl (ti->r_id);
2403   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending TICKET_RESULT message\n");
2404   GNUNET_MQ_send (ti->client->mq, env);
2405   if (NULL == ticket)
2406     GNUNET_free (ti);
2407 }
2408
2409
2410 /**
2411  * Client requests a ticket iteration
2412  *
2413  * @param cls the client
2414  * @param tis_msg the iteration request message
2415  */
2416 static void
2417 handle_ticket_iteration_start (
2418   void *cls,
2419   const struct TicketIterationStartMessage *tis_msg)
2420 {
2421   struct IdpClient *client = cls;
2422   struct TicketIteration *ti;
2423
2424   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2425               "Received TICKET_ITERATION_START message\n");
2426   ti = GNUNET_new (struct TicketIteration);
2427   ti->r_id = ntohl (tis_msg->id);
2428   ti->client = client;
2429
2430   GNUNET_CONTAINER_DLL_insert (client->ticket_iter_head,
2431                                client->ticket_iter_tail,
2432                                ti);
2433   ti->iter
2434     = RECLAIM_TICKETS_iteration_start (&tis_msg->identity, &ticket_iter_cb, ti);
2435   GNUNET_SERVICE_client_continue (client->client);
2436 }
2437
2438
2439 /**
2440  * Client has had enough tickets
2441  *
2442  * @param cls the client
2443  * @param tis_msg the stop message
2444  */
2445 static void
2446 handle_ticket_iteration_stop (void *cls,
2447                               const struct TicketIterationStopMessage *tis_msg)
2448 {
2449   struct IdpClient *client = cls;
2450   struct TicketIteration *ti;
2451   uint32_t rid;
2452
2453   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2454               "Received `%s' message\n",
2455               "TICKET_ITERATION_STOP");
2456   rid = ntohl (tis_msg->id);
2457   for (ti = client->ticket_iter_head; NULL != ti; ti = ti->next)
2458     if (ti->r_id == rid)
2459       break;
2460   if (NULL == ti)
2461   {
2462     GNUNET_break (0);
2463     GNUNET_SERVICE_client_drop (client->client);
2464     return;
2465   }
2466   RECLAIM_TICKETS_iteration_stop (ti->iter);
2467   GNUNET_CONTAINER_DLL_remove (client->ticket_iter_head,
2468                                client->ticket_iter_tail,
2469                                ti);
2470   GNUNET_free (ti);
2471   GNUNET_SERVICE_client_continue (client->client);
2472 }
2473
2474
2475 /**
2476  * Client requests next result.
2477  *
2478  * @param cls the client
2479  * @param tis_msg the message
2480  */
2481 static void
2482 handle_ticket_iteration_next (void *cls,
2483                               const struct TicketIterationNextMessage *tis_msg)
2484 {
2485   struct IdpClient *client = cls;
2486   struct TicketIteration *ti;
2487   uint32_t rid;
2488
2489   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2490               "Received TICKET_ITERATION_NEXT message\n");
2491   rid = ntohl (tis_msg->id);
2492   for (ti = client->ticket_iter_head; NULL != ti; ti = ti->next)
2493     if (ti->r_id == rid)
2494       break;
2495   if (NULL == ti)
2496   {
2497     GNUNET_break (0);
2498     GNUNET_SERVICE_client_drop (client->client);
2499     return;
2500   }
2501   RECLAIM_TICKETS_iteration_next (ti->iter);
2502   GNUNET_SERVICE_client_continue (client->client);
2503 }
2504
2505
2506 /**
2507  * Main function that will be run
2508  *
2509  * @param cls closure
2510  * @param c the configuration used
2511  * @param server the service handle
2512  */
2513 static void
2514 run (void *cls,
2515      const struct GNUNET_CONFIGURATION_Handle *c,
2516      struct GNUNET_SERVICE_Handle *server)
2517 {
2518   cfg = c;
2519
2520   if (GNUNET_OK != RECLAIM_TICKETS_init (cfg))
2521   {
2522     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2523                 "Unable to initialize TICKETS subsystem.\n");
2524     GNUNET_SCHEDULER_shutdown ();
2525     return;
2526   }
2527   // Connect to identity and namestore services
2528   nsh = GNUNET_NAMESTORE_connect (cfg);
2529   if (NULL == nsh)
2530   {
2531     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
2532                          "error connecting to namestore");
2533   }
2534
2535   GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
2536 }
2537
2538
2539 /**
2540  * Called whenever a client is disconnected.
2541  *
2542  * @param cls closure
2543  * @param client identification of the client
2544  * @param app_ctx @a client
2545  */
2546 static void
2547 client_disconnect_cb (void *cls,
2548                       struct GNUNET_SERVICE_Client *client,
2549                       void *app_ctx)
2550 {
2551   struct IdpClient *idp = app_ctx;
2552
2553   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p disconnected\n", client);
2554   GNUNET_CONTAINER_DLL_remove (client_list_head,
2555                                client_list_tail,
2556                                idp);
2557   cleanup_client (idp);
2558 }
2559
2560
2561 /**
2562  * Add a client to our list of active clients.
2563  *
2564  * @param cls NULL
2565  * @param client client to add
2566  * @param mq message queue for @a client
2567  * @return internal namestore client structure for this client
2568  */
2569 static void *
2570 client_connect_cb (void *cls,
2571                    struct GNUNET_SERVICE_Client *client,
2572                    struct GNUNET_MQ_Handle *mq)
2573 {
2574   struct IdpClient *idp;
2575
2576   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", client);
2577   idp = GNUNET_new (struct IdpClient);
2578   idp->client = client;
2579   idp->mq = mq;
2580   GNUNET_CONTAINER_DLL_insert (client_list_head,
2581                                client_list_tail,
2582                                idp);
2583   return idp;
2584 }
2585
2586
2587 /**
2588  * Define "main" method using service macro.
2589  */
2590 GNUNET_SERVICE_MAIN (
2591   "reclaim",
2592   GNUNET_SERVICE_OPTION_NONE,
2593   &run,
2594   &client_connect_cb,
2595   &client_disconnect_cb,
2596   NULL,
2597   GNUNET_MQ_hd_var_size (attribute_store_message,
2598                          GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE,
2599                          struct AttributeStoreMessage,
2600                          NULL),
2601   GNUNET_MQ_hd_var_size (attestation_store_message,
2602                          GNUNET_MESSAGE_TYPE_RECLAIM_ATTESTATION_STORE,
2603                          struct AttributeStoreMessage,
2604                          NULL),
2605   GNUNET_MQ_hd_var_size (attribute_delete_message,
2606                          GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_DELETE,
2607                          struct AttributeDeleteMessage,
2608                          NULL),
2609   GNUNET_MQ_hd_var_size (attestation_delete_message,
2610                          GNUNET_MESSAGE_TYPE_RECLAIM_ATTESTATION_DELETE,
2611                          struct AttributeDeleteMessage,
2612                          NULL),
2613   GNUNET_MQ_hd_var_size (reference_store_message,
2614                          GNUNET_MESSAGE_TYPE_RECLAIM_REFERENCE_STORE,
2615                          struct AttributeStoreMessage,
2616                          NULL),
2617   GNUNET_MQ_hd_var_size (reference_delete_message,
2618                          GNUNET_MESSAGE_TYPE_RECLAIM_REFERENCE_DELETE,
2619                          struct AttributeDeleteMessage,
2620                          NULL),
2621   GNUNET_MQ_hd_fixed_size (
2622     iteration_start,
2623     GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_START,
2624     struct AttributeIterationStartMessage,
2625     NULL),
2626   GNUNET_MQ_hd_fixed_size (iteration_next,
2627                            GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_NEXT,
2628                            struct AttributeIterationNextMessage,
2629                            NULL),
2630   GNUNET_MQ_hd_fixed_size (iteration_stop,
2631                            GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_STOP,
2632                            struct AttributeIterationStopMessage,
2633                            NULL),
2634   GNUNET_MQ_hd_var_size (issue_ticket_message,
2635                          GNUNET_MESSAGE_TYPE_RECLAIM_ISSUE_TICKET,
2636                          struct IssueTicketMessage,
2637                          NULL),
2638   GNUNET_MQ_hd_var_size (consume_ticket_message,
2639                          GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET,
2640                          struct ConsumeTicketMessage,
2641                          NULL),
2642   GNUNET_MQ_hd_fixed_size (ticket_iteration_start,
2643                            GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_START,
2644                            struct TicketIterationStartMessage,
2645                            NULL),
2646   GNUNET_MQ_hd_fixed_size (ticket_iteration_next,
2647                            GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_NEXT,
2648                            struct TicketIterationNextMessage,
2649                            NULL),
2650   GNUNET_MQ_hd_fixed_size (ticket_iteration_stop,
2651                            GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_STOP,
2652                            struct TicketIterationStopMessage,
2653                            NULL),
2654   GNUNET_MQ_hd_var_size (revoke_ticket_message,
2655                          GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET,
2656                          struct RevokeTicketMessage,
2657                          NULL),
2658   GNUNET_MQ_handler_end ());
2659 /* end of gnunet-service-reclaim.c */