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