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