update clang-format
[oweals/gnunet.git] / src / namestore / plugin_rest_namestore.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  * @author Philippe Buschmann
23  * @file namestore/plugin_rest_namestore.c
24  * @brief GNUnet Namestore REST plugin
25  */
26
27 #include "platform.h"
28 #include "gnunet_rest_plugin.h"
29 #include "gnunet_gns_service.h"
30 #include "gnunet_namestore_service.h"
31 #include "gnunet_identity_service.h"
32 #include "gnunet_rest_lib.h"
33 #include "gnunet_json_lib.h"
34 #include "microhttpd.h"
35 #include <jansson.h>
36
37 /**
38  * Namestore Namespace
39  */
40 #define GNUNET_REST_API_NS_NAMESTORE "/namestore"
41
42 /**
43  * Error message Unknown Error
44  */
45 #define GNUNET_REST_NAMESTORE_ERROR_UNKNOWN "Unknown Error"
46
47 /**
48  * Error message No identity found
49  */
50 #define GNUNET_REST_IDENTITY_NOT_FOUND "No identity found"
51
52 /**
53  * Error message No default zone specified
54  */
55 #define GNUNET_REST_NAMESTORE_NO_DEFAULT_ZONE "No default zone specified"
56
57 /**
58  * Error message Failed request
59  */
60 #define GNUNET_REST_NAMESTORE_FAILED "Namestore action failed"
61
62 /**
63  * Error message invalid data
64  */
65 #define GNUNET_REST_NAMESTORE_INVALID_DATA "Data invalid"
66
67 /**
68  * Error message No data
69  */
70 #define GNUNET_REST_NAMESTORE_NO_DATA "No data"
71
72 /**
73  * State while collecting all egos
74  */
75 #define ID_REST_STATE_INIT 0
76
77 /**
78  * Done collecting egos
79  */
80 #define ID_REST_STATE_POST_INIT 1
81 /**
82  * The configuration handle
83  */
84 const struct GNUNET_CONFIGURATION_Handle *cfg;
85
86 /**
87  * HTTP methods allows for this plugin
88  */
89 static char* allow_methods;
90
91 /**
92  * @brief struct returned by the initialization function of the plugin
93  */
94 struct Plugin
95 {
96   const struct GNUNET_CONFIGURATION_Handle *cfg;
97 };
98
99 /**
100  * The default namestore ego
101  */
102 struct EgoEntry
103 {
104   /**
105    * DLL
106    */
107   struct EgoEntry *next;
108
109   /**
110    * DLL
111    */
112   struct EgoEntry *prev;
113
114   /**
115    * Ego Identifier
116    */
117   char *identifier;
118
119   /**
120    * Public key string
121    */
122   char *keystring;
123
124   /**
125    * The Ego
126    */
127   struct GNUNET_IDENTITY_Ego *ego;
128 };
129
130 /**
131  * The request handle
132  */
133 struct RequestHandle
134 {
135   /**
136    * Records to store
137    */
138   char *record_name;
139
140   /**
141    * Records to store
142    */
143   struct GNUNET_GNSRECORD_Data *rd;
144
145   /**
146    * NAMESTORE Operation
147    */
148   struct GNUNET_NAMESTORE_QueueEntry *add_qe;
149
150   /**
151    * Response object
152    */
153   json_t *resp_object;
154
155   /**
156    * The processing state
157    */
158   int state;
159
160   /**
161    * Handle to NAMESTORE
162    */
163   struct GNUNET_NAMESTORE_Handle *ns_handle;
164
165   /**
166    * Handle to NAMESTORE it
167    */
168   struct GNUNET_NAMESTORE_ZoneIterator *list_it;
169
170   /**
171    * Private key for the zone
172    */
173   const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_pkey;
174
175   /**
176    * IDENTITY Operation
177    */
178   struct EgoEntry *ego_entry;
179
180   /**
181    * Ego list
182    */
183   struct EgoEntry *ego_head;
184
185   /**
186    * Ego list
187    */
188   struct EgoEntry *ego_tail;
189
190   /**
191    * IDENTITY Operation
192    */
193   struct GNUNET_IDENTITY_Operation *op;
194
195   /**
196    * Handle to Identity service.
197    */
198   struct GNUNET_IDENTITY_Handle *identity_handle;
199
200   /**
201    * Rest connection
202    */
203   struct GNUNET_REST_RequestHandle *rest_handle;
204   
205   /**
206    * Desired timeout for the lookup (default is no timeout).
207    */
208   struct GNUNET_TIME_Relative timeout;
209
210   /**
211    * ID of a task associated with the resolution process.
212    */
213   struct GNUNET_SCHEDULER_Task *timeout_task;
214
215   /**
216    * The plugin result processor
217    */
218   GNUNET_REST_ResultProcessor proc;
219
220   /**
221    * The closure of the result processor
222    */
223   void *proc_cls;
224
225   /**
226    * The url
227    */
228   char *url;
229
230   /**
231    * Error response message
232    */
233   char *emsg;
234
235   /**
236    * Response code
237    */
238   int response_code;
239
240 };
241
242 /**
243  * Cleanup lookup handle
244  * @param handle Handle to clean up
245  */
246 static void
247 cleanup_handle (void *cls)
248 {
249   struct RequestHandle *handle = cls;
250   struct EgoEntry *ego_entry;
251   struct EgoEntry *ego_tmp;
252
253   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
254               "Cleaning up\n");
255   if (NULL != handle->timeout_task)
256   {
257     GNUNET_SCHEDULER_cancel (handle->timeout_task);
258     handle->timeout_task = NULL;
259   }
260   if (NULL != handle->record_name)
261     GNUNET_free(handle->record_name);
262   if (NULL != handle->url)
263     GNUNET_free(handle->url);
264   if (NULL != handle->emsg)
265     GNUNET_free(handle->emsg);
266   if (NULL != handle->rd)
267   {
268     if (NULL != handle->rd->data)
269       GNUNET_free((void*)handle->rd->data);
270     GNUNET_free(handle->rd);
271   }
272   if (NULL != handle->timeout_task)
273     GNUNET_SCHEDULER_cancel(handle->timeout_task);
274   if (NULL != handle->list_it)
275     GNUNET_NAMESTORE_zone_iteration_stop(handle->list_it);
276   if (NULL != handle->add_qe)
277     GNUNET_NAMESTORE_cancel(handle->add_qe);
278   if (NULL != handle->identity_handle)
279     GNUNET_IDENTITY_disconnect(handle->identity_handle);
280   if (NULL != handle->ns_handle)
281   {
282     GNUNET_NAMESTORE_disconnect(handle->ns_handle);
283   }
284
285   for (ego_entry = handle->ego_head;
286   NULL != ego_entry;)
287   {
288     ego_tmp = ego_entry;
289     ego_entry = ego_entry->next;
290     GNUNET_free(ego_tmp->identifier);
291     GNUNET_free(ego_tmp->keystring);
292     GNUNET_free(ego_tmp);
293   }
294
295   if(NULL != handle->resp_object)
296   {
297     json_decref(handle->resp_object);
298   }
299
300   GNUNET_free (handle);
301 }
302
303
304 /**
305  * Task run on errors.  Reports an error and cleans up everything.
306  *
307  * @param cls the `struct RequestHandle`
308  */
309 static void
310 do_error (void *cls)
311 {
312   struct RequestHandle *handle = cls;
313   struct MHD_Response *resp;
314   json_t *json_error = json_object();
315   char *response;
316
317   if (NULL == handle->emsg)
318     handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_ERROR_UNKNOWN);
319
320   json_object_set_new(json_error,"error", json_string(handle->emsg));
321
322   if (0 == handle->response_code)
323     handle->response_code = MHD_HTTP_OK;
324   response = json_dumps (json_error, 0);
325   resp = GNUNET_REST_create_response (response);
326   handle->proc (handle->proc_cls, resp, handle->response_code);
327   json_decref(json_error);
328   GNUNET_free(response);
329   GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
330 }
331
332
333 /**
334  * Get EgoEntry from list with either a public key or a name
335  * If public key and name are not NULL, it returns the public key result first
336  *
337  * @param handle the RequestHandle
338  * @param pubkey the public key of an identity (only one can be NULL)
339  * @param name the name of an identity (only one can be NULL)
340  * @return EgoEntry or NULL if not found
341  */
342 struct EgoEntry*
343 get_egoentry_namestore(struct RequestHandle *handle, char *name)
344 {
345   struct EgoEntry *ego_entry;
346   if (NULL != name)
347   {
348     for (ego_entry = handle->ego_head;
349         NULL != ego_entry;
350         ego_entry = ego_entry->next)
351     {
352       if (0 != strcasecmp (name, ego_entry->identifier))
353         continue;
354       return ego_entry;
355     }
356   }
357   return NULL;
358 }
359
360
361 /**
362  * Does internal server error when iteration failed.
363  *
364  * @param cls the `struct RequestHandle`
365  */
366 static void
367 namestore_iteration_error (void *cls)
368 {
369   struct RequestHandle *handle = cls;
370   handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_FAILED);
371   GNUNET_SCHEDULER_add_now (&do_error, handle);
372   return;
373 }
374
375
376 /**
377  * Create finished callback
378  *
379  * @param cls the `struct RequestHandle`
380  * @param success the success indicating integer, GNUNET_OK on success
381  * @param emsg the error message (can be NULL)
382  */
383 static void
384 create_finished (void *cls, int32_t success, const char *emsg)
385 {
386   struct RequestHandle *handle = cls;
387   struct MHD_Response *resp;
388
389   handle->add_qe = NULL;
390   if (GNUNET_YES != success)
391   {
392     if (NULL != emsg)
393     {
394       handle->emsg = GNUNET_strdup(emsg);
395       GNUNET_SCHEDULER_add_now (&do_error, handle);
396       return;
397     }
398     handle->emsg = GNUNET_strdup("Error storing records");
399     GNUNET_SCHEDULER_add_now (&do_error, handle);
400     return;
401   }
402   resp = GNUNET_REST_create_response (NULL);
403   handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
404   GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
405 }
406
407
408 /**
409  * Delete finished callback
410  *
411  * @param cls the `struct RequestHandle`
412  * @param success the success indicating integer, GNUNET_OK on success
413  * @param emsg the error message (can be NULL)
414  */
415 static void
416 del_finished (void *cls, int32_t success, const char *emsg)
417 {
418   struct RequestHandle *handle = cls;
419
420   handle->add_qe = NULL;
421   if (GNUNET_NO == success)
422   {
423     handle->response_code = MHD_HTTP_NOT_FOUND;
424     handle->emsg = GNUNET_strdup("No record found");
425     GNUNET_SCHEDULER_add_now (&do_error, handle);
426     return;
427   }
428   if (GNUNET_SYSERR == success)
429   {
430     if (NULL != emsg)
431     {
432       handle->emsg = GNUNET_strdup(emsg);
433       GNUNET_SCHEDULER_add_now (&do_error, handle);
434       return;
435     }
436     handle->emsg = GNUNET_strdup("Deleting record failed");
437     GNUNET_SCHEDULER_add_now (&do_error, handle);
438     return;
439   }
440   handle->proc (handle->proc_cls,
441                 GNUNET_REST_create_response (NULL),
442                 MHD_HTTP_NO_CONTENT);
443   GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
444 }
445
446
447 /**
448  * Iteration over all results finished, build final
449  * response.
450  *
451  * @param cls the `struct RequestHandle`
452  */
453 static void
454 namestore_list_finished (void *cls)
455 {
456   struct RequestHandle *handle = cls;
457   char *result_str;
458   struct MHD_Response *resp;
459
460   handle->list_it = NULL;
461
462   if (NULL == handle->resp_object)
463     handle->resp_object = json_array();
464
465   result_str = json_dumps (handle->resp_object, 0);
466   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
467   resp = GNUNET_REST_create_response (result_str);
468   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
469   GNUNET_free_non_null (result_str);
470   GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
471 }
472
473
474 /**
475  * Create a response with requested records
476  *
477  * @param handle the RequestHandle
478  */
479 static void
480 namestore_list_iteration (void *cls,
481                          const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
482                          const char *rname,
483                          unsigned int rd_len,
484                          const struct GNUNET_GNSRECORD_Data *rd)
485 {
486   struct RequestHandle *handle = cls;
487   json_t *record_obj;
488
489   if (NULL == handle->resp_object)
490     handle->resp_object = json_array();
491
492   for (unsigned int i = 0; i < rd_len; i++)
493   {
494     if ( (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) &&
495          (0 != strcmp (rname, GNUNET_GNS_EMPTY_LABEL_AT)) )
496       continue;
497
498     record_obj = GNUNET_JSON_from_gns_record(rname,rd);
499
500     if(NULL == record_obj)
501       continue;
502
503     json_array_append (handle->resp_object, record_obj);
504     json_decref (record_obj);
505   }
506
507   GNUNET_NAMESTORE_zone_iterator_next (handle->list_it, 1);
508 }
509
510 /**
511  * @param cls closure
512  * @param ego ego handle
513  * @param ctx context for application to store data for this ego
514  *                 (during the lifetime of this process, initially NULL)
515  * @param identifier identifier assigned by the user for this ego,
516  *                   NULL if the user just deleted the ego and it
517  *                   must thus no longer be used
518  */
519 static void
520 default_ego_get (void *cls,
521                  struct GNUNET_IDENTITY_Ego *ego,
522                  void **ctx,
523                  const char *identifier)
524 {
525   struct RequestHandle *handle = cls;
526   handle->op = NULL;
527
528   if (ego == NULL)
529   {
530     handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_NO_DEFAULT_ZONE);
531     GNUNET_SCHEDULER_add_now (&do_error, handle);
532     return;
533   }
534   handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego);
535
536   handle->list_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
537                                                            handle->zone_pkey,
538                                                            &namestore_iteration_error,
539                                                            handle,
540                                                            &namestore_list_iteration,
541                                                            handle,
542                                                            &namestore_list_finished,
543                                                            handle);
544   if (NULL == handle->list_it)
545   {
546     handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_FAILED);
547     GNUNET_SCHEDULER_add_now (&do_error, handle);
548     return;
549   }
550 }
551
552
553 /**
554  * Handle namestore GET request
555  *
556  * @param con_handle the connection handle
557  * @param url the url
558  * @param cls the RequestHandle
559  */
560 void
561 namestore_get (struct GNUNET_REST_RequestHandle *con_handle,
562                  const char* url,
563                  void *cls)
564 {
565   struct RequestHandle *handle = cls;
566   struct EgoEntry *ego_entry;
567   char *egoname;
568
569   egoname = NULL;
570   ego_entry = NULL;
571
572   //set zone to name if given
573   if (strlen (GNUNET_REST_API_NS_NAMESTORE) < strlen (handle->url))
574   {
575     egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE)+1];
576     ego_entry = get_egoentry_namestore(handle, egoname);
577
578     if (NULL == ego_entry)
579     {
580       handle->response_code = MHD_HTTP_NOT_FOUND;
581       handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
582       GNUNET_SCHEDULER_add_now (&do_error, handle);
583       return;
584     }
585   }
586   if ( NULL != ego_entry )
587   {
588     handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key(ego_entry->ego);
589   }
590
591   if (NULL == handle->zone_pkey)
592   {
593     handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
594                                       "namestore",
595                                       &default_ego_get,
596                                       handle);
597     return;
598   }
599   handle->list_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
600                                                            handle->zone_pkey,
601                                                            &namestore_iteration_error,
602                                                            handle,
603                                                            &namestore_list_iteration,
604                                                            handle,
605                                                            &namestore_list_finished,
606                                                            handle);
607   if (NULL == handle->list_it)
608   {
609     handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_FAILED);
610     GNUNET_SCHEDULER_add_now (&do_error, handle);
611     return;
612   }
613 }
614
615
616 /**
617  * @param cls closure
618  * @param ego ego handle
619  * @param ctx context for application to store data for this ego
620  *                 (during the lifetime of this process, initially NULL)
621  * @param identifier identifier assigned by the user for this ego,
622  *                   NULL if the user just deleted the ego and it
623  *                   must thus no longer be used
624  */
625 static void
626 default_ego_post (void *cls,
627                   struct GNUNET_IDENTITY_Ego *ego,
628                   void **ctx,
629                   const char *identifier)
630 {
631   struct RequestHandle *handle = cls;
632   handle->op = NULL;
633
634   if (ego == NULL)
635   {
636     handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_NO_DEFAULT_ZONE);
637     GNUNET_SCHEDULER_add_now (&do_error, handle);
638     return;
639   }
640   handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego);
641
642   handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
643                                                    handle->zone_pkey,
644                                                    handle->record_name,
645                                                    1,
646                                                    handle->rd,
647                                                    &create_finished,
648                                                    handle);
649   if (NULL == handle->add_qe)
650   {
651     handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_FAILED);
652     GNUNET_SCHEDULER_add_now (&do_error, handle);
653     return;
654   }
655 }
656
657
658 /**
659  * Handle namestore POST request
660  *
661  * @param con_handle the connection handle
662  * @param url the url
663  * @param cls the RequestHandle
664  */
665 void
666 namestore_add (struct GNUNET_REST_RequestHandle *con_handle,
667                const char* url,
668                void *cls)
669 {
670   struct RequestHandle *handle = cls;
671   struct GNUNET_GNSRECORD_Data *gns_record;
672   struct EgoEntry *ego_entry;
673   char *egoname;
674   json_t *data_js;
675   json_t *name_json;
676   json_error_t err;
677   char term_data[handle->rest_handle->data_size + 1];
678
679   struct GNUNET_JSON_Specification gnsspec[] = {
680     GNUNET_JSON_spec_gnsrecord_data(&gns_record),
681     GNUNET_JSON_spec_end ()
682   };
683
684   if (0 >= handle->rest_handle->data_size)
685   {
686     handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_NO_DATA);
687     GNUNET_SCHEDULER_add_now (&do_error, handle);
688     return;
689   }
690   term_data[handle->rest_handle->data_size] = '\0';
691   GNUNET_memcpy(term_data, handle->rest_handle->data,
692                 handle->rest_handle->data_size);
693   data_js = json_loads (term_data, JSON_DECODE_ANY, &err);
694   if (GNUNET_OK != GNUNET_JSON_parse (data_js, gnsspec, NULL, NULL))
695   {
696     handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_INVALID_DATA);
697     GNUNET_SCHEDULER_add_now (&do_error, handle);
698     GNUNET_JSON_parse_free(gnsspec);
699     json_decref (data_js);
700     return;
701   }
702   handle->rd = gns_record;
703
704   name_json = json_object_get(data_js, "record_name");
705   if (!json_is_string(name_json))
706   {
707     handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_INVALID_DATA);
708     GNUNET_SCHEDULER_add_now (&do_error, handle);
709     json_decref (data_js);
710     return;
711   }
712   handle->record_name = GNUNET_strdup(json_string_value(name_json));
713   if(NULL == handle->record_name)
714   {
715     handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_INVALID_DATA);
716     GNUNET_SCHEDULER_add_now (&do_error, handle);
717     json_decref (data_js);
718     return;
719   }
720   if (0 >= strlen(handle->record_name))
721   {
722     handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_INVALID_DATA);
723     GNUNET_SCHEDULER_add_now (&do_error, handle);
724     json_decref (data_js);
725     return;
726   }
727   json_decref (data_js);
728
729   egoname = NULL;
730   ego_entry = NULL;
731
732   //set zone to name if given
733   if (strlen (GNUNET_REST_API_NS_NAMESTORE) < strlen (handle->url))
734   {
735     egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE)+1];
736     ego_entry = get_egoentry_namestore(handle, egoname);
737
738     if (NULL == ego_entry)
739     {
740       handle->response_code = MHD_HTTP_NOT_FOUND;
741       handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
742       GNUNET_SCHEDULER_add_now (&do_error, handle);
743       return;
744     }
745   }
746   if (NULL != ego_entry)
747   {
748     handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key(ego_entry->ego);
749   }
750   if (NULL == handle->zone_pkey)
751   {
752     handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
753                                       "namestore",
754                                       &default_ego_post,
755                                       handle);
756     return;
757   }
758   handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
759                                                    handle->zone_pkey,
760                                                    handle->record_name,
761                                                    1,
762                                                    handle->rd,
763                                                    &create_finished,
764                                                    handle);
765   if (NULL == handle->add_qe)
766   {
767     handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_FAILED);
768     GNUNET_SCHEDULER_add_now (&do_error, handle);
769     return;
770   }
771 }
772
773
774 /**
775  * @param cls closure
776  * @param ego ego handle
777  * @param ctx context for application to store data for this ego
778  *                 (during the lifetime of this process, initially NULL)
779  * @param identifier identifier assigned by the user for this ego,
780  *                   NULL if the user just deleted the ego and it
781  *                   must thus no longer be used
782  */
783 static void
784 default_ego_delete (void *cls,
785                     struct GNUNET_IDENTITY_Ego *ego,
786                     void **ctx,
787                     const char *identifier)
788 {
789   struct RequestHandle *handle = cls;
790   handle->op = NULL;
791
792   if (ego == NULL)
793   {
794     handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_NO_DEFAULT_ZONE);
795     GNUNET_SCHEDULER_add_now (&do_error, handle);
796     return;
797   }
798   handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego);
799
800   handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
801                                                    handle->zone_pkey,
802                                                    handle->record_name,
803                                                    0,
804                                                    NULL,
805                                                    &del_finished,
806                                                    handle);
807   if (NULL == handle->add_qe)
808   {
809     handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_FAILED);
810     GNUNET_SCHEDULER_add_now (&do_error, handle);
811     return;
812   }
813 }
814
815
816 /**
817  * Handle namestore DELETE request
818  *
819  * @param con_handle the connection handle
820  * @param url the url
821  * @param cls the RequestHandle
822  */
823 void
824 namestore_delete (struct GNUNET_REST_RequestHandle *con_handle,
825                  const char* url,
826                  void *cls)
827 {
828   struct RequestHandle *handle = cls;
829   struct GNUNET_HashCode key;
830   struct EgoEntry *ego_entry;
831   char *egoname;
832
833   egoname = NULL;
834   ego_entry = NULL;
835
836   //set zone to name if given
837   if (strlen (GNUNET_REST_API_NS_NAMESTORE) < strlen (handle->url))
838   {
839     egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE)+1];
840     ego_entry = get_egoentry_namestore(handle, egoname);
841
842     if (NULL == ego_entry)
843     {
844       handle->response_code = MHD_HTTP_NOT_FOUND;
845       handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_NOT_FOUND);
846       GNUNET_SCHEDULER_add_now (&do_error, handle);
847       return;
848     }
849   }
850   if ( NULL != ego_entry )
851   {
852     handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key(ego_entry->ego);
853   }
854
855   GNUNET_CRYPTO_hash ("record_name", strlen ("record_name"), &key);
856   if ( GNUNET_NO
857       == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map,
858                                                  &key))
859   {
860     handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_INVALID_DATA);
861     GNUNET_SCHEDULER_add_now (&do_error, handle);
862     return;
863   }
864   handle->record_name = GNUNET_strdup(
865       GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, &key));
866
867   if (NULL == handle->zone_pkey)
868   {
869     handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
870                                       "namestore",
871                                       &default_ego_delete,
872                                       handle);
873     return;
874   }
875
876   handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
877                                                    handle->zone_pkey,
878                                                    handle->record_name,
879                                                    0,
880                                                    NULL,
881                                                    &del_finished,
882                                                    handle);
883   if (NULL == handle->add_qe)
884   {
885     handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_FAILED);
886     GNUNET_SCHEDULER_add_now (&do_error, handle);
887     return;
888   }
889 }
890
891
892
893 /**
894  * Respond to OPTIONS request
895  *
896  * @param con_handle the connection handle
897  * @param url the url
898  * @param cls the RequestHandle
899  */
900 static void
901 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
902               const char* url,
903               void *cls)
904 {
905   struct MHD_Response *resp;
906   struct RequestHandle *handle = cls;
907
908   //independent of path return all options
909   resp = GNUNET_REST_create_response (NULL);
910   MHD_add_response_header (resp,
911                            "Access-Control-Allow-Methods",
912                            allow_methods);
913   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
914   GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
915   return;
916 }
917
918
919 /**
920  * Handle rest request
921  *
922  * @param handle the request handle
923  */
924 static void
925 init_cont (struct RequestHandle *handle)
926 {
927   struct GNUNET_REST_RequestHandlerError err;
928   static const struct GNUNET_REST_RequestHandler handlers[] = {
929     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE, &namestore_get},
930     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE, &namestore_add},
931     {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_NAMESTORE, &namestore_delete},
932     {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_NAMESTORE, &options_cont},
933     GNUNET_REST_HANDLER_END
934   };
935
936   if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
937                                                handlers,
938                                                &err,
939                                                handle))
940   {
941     handle->response_code = err.error_code;
942     GNUNET_SCHEDULER_add_now (&do_error, handle);
943   }
944 }
945
946
947 /**
948  * This function is initially called for all egos and then again
949  * whenever a ego's identifier changes or if it is deleted.  At the
950  * end of the initial pass over all egos, the function is once called
951  * with 'NULL' for 'ego'. That does NOT mean that the callback won't
952  * be invoked in the future or that there was an error.
953  *
954  * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
955  * this function is only called ONCE, and 'NULL' being passed in
956  * 'ego' does indicate an error (i.e. name is taken or no default
957  * value is known).  If 'ego' is non-NULL and if '*ctx'
958  * is set in those callbacks, the value WILL be passed to a subsequent
959  * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
960  * that one was not NULL).
961  *
962  * When an identity is renamed, this function is called with the
963  * (known) ego but the NEW identifier.
964  *
965  * When an identity is deleted, this function is called with the
966  * (known) ego and "NULL" for the 'identifier'.  In this case,
967  * the 'ego' is henceforth invalid (and the 'ctx' should also be
968  * cleaned up).
969  *
970  * @param cls closure
971  * @param ego ego handle
972  * @param ctx context for application to store data for this ego
973  *                 (during the lifetime of this process, initially NULL)
974  * @param name identifier assigned by the user for this ego,
975  *                   NULL if the user just deleted the ego and it
976  *                   must thus no longer be used
977  */
978 static void
979 id_connect_cb (void *cls,
980                struct GNUNET_IDENTITY_Ego *ego,
981                void **ctx,
982                const char *name)
983 {
984   struct RequestHandle *handle = cls;
985   struct EgoEntry *ego_entry;
986   struct GNUNET_CRYPTO_EcdsaPublicKey pk;
987
988   if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
989   {
990     handle->state = ID_REST_STATE_POST_INIT;
991     init_cont(handle);
992     return;
993   }
994   if (ID_REST_STATE_INIT == handle->state)
995   {
996     ego_entry = GNUNET_new(struct EgoEntry);
997     GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
998     ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
999     ego_entry->ego = ego;
1000     GNUNET_asprintf (&ego_entry->identifier, "%s", name);
1001     GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head, handle->ego_tail,
1002                                      ego_entry);
1003   }
1004
1005 }
1006
1007
1008 /**
1009  * Function processing the REST call
1010  *
1011  * @param method HTTP method
1012  * @param url URL of the HTTP request
1013  * @param data body of the HTTP request (optional)
1014  * @param data_size length of the body
1015  * @param proc callback function for the result
1016  * @param proc_cls closure for callback function
1017  * @return GNUNET_OK if request accepted
1018  */
1019 static void
1020 rest_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
1021                               GNUNET_REST_ResultProcessor proc,
1022                               void *proc_cls)
1023 {
1024   struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1025   
1026   handle->response_code = 0;
1027   handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1028   handle->proc_cls = proc_cls;
1029   handle->proc = proc;
1030   handle->rest_handle = rest_handle;
1031   handle->zone_pkey = NULL;
1032   
1033   handle->url = GNUNET_strdup (rest_handle->url);
1034   if (handle->url[strlen (handle->url)-1] == '/')
1035     handle->url[strlen (handle->url)-1] = '\0';
1036   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
1037
1038   handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
1039   handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &id_connect_cb, handle);
1040   handle->timeout_task =
1041     GNUNET_SCHEDULER_add_delayed (handle->timeout,
1042                                   &do_error,
1043                                   handle);
1044   
1045   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
1046 }
1047
1048
1049 /**
1050  * Entry point for the plugin.
1051  *
1052  * @param cls Config info
1053  * @return NULL on error, otherwise the plugin context
1054  */
1055 void *
1056 libgnunet_plugin_rest_namestore_init (void *cls)
1057 {
1058   static struct Plugin plugin;
1059   struct GNUNET_REST_Plugin *api;
1060
1061   cfg = cls;
1062   if (NULL != plugin.cfg)
1063     return NULL;                /* can only initialize once! */
1064   memset (&plugin, 0, sizeof (struct Plugin));
1065   plugin.cfg = cfg;
1066   api = GNUNET_new (struct GNUNET_REST_Plugin);
1067   api->cls = &plugin;
1068   api->name = GNUNET_REST_API_NS_NAMESTORE;
1069   api->process_request = &rest_process_request;
1070   GNUNET_asprintf (&allow_methods,
1071                    "%s, %s, %s, %s, %s",
1072                    MHD_HTTP_METHOD_GET,
1073                    MHD_HTTP_METHOD_POST,
1074                    MHD_HTTP_METHOD_PUT,
1075                    MHD_HTTP_METHOD_DELETE,
1076                    MHD_HTTP_METHOD_OPTIONS);
1077
1078   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1079               _("Namestore REST API initialized\n"));
1080   return api;
1081 }
1082
1083
1084 /**
1085  * Exit point from the plugin.
1086  *
1087  * @param cls the plugin context (as returned by "init")
1088  * @return always NULL
1089  */
1090 void *
1091 libgnunet_plugin_rest_namestore_done (void *cls)
1092 {
1093   struct GNUNET_REST_Plugin *api = cls;
1094   struct Plugin *plugin = api->cls;
1095   plugin->cfg = NULL;
1096
1097   GNUNET_free_non_null (allow_methods);
1098   GNUNET_free (api);
1099   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1100               "Namestore REST plugin is finished\n");
1101   return NULL;
1102 }
1103
1104 /* end of plugin_rest_namestore.c */
1105