- refactor to check messages from both enc systems
[oweals/gnunet.git] / src / namestore / plugin_rest_namestore.c
1 /*
2    This file is part of GNUnet.
3    Copyright (C) 2012-2015 Christian Grothoff (and other contributing authors)
4
5    GNUnet is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published
7    by the Free Software Foundation; either version 3, or (at your
8    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    General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with GNUnet; see the file COPYING.  If not, write to the
17    Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.
19    */
20 /**
21  * @author Martin Schanzenbach
22  * @file namestore/plugin_rest_namestore.c
23  * @brief GNUnet Namestore REST plugin
24  *
25  */
26
27 #include "platform.h"
28 #include "gnunet_rest_plugin.h"
29 #include "gnunet_namestore_service.h"
30 #include "gnunet_identity_service.h"
31 #include "gnunet_rest_lib.h"
32 #include "microhttpd.h"
33 #include <jansson.h>
34
35 #define GNUNET_REST_API_NS_NAMESTORE "/names"
36
37 #define GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO "record"
38
39 #define GNUNET_REST_JSONAPI_NAMESTORE_RECORD GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO
40
41 #define GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE "record_type"
42
43 #define GNUNET_REST_JSONAPI_NAMESTORE_VALUE "value"
44
45 #define GNUNET_REST_JSONAPI_NAMESTORE_PUBLIC "public"
46
47 #define GNUNET_REST_JSONAPI_NAMESTORE_SHADOW "shadow"
48
49 #define GNUNET_REST_JSONAPI_NAMESTORE_PKEY "pkey"
50
51 #define GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION "expiration"
52
53 #define GNUNET_REST_JSONAPI_NAMESTORE_EGO "ego"
54
55 /**
56  * @brief struct returned by the initialization function of the plugin
57  */
58 struct Plugin
59 {
60   const struct GNUNET_CONFIGURATION_Handle *cfg;
61 };
62
63 const struct GNUNET_CONFIGURATION_Handle *cfg;
64
65 struct RecordEntry
66 {
67   /**
68    * DLL
69    */
70   struct RecordEntry *next;
71   
72   /**
73    * DLL
74    */
75   struct RecordEntry *prev;
76   
77 };
78
79 struct RequestHandle
80 {
81   /**
82    * Ego list
83    */
84   struct RecordEntry *record_head;
85
86   /**
87    * Ego list
88    */
89   struct record_entry *record_tail;
90
91   /**
92    * JSON response object
93    */
94   struct JsonApiObject *resp_object;
95   
96   /**
97    * Rest connection
98    */
99   struct RestConnectionDataHandle *conndata_handle;
100   
101   /**
102    * Handle to GNS service.
103    */
104   struct GNUNET_IDENTITY_Handle *identity_handle;
105
106   /**
107    * Handle to NAMESTORE
108    */
109   struct GNUNET_NAMESTORE_Handle *ns_handle;
110   
111   /**
112    * Handle to NAMESTORE it
113    */
114   struct GNUNET_NAMESTORE_ZoneIterator *list_it;
115   
116   /**
117    * Private key for the zone
118    */
119   struct GNUNET_CRYPTO_EcdsaPrivateKey zone_pkey;
120
121   /**
122    * Handle to identity lookup
123    */
124   struct GNUNET_IDENTITY_EgoLookup *ego_lookup;
125
126   /**
127    * Default Ego operation
128    */
129   struct GNUNET_IDENTITY_Operation *get_default;
130
131   /**
132    * Name of the ego
133    */
134   char *ego_name;
135
136   /**
137    * Record is public
138    */
139   int is_public;
140
141   /**
142    * Shadow record
143    */
144   int is_shadow;
145
146   /**
147    * Name of the record to modify
148    */
149   char *name;
150
151   /**
152    * Value of the record
153    */
154   char *value;
155
156   /**
157    * record type
158    */
159   uint32_t type;
160
161   /**
162    * Records to store
163    */
164   struct GNUNET_GNSRECORD_Data *rd;
165
166   /**
167    * record count
168    */
169   unsigned int rd_count;
170
171     /**
172    * NAMESTORE Operation
173    */
174   struct GNUNET_NAMESTORE_QueueEntry *add_qe;
175
176   /**
177    * Desired timeout for the lookup (default is no timeout).
178    */
179   struct GNUNET_TIME_Relative timeout;
180
181   /**
182    * ID of a task associated with the resolution process.
183    */
184   struct GNUNET_SCHEDULER_Task * timeout_task;    
185
186   /**
187    * The plugin result processor
188    */
189   GNUNET_REST_ResultProcessor proc;
190
191   /**
192    * The closure of the result processor
193    */
194   void *proc_cls;
195
196   /**
197    * The url
198    */
199   char *url;
200
201   /**
202    * The data from the REST request
203    */
204   const char* data;
205
206   /**
207    * the length of the REST data
208    */
209   size_t data_size;
210   
211   /**
212    * Cfg
213    */
214   const struct GNUNET_CONFIGURATION_Handle *cfg;
215
216 };
217
218
219 /**
220  * Cleanup lookup handle
221  * @param handle Handle to clean up
222  */
223 static void
224 cleanup_handle (struct RequestHandle *handle)
225 {
226   struct RecordEntry *record_entry;
227   struct RecordEntry *record_tmp;
228   int i;
229   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
230               "Cleaning up\n");
231   if (NULL != handle->name)
232     GNUNET_free (handle->name);
233   if (NULL != handle->timeout_task)
234     GNUNET_SCHEDULER_cancel (handle->timeout_task);
235   if (NULL != handle->ego_lookup)
236     GNUNET_IDENTITY_ego_lookup_cancel (handle->ego_lookup);
237   if (NULL != handle->get_default)
238     GNUNET_IDENTITY_cancel (handle->get_default);
239   if (NULL != handle->list_it)
240     GNUNET_NAMESTORE_zone_iteration_stop (handle->list_it);
241   if (NULL != handle->add_qe)
242     GNUNET_NAMESTORE_cancel (handle->add_qe);
243   if (NULL != handle->identity_handle)
244     GNUNET_IDENTITY_disconnect (handle->identity_handle);
245   if (NULL != handle->ns_handle)
246     GNUNET_NAMESTORE_disconnect (handle->ns_handle);
247   if (NULL != handle->url)
248     GNUNET_free (handle->url);
249   if (NULL != handle->value)
250     GNUNET_free (handle->value);
251   if (NULL != handle->rd)
252   {
253     for (i = 0; i < handle->rd_count; i++)
254     {
255       if (NULL != handle->rd[i].data)
256         GNUNET_free ((void*)handle->rd[i].data);
257     }
258     GNUNET_free (handle->rd);
259   }
260   if (NULL != handle->ego_name)
261     GNUNET_free (handle->ego_name);
262   for (record_entry = handle->record_head;
263        NULL != record_entry;)
264   {
265     record_tmp = record_entry;
266     record_entry = record_entry->next;
267     GNUNET_free (record_tmp);
268   }
269   GNUNET_free (handle);
270 }
271
272 /**
273  * Create json representation of a GNSRECORD
274  *
275  * @param rd the GNSRECORD_Data
276  */
277 static json_t *
278 gnsrecord_to_json (const struct GNUNET_GNSRECORD_Data *rd)
279 {
280   const char *typename;
281   char *string_val;
282   const char *exp_str;
283   json_t *record_obj;
284
285   typename = GNUNET_GNSRECORD_number_to_typename (rd->record_type);
286   string_val = GNUNET_GNSRECORD_value_to_string (rd->record_type,
287                                                  rd->data,
288                                                  rd->data_size);
289
290   if (NULL == string_val)
291   {
292     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
293                 "Record of type %d malformed, skipping\n",
294                 (int) rd->record_type);
295     return NULL;
296   }
297   record_obj = json_object();
298   json_object_set_new (record_obj,
299                        GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE,
300                        json_string (typename));
301   json_object_set_new (record_obj,
302                        GNUNET_REST_JSONAPI_NAMESTORE_VALUE,
303                        json_string (string_val));
304   GNUNET_free (string_val);
305
306   if (GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION & rd->flags)
307   {
308     struct GNUNET_TIME_Relative time_rel;
309     time_rel.rel_value_us = rd->expiration_time;
310     exp_str = GNUNET_STRINGS_relative_time_to_string (time_rel, 1);
311   }
312   else
313   {
314     struct GNUNET_TIME_Absolute time_abs;
315     time_abs.abs_value_us = rd->expiration_time;
316     exp_str = GNUNET_STRINGS_absolute_time_to_string (time_abs);
317   }
318   json_object_set_new (record_obj, GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION, json_string (exp_str));
319
320   json_object_set_new (record_obj, "expired",
321                        json_boolean (GNUNET_YES == GNUNET_GNSRECORD_is_expired (rd)));
322   return record_obj;
323 }
324
325
326 /**
327  * Task run on shutdown.  Cleans up everything.
328  *
329  * @param cls unused
330  * @param tc scheduler context
331  */
332 static void
333 do_error (void *cls,
334           const struct GNUNET_SCHEDULER_TaskContext *tc)
335 {
336   struct RequestHandle *handle = cls;
337   struct MHD_Response *resp = GNUNET_REST_create_json_response (NULL);
338   handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
339   cleanup_handle (handle);
340 }
341
342 static void
343 cleanup_handle_delayed (void *cls,
344                         const struct GNUNET_SCHEDULER_TaskContext *tc)
345 {
346   cleanup_handle (cls);
347 }
348
349 /**
350  * Create a response with requested records
351  *
352  * @param handle the RequestHandle
353  */
354 static void
355 namestore_list_response (void *cls,
356                          const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
357                          const char *rname,
358                          unsigned int rd_len,
359                          const struct GNUNET_GNSRECORD_Data *rd)
360 {
361   struct RequestHandle *handle = cls;
362   struct JsonApiResource *json_resource;
363   struct MHD_Response *resp;
364   json_t *result_array;
365   json_t *record_obj;
366   int i;
367   char *result;
368
369   if (NULL == handle->resp_object)
370     handle->resp_object = GNUNET_REST_jsonapi_object_new ();
371
372   if (NULL == rname)
373   {
374     //Handle response
375     if (GNUNET_SYSERR == GNUNET_REST_jsonapi_data_serialize (handle->resp_object, &result))
376     {
377       GNUNET_SCHEDULER_add_now (&do_error, handle);
378       return;
379     }
380     GNUNET_REST_jsonapi_object_delete (handle->resp_object);
381     resp = GNUNET_REST_create_json_response (result);
382     handle->list_it = NULL;
383     handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
384     GNUNET_free (result);
385     GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
386     return;
387   }
388
389   if ( (NULL != handle->name) &&
390        (0 != strcmp (handle->name, rname)) )
391   {
392     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
393                 "%s does not match %s\n", rname, handle->name);
394     GNUNET_NAMESTORE_zone_iterator_next (handle->list_it);
395     return;
396   }
397
398   json_resource = GNUNET_REST_jsonapi_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO,
399                                                     rname);
400   result_array = json_array ();
401   for (i=0; i<rd_len; i++)
402   {
403     if ( (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) &&
404          (0 != strcmp (rname, "+")) )
405       continue;
406
407     if ( (rd[i].record_type != handle->type) &&
408          (GNUNET_GNSRECORD_TYPE_ANY != handle->type) )
409       continue;
410     record_obj = gnsrecord_to_json (&(rd[i]));
411     json_array_append (result_array, record_obj);
412     json_decref (record_obj);
413   }
414   GNUNET_REST_jsonapi_resource_add_attr (json_resource,
415                                          GNUNET_REST_JSONAPI_NAMESTORE_RECORD,
416                                          result_array);
417   GNUNET_REST_jsonapi_object_resource_add (handle->resp_object, json_resource);
418   json_decref (result_array);
419   GNUNET_NAMESTORE_zone_iterator_next (handle->list_it);
420 }
421
422 static void
423 create_finished (void *cls, int32_t success, const char *emsg)
424 {
425   struct RequestHandle *handle = cls;
426   struct MHD_Response *resp;
427
428   handle->add_qe = NULL;
429   if (GNUNET_YES != success)
430   {
431     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
432                 "Error storing records%s%s\n",
433                 (NULL == emsg) ? "" : ": ",
434                 (NULL == emsg) ? "" : emsg);
435     GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
436     return;
437   }
438   resp = GNUNET_REST_create_json_response (NULL);
439   handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
440   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
441 }
442
443
444 /**
445  * We're storing a new record; this requires
446  * that no record already exists
447  *
448  * @param cls closure, unused
449  * @param zone_key private key of the zone
450  * @param rec_name name that is being mapped (at most 255 characters long)
451  * @param rd_count number of entries in @a rd array
452  * @param rd array of records with data to store
453  */
454 static void
455 create_new_record_cont (void *cls,
456                         const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
457                         const char *rec_name,
458                         unsigned int rd_count,
459                         const struct GNUNET_GNSRECORD_Data *rd)
460 {
461   struct RequestHandle *handle = cls;
462
463   handle->add_qe = NULL;
464   if ( (NULL != zone_key) &&
465        (0 != strcmp (rec_name, handle->name)) )
466   {
467     GNUNET_break (0);
468     GNUNET_SCHEDULER_add_now (&do_error, handle);
469     return;
470   }
471
472   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
473               "Received %u records for name `%s'\n",
474               rd_count, rec_name);
475   if (0 != rd_count)
476   {
477     handle->proc (handle->proc_cls,
478                 GNUNET_REST_create_json_response (NULL),
479                 MHD_HTTP_CONFLICT);
480     GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
481     return;
482   }
483
484   GNUNET_assert (NULL != handle->name);
485   handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
486                                                    &handle->zone_pkey,
487                                                    handle->name,
488                                                    handle->rd_count,
489                                                    handle->rd,
490                                                    &create_finished,
491                                                    handle);
492 }
493
494 static void
495 del_finished (void *cls,
496               int32_t success,
497               const char *emsg)
498 {
499   struct RequestHandle *handle = cls;
500
501   handle->add_qe = NULL;
502   if (GNUNET_NO == success)
503   {
504     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
505                 _("Deleting record failed, record does not exist%s%s\n"),
506                 (NULL != emsg) ? ": " : "",
507                 (NULL != emsg) ? emsg : "");
508     GNUNET_SCHEDULER_add_now (&do_error, handle); //do_not_found TODO
509     return;
510   }
511   if (GNUNET_SYSERR == success)
512   {
513     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
514                 _("Deleting record failed%s%s\n"),
515                 (NULL != emsg) ? ": " : "",
516                 (NULL != emsg) ? emsg : "");
517     GNUNET_SCHEDULER_add_now (&do_error, handle);
518     return;
519   }
520   handle->proc (handle->proc_cls,
521                 GNUNET_REST_create_json_response (NULL),
522                 MHD_HTTP_NO_CONTENT);
523   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
524 }
525
526 static void
527 del_cont (void *cls,
528              const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
529              const char *label,
530              unsigned int rd_count,
531              const struct GNUNET_GNSRECORD_Data *rd)
532 {
533   struct RequestHandle *handle = cls;
534
535   if (0 == rd_count)
536   {
537     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
538                 _("There are no records under label `%s' that could be deleted.\n"),
539                 label);
540     GNUNET_SCHEDULER_add_now (&do_error, handle);
541     return;
542   }
543
544   handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
545                                                    &handle->zone_pkey,
546                                                    handle->name,
547                                                    0, NULL,
548                                                    &del_finished,
549                                                    handle);
550 }
551
552 static void
553 namestore_delete_cont (struct RestConnectionDataHandle *con,
554                        const char *url,
555                        void *cls)
556 {
557   struct RequestHandle *handle = cls;
558
559   if (NULL == handle->name)
560   {
561     GNUNET_SCHEDULER_add_now (&do_error, handle);
562     return;
563   }
564
565   handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
566                                                     &handle->zone_pkey,
567                                                     handle->name,
568                                                     &del_cont,
569                                                     handle);
570 }
571
572 static int
573 json_to_gnsrecord (const json_t *records_json,
574                    struct GNUNET_GNSRECORD_Data **rd,
575                    unsigned int *rd_count)
576 {
577   struct GNUNET_TIME_Relative etime_rel;
578   struct GNUNET_TIME_Absolute etime_abs;
579   char *value;
580   void *rdata;
581   size_t rdata_size;
582   const char *typestring;
583   const char *expirationstring;
584   int i;
585   json_t *type_json;
586   json_t *value_json;
587   json_t *record_json;
588   json_t *exp_json;
589   
590   *rd_count = json_array_size (records_json);
591   *rd = GNUNET_malloc (sizeof (struct GNUNET_GNSRECORD_Data) * *rd_count);
592   for (i = 0; i < *rd_count; i++)
593   {
594     memset (&((*rd)[i]), 0, sizeof (struct GNUNET_GNSRECORD_Data));
595     record_json = json_array_get (records_json, i);
596     type_json = json_object_get (record_json,
597                                  GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE);
598     if (!json_is_string (type_json))
599     {
600       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
601                   "Type property is no string\n");
602       return GNUNET_SYSERR;
603     }
604     typestring = json_string_value (type_json);
605     (*rd)[i].record_type = GNUNET_GNSRECORD_typename_to_number (typestring);
606     if (UINT32_MAX == (*rd)[i].record_type)
607     {
608       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unsupported type `%s'\n"),
609                   json_string_value (type_json));
610       return GNUNET_SYSERR;
611     }
612     value_json = json_object_get (record_json,
613                                   GNUNET_REST_JSONAPI_NAMESTORE_VALUE);
614     if (!json_is_string (value_json))
615     {
616       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
617                   "Value property is no string\n");
618       return GNUNET_SYSERR;
619     }
620     GNUNET_asprintf (&value, "%s", json_string_value (value_json));
621     if (GNUNET_OK != GNUNET_GNSRECORD_string_to_value ((*rd)[i].record_type,
622                                                        value,
623                                                        &rdata,
624                                                        &rdata_size))
625    {
626       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Value `%s' invalid for record type `%s'\n"),
627                   value, typestring);
628       return GNUNET_SYSERR;
629     }
630     (*rd)[i].data = rdata;
631     (*rd)[i].data_size = rdata_size;
632     /**TODO
633      * if (1 == handle->is_shadow)
634      rde->flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
635      if (1 != handle->is_public)
636      rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
637      */
638     exp_json = json_object_get (record_json,
639                                 GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION);
640     if (!json_is_string (exp_json))
641     {
642       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
643                   "Expiration property is no string\n");
644       return GNUNET_SYSERR;
645     }
646     expirationstring = json_string_value (exp_json);
647     if (0 == strcmp (expirationstring, "never"))
648     {
649       (*rd)[i].expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
650     }
651     else if (GNUNET_OK ==
652              GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
653                                                     &etime_rel))
654     {
655       (*rd)[i].expiration_time = etime_rel.rel_value_us;
656       (*rd)[i].flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
657     }
658     else if (GNUNET_OK ==
659              GNUNET_STRINGS_fancy_time_to_absolute (expirationstring,
660                                                     &etime_abs))
661     {
662       (*rd)[i].expiration_time = etime_abs.abs_value_us;
663     }
664     else 
665     {
666       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Value `%s' invalid for record type `%s'\n"),
667                   value, typestring);
668       return GNUNET_SYSERR;
669     }
670   }
671   return GNUNET_OK;
672 }
673
674 static void
675 namestore_create_cont (struct RestConnectionDataHandle *con,
676                        const char *url,
677                        void *cls)
678 {
679   struct RequestHandle *handle = cls;
680   struct MHD_Response *resp;
681   struct JsonApiObject *json_obj;
682   struct JsonApiResource *json_res;
683   json_t *name_json;
684   json_t *records_json;
685   char term_data[handle->data_size+1];
686
687   if (strlen (GNUNET_REST_API_NS_NAMESTORE) != strlen (handle->url))
688   {
689     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
690                 "Cannot create under %s\n", handle->url);
691     GNUNET_SCHEDULER_add_now (&do_error, handle);
692     return;
693   }
694   if (0 >= handle->data_size)
695   {
696     GNUNET_SCHEDULER_add_now (&do_error, handle);
697     return;
698   }
699   term_data[handle->data_size] = '\0';
700   memcpy (term_data, handle->data, handle->data_size);
701   json_obj = GNUNET_REST_jsonapi_object_parse (term_data);
702   if (NULL == json_obj)
703   {
704     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
705                 "Unable to parse JSONAPI Object from %s\n",
706                 term_data);
707     GNUNET_SCHEDULER_add_now (&do_error, handle);
708     return;
709   }
710   if (1 != GNUNET_REST_jsonapi_object_resource_count (json_obj))
711   {
712     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
713                 "Cannot create more than 1 resource! (Got %d)\n",
714                 GNUNET_REST_jsonapi_object_resource_count (json_obj));
715     GNUNET_REST_jsonapi_object_delete (json_obj);
716     GNUNET_SCHEDULER_add_now (&do_error, handle);
717     return;
718   }
719   json_res = GNUNET_REST_jsonapi_object_get_resource (json_obj, 0);
720   if (GNUNET_NO == GNUNET_REST_jsonapi_resource_check_type (json_res,
721                                                             GNUNET_REST_JSONAPI_NAMESTORE_RECORD))
722   {
723     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
724                 "Unsupported JSON data type\n");
725     GNUNET_REST_jsonapi_object_delete (json_obj);
726     resp = GNUNET_REST_create_json_response (NULL);
727     handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
728     cleanup_handle (handle);
729     return;
730   }
731   name_json = GNUNET_REST_jsonapi_resource_read_attr (json_res, GNUNET_REST_JSONAPI_KEY_ID);
732   if (!json_is_string (name_json))
733   {
734     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
735                 "Name property is no string\n");
736     GNUNET_REST_jsonapi_object_delete (json_obj); 
737     GNUNET_SCHEDULER_add_now (&do_error, handle);
738     return;
739   }
740   GNUNET_asprintf (&handle->name, "%s", json_string_value (name_json));
741   records_json = GNUNET_REST_jsonapi_resource_read_attr (json_res,
742                                                          GNUNET_REST_JSONAPI_NAMESTORE_RECORD);
743   if (NULL == records_json)
744   {
745     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
746                 "No records given\n");
747     GNUNET_REST_jsonapi_object_delete (json_obj);
748     GNUNET_SCHEDULER_add_now (&do_error, handle);
749     return;
750   }
751   if (GNUNET_SYSERR == json_to_gnsrecord (records_json, &handle->rd, &handle->rd_count))
752   {
753     GNUNET_REST_jsonapi_object_delete (json_obj);
754     GNUNET_SCHEDULER_add_now (&do_error, handle);
755     return;
756   }
757   GNUNET_REST_jsonapi_object_delete (json_obj);
758
759   handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
760                                                     &handle->zone_pkey,
761                                                     handle->name,
762                                                     &create_new_record_cont, handle );
763 }
764
765
766
767
768
769 static void
770 namestore_info_cont (struct RestConnectionDataHandle *con,
771                      const char *url,
772                      void *cls)
773 {
774   struct RequestHandle *handle = cls;
775   handle->list_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
776                                                            &handle->zone_pkey,
777                                                            &namestore_list_response,
778                                                            handle);
779 }
780
781 static char*
782 get_name_from_url (const char* url)
783 {
784   if (strlen (url) <= strlen (GNUNET_REST_API_NS_NAMESTORE))
785     return NULL;
786   return (char*)url + strlen (GNUNET_REST_API_NS_NAMESTORE) + 1;
787 }
788
789 /**
790  * Function called with the result from the check if the namestore
791  * service is actually running.  If it is, we start the actual
792  * operation.
793  *
794  * @param cls closure with our configuration
795  * @param result #GNUNET_YES if the namestore service is running
796  */
797 static void
798 testservice_task (void *cls,
799                   int result)
800 {
801   struct RequestHandle *handle = cls;
802   static const struct GNUNET_REST_RestConnectionHandler handlers[] = {
803     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE, &namestore_info_cont}, //list
804     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE, &namestore_create_cont}, //create
805     //    {MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_NAMESTORE, &namestore_edit_cont}, //update. TODO this shoul be PATCH
806     {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_NAMESTORE, &namestore_delete_cont}, //delete
807     GNUNET_REST_HANDLER_END
808   };
809
810   if (GNUNET_YES != result)
811   {
812     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Service `%s' is not running\n"),
813                 "namestore");
814     GNUNET_SCHEDULER_add_now (&do_error, handle);
815     return;
816   }
817   handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
818   if (NULL == handle->ns_handle)
819   {
820     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
821                 _("Failed to connect to namestore\n"));
822     GNUNET_SCHEDULER_add_now (&do_error, handle);
823     return;
824   }
825
826   if (GNUNET_NO == GNUNET_REST_handle_request (handle->conndata_handle, handlers, handle))
827     GNUNET_SCHEDULER_add_now (&do_error, (void*) handle);
828
829 }
830
831 /**
832  * Callback invoked from identity service with ego information.
833  * An @a ego of NULL means the ego was not found.
834  *
835  * @param cls closure with the configuration
836  * @param ego an ego known to identity service, or NULL
837  */
838 static void
839 identity_cb (void *cls,
840              const struct GNUNET_IDENTITY_Ego *ego)
841 {
842   struct RequestHandle *handle = cls;
843   struct MHD_Response *resp;
844
845   handle->ego_lookup = NULL;
846   if (NULL == ego)
847   {
848     if (NULL != handle->ego_name)
849     {
850       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
851                   _("Ego `%s' not known to identity service\n"),
852                   handle->ego_name);
853     }
854     resp = GNUNET_REST_create_json_response (NULL);
855     handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
856     cleanup_handle (handle);
857     return;
858   }
859   handle->zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
860   GNUNET_CLIENT_service_test ("namestore", handle->cfg,
861                               GNUNET_TIME_UNIT_SECONDS,
862                               &testservice_task,
863                               (void *) handle);
864 }
865
866 static void
867 default_ego_cb (void *cls,
868                 struct GNUNET_IDENTITY_Ego *ego,
869                 void **ctx,
870                 const char *name)
871 {
872   struct RequestHandle *handle = cls;
873   struct MHD_Response *resp;
874   handle->get_default = NULL;
875   if (NULL == ego)
876   {
877     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
878                 _("No default ego configured in identity service\n"));
879     resp = GNUNET_REST_create_json_response (NULL);
880     handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
881     cleanup_handle (handle);
882     return;
883   }
884   else
885   {
886     identity_cb (cls, ego);
887   }
888 }
889
890 static void
891 id_connect_cb (void *cls,
892                struct GNUNET_IDENTITY_Ego *ego,
893                void **ctx,
894                const char *name)
895 {
896   struct RequestHandle *handle = cls;
897   if (NULL == ego)
898   {
899     handle->get_default = GNUNET_IDENTITY_get (handle->identity_handle,
900                                                "namestore",
901                                                &default_ego_cb, handle);
902   }
903 }
904
905 static void
906 testservice_id_task (void *cls, int result)
907 {
908   struct RequestHandle *handle = cls;
909   struct MHD_Response *resp;
910   struct GNUNET_HashCode key;
911   char *ego;
912   char *name;
913
914   if (result != GNUNET_YES)
915   {
916     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
917                 _("Identity service is not running\n"));
918     resp = GNUNET_REST_create_json_response (NULL);
919     handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
920     cleanup_handle (handle);
921     return;
922   }
923   ego = NULL;
924   GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_EGO,
925                       strlen (GNUNET_REST_JSONAPI_NAMESTORE_EGO),
926                       &key);
927   if ( GNUNET_YES == 
928        GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
929                                                &key) )
930   {
931     ego = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
932                                              &key);
933   }
934   name = get_name_from_url (handle->url);
935   if (NULL != ego)
936     GNUNET_asprintf (&handle->ego_name, "%s", ego);
937   if (NULL != name)
938     GNUNET_asprintf (&handle->name, "%s", name);
939   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", handle->ego_name);
940   if (NULL == handle->ego_name)
941   {
942     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", handle->ego_name);
943     handle->identity_handle = GNUNET_IDENTITY_connect (handle->cfg, &id_connect_cb, handle);
944     if (NULL == handle->identity_handle)
945     {
946       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Cannot connect to identity service\n"));
947       resp = GNUNET_REST_create_json_response (NULL);
948       handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
949       cleanup_handle (handle);
950     }
951     return;
952   }
953   handle->ego_lookup = GNUNET_IDENTITY_ego_lookup (cfg,
954                                                    handle->ego_name,
955                                                    &identity_cb,
956                                                    handle);
957 }
958
959 /**
960  * Function processing the REST call
961  *
962  * @param method HTTP method
963  * @param url URL of the HTTP request
964  * @param data body of the HTTP request (optional)
965  * @param data_size length of the body
966  * @param proc callback function for the result
967  * @param proc_cls closure for callback function
968  * @return GNUNET_OK if request accepted
969  */
970 static void
971 rest_identity_process_request(struct RestConnectionDataHandle *conndata_handle,
972                               GNUNET_REST_ResultProcessor proc,
973                               void *proc_cls)
974 {
975   struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
976
977   handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
978   handle->proc_cls = proc_cls;
979   handle->proc = proc;
980   handle->conndata_handle = conndata_handle;
981   handle->data = conndata_handle->data;
982   handle->data_size = conndata_handle->data_size;
983   GNUNET_asprintf (&handle->url, "%s", conndata_handle->url);
984   if (handle->url[strlen (handle->url)-1] == '/')
985     handle->url[strlen (handle->url)-1] = '\0';
986   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
987               "Connecting...\n");
988   handle->cfg = cfg;
989   GNUNET_CLIENT_service_test ("identity",
990                               cfg,
991                               GNUNET_TIME_UNIT_SECONDS,
992                               &testservice_id_task,
993                               handle);
994   handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
995                                                        &do_error,
996                                                        handle);
997
998
999 }
1000
1001 /**
1002  * Entry point for the plugin.
1003  *
1004  * @param cls Config info
1005  * @return NULL on error, otherwise the plugin context
1006  */
1007 void *
1008 libgnunet_plugin_rest_namestore_init (void *cls)
1009 {
1010   static struct Plugin plugin;
1011   cfg = cls;
1012   struct GNUNET_REST_Plugin *api;
1013
1014   if (NULL != plugin.cfg)
1015     return NULL;                /* can only initialize once! */
1016   memset (&plugin, 0, sizeof (struct Plugin));
1017   plugin.cfg = cfg;
1018   api = GNUNET_new (struct GNUNET_REST_Plugin);
1019   api->cls = &plugin;
1020   api->name = GNUNET_REST_API_NS_NAMESTORE;
1021   api->process_request = &rest_identity_process_request;
1022   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1023               _("Namestore REST API initialized\n"));
1024   return api;
1025 }
1026
1027
1028 /**
1029  * Exit point from the plugin.
1030  *
1031  * @param cls the plugin context (as returned by "init")
1032  * @return always NULL
1033  */
1034 void *
1035 libgnunet_plugin_rest_namestore_done (void *cls)
1036 {
1037   struct GNUNET_REST_Plugin *api = cls;
1038   struct Plugin *plugin = api->cls;
1039
1040   plugin->cfg = NULL;
1041   GNUNET_free (api);
1042   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1043               "Namestore REST plugin is finished\n");
1044   return NULL;
1045 }
1046
1047 /* end of plugin_rest_namestore.c */