- give control over CORS methods to plugin
[oweals/gnunet.git] / src / identity / plugin_rest_identity.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 identity/plugin_rest_identity.c
23  * @brief GNUnet Namestore REST plugin
24  *
25  */
26
27 #include "platform.h"
28 #include "gnunet_rest_plugin.h"
29 #include "gnunet_identity_service.h"
30 #include "gnunet_rest_lib.h"
31 #include "microhttpd.h"
32 #include <jansson.h>
33
34 #define GNUNET_REST_API_NS_IDENTITY "/identity"
35
36 #define ID_REST_STATE_INIT 0
37
38 #define ID_REST_STATE_POST_INIT 1
39
40 #define GNUNET_REST_JSONAPI_IDENTITY_EGO "ego"
41
42 #define GNUNET_REST_JSONAPI_IDENTITY_KEY "key"
43
44 #define GNUNET_REST_JSONAPI_IDENTITY_NEWNAME "newname"
45
46 #define GNUNET_REST_JSONAPI_IDENTITY_SUBSYSTEM "subsystem"
47
48 /**
49  * @brief struct returned by the initialization function of the plugin
50  */
51 struct Plugin
52 {
53   const struct GNUNET_CONFIGURATION_Handle *cfg;
54 };
55
56 const struct GNUNET_CONFIGURATION_Handle *cfg;
57
58 static char* allow_methods;
59
60 struct EgoEntry
61 {
62   /**
63    * DLL
64    */
65   struct EgoEntry *next;
66   
67   /**
68    * DLL
69    */
70   struct EgoEntry *prev;
71   
72   /**
73    * Ego Identifier
74    */
75   char *identifier;
76   
77   /**
78    * Ego Pkey
79    */
80   struct GNUNET_CRYPTO_EcdsaPublicKey pk;
81
82   /**
83    * The Ego
84    */
85   struct GNUNET_IDENTITY_Ego *ego;
86 };
87
88
89 struct RequestHandle
90 {
91   /**
92    * Ego list
93    */
94   struct EgoEntry *ego_head;
95
96   /**
97    * Ego list
98    */
99   struct EgoEntry *ego_tail;
100
101   struct RestConnectionDataHandle *conndata_handle;
102   
103   /**
104    * The processing state
105    */
106   int state;
107
108   /**
109    * Handle to GNS service.
110    */
111   struct GNUNET_IDENTITY_Handle *identity_handle;
112
113   /**
114    * IDENTITY Operation
115    */
116   struct GNUNET_IDENTITY_Operation *op;
117
118   /**
119    * Desired timeout for the lookup (default is no timeout).
120    */
121   struct GNUNET_TIME_Relative timeout;
122
123   /**
124    * ID of a task associated with the resolution process.
125    */
126   struct GNUNET_SCHEDULER_Task * timeout_task;    
127
128   /**
129    * The root of the received JSON or NULL
130    */
131   json_t *json_root;
132
133   /**
134    * The plugin result processor
135    */
136   GNUNET_REST_ResultProcessor proc;
137
138   /**
139    * The closure of the result processor
140    */
141   void *proc_cls;
142
143   /**
144    * The name to look up
145    */
146   char *name;
147
148   /**
149    * The subsystem set from REST
150    */
151   char *subsys;
152
153   /**
154    * The url
155    */
156   char *url;
157
158   /**
159    * The data from the REST request
160    */
161   const char* data;
162
163   /**
164    * the length of the REST data
165    */
166   size_t data_size;
167
168   /**
169    * HTTP method
170    */
171   const char* method;
172
173 };
174
175
176 /**
177  * Cleanup lookup handle
178  * @param handle Handle to clean up
179  */
180 static void
181 cleanup_handle (struct RequestHandle *handle)
182 {
183   struct EgoEntry *ego_entry;
184   struct EgoEntry *ego_tmp;
185   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
186               "Cleaning up\n");
187   if (NULL != handle->name)
188     GNUNET_free (handle->name);
189   if (NULL != handle->timeout_task)
190     GNUNET_SCHEDULER_cancel (handle->timeout_task);
191   if (NULL != handle->identity_handle)
192     GNUNET_IDENTITY_disconnect (handle->identity_handle);
193   if (NULL != handle->subsys)
194     GNUNET_free (handle->subsys);
195   if (NULL != handle->url)
196     GNUNET_free (handle->url);
197   for (ego_entry = handle->ego_head;
198        NULL != ego_entry;)
199   {
200     ego_tmp = ego_entry;
201     ego_entry = ego_entry->next;
202     GNUNET_free (ego_tmp->identifier);
203     GNUNET_free (ego_tmp);
204   }
205   GNUNET_free (handle);
206 }
207
208
209 /**
210  * Task run on shutdown.  Cleans up everything.
211  *
212  * @param cls unused
213  * @param tc scheduler context
214  */
215 static void
216 do_error (void *cls,
217           const struct GNUNET_SCHEDULER_TaskContext *tc)
218 {
219   struct RequestHandle *handle = cls;
220   struct MHD_Response *resp = GNUNET_REST_create_json_response (NULL);
221   handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
222   cleanup_handle (handle);
223 }
224
225 /**
226  * Callback for IDENTITY_get()
227  *
228  * @param cls the RequestHandle
229  * @param ego the Ego found
230  * @param ctx the context
231  * @param name the id of the ego
232  */
233 static void
234 get_ego_for_subsys (void *cls,
235                     struct GNUNET_IDENTITY_Ego *ego,
236                     void **ctx,
237                     const char *name)
238 {
239   struct RequestHandle *handle = cls;
240   struct JsonApiObject *json_object;
241   struct JsonApiResource *json_resource;
242   struct EgoEntry *ego_entry;
243   struct MHD_Response *resp;
244   json_t *key_json;
245   char *result_str;
246   char *keystring;
247
248   json_object = GNUNET_REST_jsonapi_object_new ();
249   
250   for (ego_entry = handle->ego_head;
251        NULL != ego_entry;
252        ego_entry = ego_entry->next)
253   {
254     if ( (NULL != name) && (0 != strcmp (name, ego_entry->identifier)) )
255       continue;
256     if (NULL == name)
257       continue;
258     json_resource = GNUNET_REST_jsonapi_resource_new (GNUNET_REST_JSONAPI_IDENTITY_EGO, ego_entry->identifier);
259     keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&ego_entry->pk);
260     key_json = json_string (keystring);
261     GNUNET_REST_jsonapi_resource_add_attr (json_resource, GNUNET_REST_JSONAPI_IDENTITY_KEY, key_json);
262     json_decref (key_json);
263     GNUNET_free (keystring);
264     GNUNET_REST_jsonapi_object_resource_add (json_object, json_resource);
265     break;
266   }
267   if (0 == GNUNET_REST_jsonapi_object_resource_count (json_object))
268   {
269     GNUNET_REST_jsonapi_object_delete (json_object);
270     GNUNET_SCHEDULER_add_now (&do_error, handle);
271     return;
272   }
273   GNUNET_REST_jsonapi_data_serialize (json_object, &result_str);
274   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
275   resp = GNUNET_REST_create_json_response (result_str);
276   GNUNET_REST_jsonapi_object_delete (json_object);
277   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
278   GNUNET_free (result_str);
279   cleanup_handle (handle);
280 }
281
282 /**
283  * Create a response with requested ego(s)
284  *
285  * @param handle the RequestHandle
286  */
287 static void
288 ego_info_response (struct RestConnectionDataHandle *con,
289                    const char *url,
290                    void *cls)
291 {
292   const char *egoname;
293   char *keystring;
294   char *result_str;
295   char *subsys_val;
296   struct RequestHandle *handle = cls;
297   struct EgoEntry *ego_entry;
298   struct GNUNET_HashCode key;
299   struct MHD_Response *resp;
300   struct JsonApiObject *json_object;
301   struct JsonApiResource *json_resource;
302   json_t *key_str;
303   if (GNUNET_NO == GNUNET_REST_namespace_match (handle->url, GNUNET_REST_API_NS_IDENTITY))
304   {
305     resp = GNUNET_REST_create_json_response (NULL);
306     handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
307     cleanup_handle (handle);
308     return;
309   }
310   if ( (strlen (GNUNET_REST_API_NS_IDENTITY) == strlen (handle->url) )) {
311     GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_SUBSYSTEM, strlen (GNUNET_REST_JSONAPI_IDENTITY_SUBSYSTEM), &key);
312     if ( GNUNET_YES ==
313          GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
314                                                  &key) )
315     {
316       subsys_val = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
317                                                       &key);
318       if (NULL != subsys_val)
319       {
320         GNUNET_asprintf (&handle->subsys, "%s", subsys_val);
321         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking for %s's ego\n", subsys_val);
322         handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
323                                           handle->subsys,
324                                           &get_ego_for_subsys,
325                                           handle);
326         return;
327       }
328     }
329   }
330   json_object = GNUNET_REST_jsonapi_object_new ();
331   egoname = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY)+1];
332
333   if (strlen (GNUNET_REST_API_NS_IDENTITY) == strlen (handle->url))
334   {
335     egoname = NULL;
336   }
337   //Return all egos
338   for (ego_entry = handle->ego_head;
339        NULL != ego_entry;
340        ego_entry = ego_entry->next)
341   {
342     if ( (NULL != egoname) && (0 != strcmp (egoname, ego_entry->identifier)) )
343       continue;
344     keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&ego_entry->pk);
345     json_resource = GNUNET_REST_jsonapi_resource_new (GNUNET_REST_JSONAPI_IDENTITY_EGO, ego_entry->identifier);
346     key_str = json_string (keystring);
347     GNUNET_REST_jsonapi_resource_add_attr (json_resource,
348                                            GNUNET_REST_JSONAPI_IDENTITY_KEY,
349                                            key_str);
350     json_decref (key_str);
351     GNUNET_free (keystring);
352     GNUNET_REST_jsonapi_object_resource_add (json_object, json_resource);
353   }
354   if (0 == GNUNET_REST_jsonapi_object_resource_count (json_object))
355   {
356     GNUNET_REST_jsonapi_object_delete (json_object);
357     GNUNET_SCHEDULER_add_now (&do_error, handle);
358     return;
359   }
360   GNUNET_REST_jsonapi_data_serialize (json_object, &result_str);
361   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
362   resp = GNUNET_REST_create_json_response (result_str);
363   GNUNET_REST_jsonapi_object_delete (json_object);
364   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
365   GNUNET_free (result_str);
366   cleanup_handle (handle);
367 }
368
369 static void
370 do_finished (void *cls, const char *emsg)
371 {
372   struct RequestHandle *handle = cls;
373   struct MHD_Response *resp;
374
375   handle->op = NULL;
376   if (NULL != emsg)
377   {
378     GNUNET_SCHEDULER_add_now (&do_error, handle);
379     return;
380   }
381   resp = GNUNET_REST_create_json_response (NULL);
382   handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
383   cleanup_handle (handle);
384 }
385
386 static void
387 edit_finished (void *cls, const char *emsg)
388 {
389   struct RequestHandle *handle = cls;
390   struct MHD_Response *resp;
391   
392   handle->op = NULL;
393   if (NULL != emsg)
394   {
395     GNUNET_SCHEDULER_add_now (&do_error, handle);
396     return;
397   }
398   resp = GNUNET_REST_create_json_response (NULL);
399   handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
400   cleanup_handle (handle);
401 }
402
403 static void
404 create_finished (void *cls, const char *emsg)
405 {
406   struct RequestHandle *handle = cls;
407   struct MHD_Response *resp;
408
409   handle->op = NULL;
410   if (NULL != emsg)
411   {
412     GNUNET_SCHEDULER_add_now (&do_error, handle);
413     return;
414   }
415   resp = GNUNET_REST_create_json_response (NULL);
416   handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
417   cleanup_handle (handle);
418 }
419
420 static void
421 ego_create_cont (struct RestConnectionDataHandle *con,
422                  const char *url,
423                  void *cls)
424 {
425   struct RequestHandle *handle = cls;
426   struct EgoEntry *ego_entry;
427   struct MHD_Response *resp;
428   struct JsonApiObject *json_obj;
429   struct JsonApiResource *json_res;
430   json_t *egoname_json;
431   const char* egoname;
432   char term_data[handle->data_size+1];
433
434   if (strlen (GNUNET_REST_API_NS_IDENTITY) != strlen (handle->url))
435   {
436     GNUNET_SCHEDULER_add_now (&do_error, handle);
437     return;
438   }
439   if (0 >= handle->data_size)
440   {
441     GNUNET_SCHEDULER_add_now (&do_error, handle);
442     return;
443   }
444   term_data[handle->data_size] = '\0';
445   memcpy (term_data, handle->data, handle->data_size);
446   json_obj = GNUNET_REST_jsonapi_object_parse (term_data);
447   if (NULL == json_obj)
448   {
449     GNUNET_SCHEDULER_add_now (&do_error, handle);
450     return;
451   }
452   if (1 != GNUNET_REST_jsonapi_object_resource_count (json_obj))
453   {
454     GNUNET_REST_jsonapi_object_delete (json_obj);
455     GNUNET_SCHEDULER_add_now (&do_error, handle);
456     return;
457   }
458   json_res = GNUNET_REST_jsonapi_object_get_resource (json_obj, 0);
459   if (GNUNET_NO == GNUNET_REST_jsonapi_resource_check_type (json_res, GNUNET_REST_JSONAPI_IDENTITY_EGO))
460   {
461     GNUNET_REST_jsonapi_object_delete (json_obj);
462     resp = GNUNET_REST_create_json_response (NULL);
463     handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
464     cleanup_handle (handle);
465     return;
466   }
467   egoname_json = GNUNET_REST_jsonapi_resource_read_attr (json_res, GNUNET_REST_JSONAPI_KEY_ID);
468   if (!json_is_string (egoname_json))
469   {
470     GNUNET_REST_jsonapi_object_delete (json_obj); 
471     GNUNET_SCHEDULER_add_now (&do_error, handle);
472     return;
473   }
474   egoname = json_string_value (egoname_json);
475   for (ego_entry = handle->ego_head;
476        NULL != ego_entry;
477        ego_entry = ego_entry->next)
478   {
479     if (0 == strcasecmp (egoname, ego_entry->identifier))
480     {
481       GNUNET_REST_jsonapi_object_delete (json_obj);
482       resp = GNUNET_REST_create_json_response (NULL);
483       handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
484       cleanup_handle (handle);
485       return;
486     }
487   }
488   GNUNET_asprintf (&handle->name, "%s", egoname);
489   GNUNET_REST_jsonapi_object_delete (json_obj);
490   handle->op = GNUNET_IDENTITY_create (handle->identity_handle,
491                                        handle->name,
492                                        &create_finished,
493                                        handle);
494 }
495
496
497 /**
498  * Handle ego edit request
499  *
500  * @param con rest connection handle
501  * @param url the url that is requested
502  * @param cls the RequestHandle
503  */
504 static void 
505 ego_edit_cont (struct RestConnectionDataHandle *con,
506                  const char *url,
507                  void *cls)
508 {
509   struct JsonApiObject *json_obj;
510   struct JsonApiResource *json_res;
511   struct RequestHandle *handle = cls;
512   struct EgoEntry *ego_entry;
513   struct MHD_Response *resp;
514   json_t *subsys_json;
515   json_t *name_json;
516   const char *egoname;
517   const char *subsys;
518   const char *newname;
519   char term_data[handle->data_size+1];
520   int ego_exists = GNUNET_NO;
521   
522   if (strlen (GNUNET_REST_API_NS_IDENTITY) > strlen (handle->url))
523   {
524     GNUNET_SCHEDULER_add_now (&do_error, handle);
525     return;
526   }
527
528   egoname = &handle->url[strlen(GNUNET_REST_API_NS_IDENTITY)+1];
529   for (ego_entry = handle->ego_head;
530        NULL != ego_entry;
531        ego_entry = ego_entry->next)
532   {
533     if (0 == strcasecmp (egoname, ego_entry->identifier))
534     {
535       ego_exists = GNUNET_YES;
536       break;
537     }
538   }
539   if (GNUNET_NO == ego_exists)
540   {
541     resp = GNUNET_REST_create_json_response (NULL);
542     handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
543     cleanup_handle (handle);
544     return;
545   }
546
547   if (0 >= handle->data_size)
548   {
549     GNUNET_SCHEDULER_add_now (&do_error, handle);
550     return;
551   }
552
553   term_data[handle->data_size] = '\0';
554   memcpy (term_data, handle->data, handle->data_size);
555   json_obj = GNUNET_REST_jsonapi_object_parse (term_data);
556
557   if (NULL == json_obj)
558   {
559     GNUNET_SCHEDULER_add_now (&do_error, handle);
560     return;
561   }
562   if (1 != GNUNET_REST_jsonapi_object_resource_count (json_obj))
563   {
564     GNUNET_REST_jsonapi_object_delete (json_obj);
565     GNUNET_SCHEDULER_add_now (&do_error, handle);
566     return;
567   }
568   json_res = GNUNET_REST_jsonapi_object_get_resource (json_obj, 0); 
569   if (GNUNET_NO == GNUNET_REST_jsonapi_resource_check_type (json_res, GNUNET_REST_JSONAPI_IDENTITY_EGO))
570   {
571     GNUNET_REST_jsonapi_object_delete (json_obj);
572     GNUNET_SCHEDULER_add_now (&do_error, handle);
573     return;
574   }
575     //This is a rename
576   name_json = GNUNET_REST_jsonapi_resource_read_attr (json_res, GNUNET_REST_JSONAPI_IDENTITY_NEWNAME);
577   if (NULL != name_json)
578   {
579     newname = NULL;
580     if (json_is_string (name_json))
581     {
582       newname = json_string_value (name_json);
583       handle->op = GNUNET_IDENTITY_rename (handle->identity_handle,
584                                       egoname,
585                                       newname,
586                                       &edit_finished,
587                                       handle);
588       GNUNET_REST_jsonapi_object_delete (json_obj);
589       return;
590     }
591   }
592
593   subsys_json = GNUNET_REST_jsonapi_resource_read_attr (json_res, GNUNET_REST_JSONAPI_IDENTITY_SUBSYSTEM);
594   if (NULL != subsys_json)
595   {
596     subsys = NULL;
597     if (json_is_string (subsys_json))
598     {
599       subsys = json_string_value (subsys_json);
600       GNUNET_asprintf (&handle->subsys, "%s", subsys);
601       GNUNET_REST_jsonapi_object_delete (json_obj);
602       handle->op = GNUNET_IDENTITY_set (handle->identity_handle,
603                                         handle->subsys,
604                                         ego_entry->ego,
605                                         &edit_finished,
606                                         handle);
607       return;
608     }
609   }
610   GNUNET_REST_jsonapi_object_delete (json_obj);
611   GNUNET_SCHEDULER_add_now (&do_error, handle);
612   
613 }
614
615 void 
616 ego_delete_cont (struct RestConnectionDataHandle *con_handle,
617                  const char* url,
618                  void *cls)
619 {
620   const char *egoname;
621   struct EgoEntry *ego_entry;
622   struct MHD_Response *resp;
623   struct RequestHandle *handle = cls;
624   int ego_exists = GNUNET_NO;
625
626   if (strlen (GNUNET_REST_API_NS_IDENTITY) >= strlen (handle->url))
627   {
628     GNUNET_SCHEDULER_add_now (&do_error, handle);
629     return;
630   }
631
632   egoname = &handle->url[strlen(GNUNET_REST_API_NS_IDENTITY)+1];
633   for (ego_entry = handle->ego_head;
634        NULL != ego_entry;
635        ego_entry = ego_entry->next)
636   {
637     if (0 == strcasecmp (egoname, ego_entry->identifier))
638     {
639       ego_exists = GNUNET_YES;
640       break;
641     }
642   }
643   if (GNUNET_NO == ego_exists)
644   {
645     resp = GNUNET_REST_create_json_response (NULL);
646     handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
647     cleanup_handle (handle);
648     return;
649   }
650   handle->op = GNUNET_IDENTITY_delete (handle->identity_handle,
651                                        egoname,
652                                        &do_finished,
653                                        handle);
654
655 }
656
657 void
658 options_cont (struct RestConnectionDataHandle *con_handle,
659               const char* url,
660               void *cls)
661 {
662   struct MHD_Response *resp;
663   struct RequestHandle *handle = cls;
664
665   //For now, independent of path return all options
666   resp = GNUNET_REST_create_json_response (NULL);
667   MHD_add_response_header (resp,
668                            "Access-Control-Allow-Methods",
669                            allow_methods);
670   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
671   cleanup_handle (handle);
672   return;
673 }
674
675 /**
676  * Handle rest request
677  *
678  * @param handle the request handle
679  */
680 static void
681 init_cont (struct RequestHandle *handle)
682 {
683   static const struct GNUNET_REST_RestConnectionHandler handlers[] = {
684     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY, &ego_info_response},
685     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY, &ego_create_cont},
686     {MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY, &ego_edit_cont},
687     {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_IDENTITY, &ego_delete_cont},
688     {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY, &options_cont},
689     GNUNET_REST_HANDLER_END
690   };
691
692   if (GNUNET_NO == GNUNET_REST_handle_request (handle->conndata_handle, handlers, handle))
693     GNUNET_SCHEDULER_add_now (&do_error, handle);
694 }
695
696 /**
697  * If listing is enabled, prints information about the egos.
698  *
699  * This function is initially called for all egos and then again
700  * whenever a ego's identifier changes or if it is deleted.  At the
701  * end of the initial pass over all egos, the function is once called
702  * with 'NULL' for 'ego'. That does NOT mean that the callback won't
703  * be invoked in the future or that there was an error.
704  *
705  * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
706  * this function is only called ONCE, and 'NULL' being passed in
707  * 'ego' does indicate an error (i.e. name is taken or no default
708  * value is known).  If 'ego' is non-NULL and if '*ctx'
709  * is set in those callbacks, the value WILL be passed to a subsequent
710  * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
711  * that one was not NULL).
712  *
713  * When an identity is renamed, this function is called with the
714  * (known) ego but the NEW identifier.
715  *
716  * When an identity is deleted, this function is called with the
717  * (known) ego and "NULL" for the 'identifier'.  In this case,
718  * the 'ego' is henceforth invalid (and the 'ctx' should also be
719  * cleaned up).
720  *
721  * @param cls closure
722  * @param ego ego handle
723  * @param ctx context for application to store data for this ego
724  *                 (during the lifetime of this process, initially NULL)
725  * @param identifier identifier assigned by the user for this ego,
726  *                   NULL if the user just deleted the ego and it
727  *                   must thus no longer be used
728  */
729 static void
730 list_ego (void *cls,
731           struct GNUNET_IDENTITY_Ego *ego,
732           void **ctx,
733           const char *identifier)
734 {
735   struct RequestHandle *handle = cls;
736   struct EgoEntry *ego_entry;
737
738   if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
739   {
740     handle->state = ID_REST_STATE_POST_INIT;
741     init_cont (handle);
742     return;
743   }
744   if (ID_REST_STATE_INIT == handle->state) {
745     ego_entry = GNUNET_new (struct EgoEntry);
746     GNUNET_IDENTITY_ego_get_public_key (ego, &(ego_entry->pk));
747     ego_entry->ego = ego;
748     GNUNET_asprintf (&ego_entry->identifier, "%s", identifier);
749     GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
750   }
751
752 }
753
754 /**
755  * Function processing the REST call
756  *
757  * @param method HTTP method
758  * @param url URL of the HTTP request
759  * @param data body of the HTTP request (optional)
760  * @param data_size length of the body
761  * @param proc callback function for the result
762  * @param proc_cls closure for callback function
763  * @return GNUNET_OK if request accepted
764  */
765 static void
766 rest_identity_process_request(struct RestConnectionDataHandle *conndata_handle,
767                               GNUNET_REST_ResultProcessor proc,
768                               void *proc_cls)
769 {
770   struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
771
772
773
774   handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
775
776   handle->proc_cls = proc_cls;
777   handle->proc = proc;
778   handle->state = ID_REST_STATE_INIT;
779   handle->conndata_handle = conndata_handle;
780   handle->data = conndata_handle->data;
781   handle->data_size = conndata_handle->data_size;
782   handle->method = conndata_handle->method;
783   GNUNET_asprintf (&handle->url, "%s", conndata_handle->url);
784   if (handle->url[strlen (handle->url)-1] == '/')
785     handle->url[strlen (handle->url)-1] = '\0';
786   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
787               "Connecting...\n");
788   handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
789                                                      &list_ego,
790                                                      handle); 
791   handle->timeout_task =
792     GNUNET_SCHEDULER_add_delayed (handle->timeout,
793                                   &do_error,
794                                   handle);
795
796
797   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
798               "Connected\n");
799 }
800
801 /**
802  * Entry point for the plugin.
803  *
804  * @param cls Config info
805  * @return NULL on error, otherwise the plugin context
806  */
807 void *
808 libgnunet_plugin_rest_identity_init (void *cls)
809 {
810   static struct Plugin plugin;
811   cfg = cls;
812   struct GNUNET_REST_Plugin *api;
813
814   if (NULL != plugin.cfg)
815     return NULL;                /* can only initialize once! */
816   memset (&plugin, 0, sizeof (struct Plugin));
817   plugin.cfg = cfg;
818   api = GNUNET_new (struct GNUNET_REST_Plugin);
819   api->cls = &plugin;
820   api->name = GNUNET_REST_API_NS_IDENTITY;
821   api->process_request = &rest_identity_process_request;
822   GNUNET_asprintf (&allow_methods,
823                    "%s, %s, %s, %s, %s",
824                    MHD_HTTP_METHOD_GET,
825                    MHD_HTTP_METHOD_POST,
826                    MHD_HTTP_METHOD_PUT,
827                    MHD_HTTP_METHOD_DELETE,
828                    MHD_HTTP_METHOD_OPTIONS);
829
830   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
831               _("Identity REST API initialized\n"));
832   return api;
833 }
834
835
836 /**
837  * Exit point from the plugin.
838  *
839  * @param cls the plugin context (as returned by "init")
840  * @return always NULL
841  */
842 void *
843 libgnunet_plugin_rest_identity_done (void *cls)
844 {
845   struct GNUNET_REST_Plugin *api = cls;
846   struct Plugin *plugin = api->cls;
847
848   plugin->cfg = NULL;
849   GNUNET_free_non_null (allow_methods);
850   GNUNET_free (api);
851   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
852               "Identity REST plugin is finished\n");
853   return NULL;
854 }
855
856 /* end of plugin_rest_gns.c */