24607bf614ffbe9fb45098e9c8a6820127a31344
[oweals/gnunet.git] / src / social / social_api.c
1  /*
2  * This file is part of GNUnet
3  * Copyright (C) 2013 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., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 /**
22  * @file social/social_api.c
23  * @brief Social service; implements social interactions using the PSYC service.
24  * @author Gabor X Toth
25  */
26
27 #include <inttypes.h>
28 #include <string.h>
29
30 #include "platform.h"
31 #include "gnunet_util_lib.h"
32 #include "gnunet_env_lib.h"
33 #include "gnunet_core_service.h"
34 #include "gnunet_identity_service.h"
35 #include "gnunet_namestore_service.h"
36 #include "gnunet_gns_service.h"
37 #include "gnunet_psyc_service.h"
38 #include "gnunet_psyc_util_lib.h"
39 #include "gnunet_social_service.h"
40 #include "social.h"
41
42 #define LOG(kind,...) GNUNET_log_from (kind, "social-api",__VA_ARGS__)
43
44
45 static struct GNUNET_CORE_Handle *core;
46 static struct GNUNET_GNS_Handle *gns;
47 static struct GNUNET_NAMESTORE_Handle *namestore;
48 static struct GNUNET_PeerIdentity this_peer;
49
50
51 /**
52  * Handle for a pseudonym of another user in the network.
53  */
54 struct GNUNET_SOCIAL_Nym
55 {
56   struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
57   struct GNUNET_HashCode pub_key_hash;
58 };
59
60
61 /**
62  * Handle for a place where social interactions happen.
63  */
64 struct GNUNET_SOCIAL_Place
65 {
66   /**
67    * Configuration to use.
68    */
69   const struct GNUNET_CONFIGURATION_Handle *cfg;
70
71   /**
72    * Client connection to the service.
73    */
74   struct GNUNET_CLIENT_MANAGER_Connection *client;
75
76   /**
77    * Transmission handle.
78    */
79   struct GNUNET_PSYC_TransmitHandle *tmit;
80
81   /**
82    * Receipt handle.
83    */
84   struct GNUNET_PSYC_ReceiveHandle *recv;
85
86   /**
87    * Slicer for processing incoming methods.
88    */
89   struct GNUNET_SOCIAL_Slicer *slicer;
90
91   /**
92    * Message to send on reconnect.
93    */
94   struct GNUNET_MessageHeader *connect_msg;
95
96   /**
97    * Function called after disconnected from the service.
98    */
99   GNUNET_ContinuationCallback disconnect_cb;
100
101   /**
102    * Closure for @a disconnect_cb.
103    */
104   void *disconnect_cls;
105
106   /**
107    * Public key of the place.
108    */
109   struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
110
111   /**
112    * Private key of the ego.
113    */
114   struct GNUNET_CRYPTO_EcdsaPrivateKey ego_key;
115
116   /**
117    * Does this place belong to a host (#GNUNET_YES) or guest (#GNUNET_NO)?
118    */
119   uint8_t is_host;
120
121   /**
122    * Is this place in the process of disconnecting from the service?
123    * #GNUNET_YES or #GNUNET_NO
124    */
125   uint8_t is_disconnecting;
126 };
127
128
129 /**
130  * Host handle for a place that we entered.
131  */
132 struct GNUNET_SOCIAL_Host
133 {
134   struct GNUNET_SOCIAL_Place plc;
135
136   struct GNUNET_CRYPTO_EddsaPrivateKey place_key;
137
138   /**
139    * Receipt handle.
140    */
141   struct GNUNET_PSYC_ReceiveHandle *recv;
142
143   /**
144    * Slicer for processing incoming methods.
145    */
146   struct GNUNET_SOCIAL_Slicer *slicer;
147
148   GNUNET_SOCIAL_HostEnterCallback enter_cb;
149
150   GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb;
151
152   GNUNET_SOCIAL_FarewellCallback farewell_cb;
153
154   /**
155    * Closure for callbacks.
156    */
157   void *cb_cls;
158
159   struct GNUNET_SOCIAL_Nym *notice_place_leave_nym;
160   struct GNUNET_ENV_Environment *notice_place_leave_env;
161 };
162
163
164 /**
165  * Guest handle for place that we entered.
166  */
167 struct GNUNET_SOCIAL_Guest
168 {
169   struct GNUNET_SOCIAL_Place plc;
170
171   /**
172    * Receipt handle.
173    */
174   struct GNUNET_PSYC_ReceiveHandle *recv;
175
176   /**
177    * Slicer for processing incoming methods.
178    */
179   struct GNUNET_SOCIAL_Slicer *slicer;
180
181   GNUNET_SOCIAL_GuestEnterCallback enter_cb;
182
183   GNUNET_SOCIAL_EntryDecisionCallback entry_dcsn_cb;
184
185   /**
186    * Closure for callbacks.
187    */
188   void *cb_cls;
189 };
190
191
192 /**
193  * Hash map of all nyms.
194  * pub_key_hash -> struct GNUNET_SOCIAL_Nym *
195  */
196 struct GNUNET_CONTAINER_MultiHashMap *nyms;
197
198
199 /**
200  * Handle for a try-and-slice instance.
201  */
202 struct GNUNET_SOCIAL_Slicer
203 {
204   /**
205    * Method handlers: method_name -> SlicerMethodCallbacks
206    */
207   struct GNUNET_CONTAINER_MultiHashMap *method_handlers;
208
209   /**
210    * Modifier handlers: modifier name -> SlicerModifierCallbacks
211    */
212   struct GNUNET_CONTAINER_MultiHashMap *modifier_handlers;
213
214   /**
215    * Currently being processed message part.
216    */
217   const struct GNUNET_MessageHeader *msg;
218
219   /**
220    * ID of currently being received message.
221    */
222   uint64_t message_id;
223
224   /**
225    * Method name of currently being received message.
226    */
227   char *method_name;
228
229   /**
230    * Name of currently processed modifier.
231    */
232   char *mod_name;
233
234   /**
235    * Value of currently processed modifier.
236    */
237   char *mod_value;
238
239   /**
240    * Public key of the nym the current message originates from.
241    */
242   struct GNUNET_CRYPTO_EcdsaPublicKey nym_key;
243
244   /**
245    * Size of @a method_name (including terminating \0).
246    */
247   uint16_t method_name_size;
248
249   /**
250    * Size of @a modifier_name (including terminating \0).
251    */
252   uint16_t mod_name_size;
253
254   /**
255    * Size of modifier value fragment.
256    */
257   uint16_t mod_value_size;
258
259   /**
260    * Full size of modifier value.
261    */
262   uint16_t mod_full_value_size;
263
264   /**
265    * Remaining bytes from the value of the current modifier.
266    */
267   uint16_t mod_value_remaining;
268
269   /**
270    * Operator of currently processed modifier.
271    */
272   uint8_t mod_oper;
273 };
274
275
276 /**
277  * Callbacks for a slicer method handler.
278  */
279 struct SlicerMethodCallbacks
280 {
281   GNUNET_SOCIAL_MethodCallback method_cb;
282   GNUNET_SOCIAL_ModifierCallback modifier_cb;
283   GNUNET_SOCIAL_DataCallback data_cb;
284   GNUNET_SOCIAL_EndOfMessageCallback eom_cb;
285   void *cls;
286 };
287
288
289 struct SlicerMethodRemoveClosure
290 {
291   struct GNUNET_SOCIAL_Slicer *slicer;
292   struct SlicerMethodCallbacks rm_cbs;
293 };
294
295
296 /**
297  * Callbacks for a slicer method handler.
298  */
299 struct SlicerModifierCallbacks
300 {
301   GNUNET_SOCIAL_ModifierCallback modifier_cb;
302   void *cls;
303 };
304
305
306 struct SlicerModifierRemoveClosure
307 {
308   struct GNUNET_SOCIAL_Slicer *slicer;
309   struct SlicerModifierCallbacks rm_cbs;
310 };
311
312
313 /**
314  * Handle for an announcement request.
315  */
316 struct GNUNET_SOCIAL_Announcement
317 {
318
319 };
320
321
322 /**
323  * A talk request.
324  */
325 struct GNUNET_SOCIAL_TalkRequest
326 {
327
328 };
329
330
331 /**
332  * A history lesson.
333  */
334 struct GNUNET_SOCIAL_HistoryRequest
335 {
336   /**
337    * Place.
338    */
339   struct GNUNET_SOCIAL_Place *plc;
340
341   /**
342    * Operation ID.
343    */
344   uint64_t op_id;
345
346   /**
347    * Message handler.
348    */
349   struct GNUNET_PSYC_ReceiveHandle *recv;
350
351   /**
352    * Function to call when the operation finished.
353    */
354   GNUNET_ResultCallback result_cb;
355
356   /**
357    * Closure for @a result_cb.
358    */
359   void *cls;
360 };
361
362
363 struct GNUNET_SOCIAL_LookHandle
364 {
365   /**
366    * Place.
367    */
368   struct GNUNET_SOCIAL_Place *plc;
369
370   /**
371    * Operation ID.
372    */
373   uint64_t op_id;
374
375   /**
376    * State variable result callback.
377    */
378   GNUNET_PSYC_StateVarCallback var_cb;
379
380   /**
381    * Function to call when the operation finished.
382    */
383   GNUNET_ResultCallback result_cb;
384
385   /**
386    * Name of current modifier being received.
387    */
388   char *mod_name;
389
390   /**
391    * Size of current modifier value being received.
392    */
393   size_t mod_value_size;
394
395   /**
396    * Remaining size of current modifier value still to be received.
397    */
398   size_t mod_value_remaining;
399
400   /**
401    * Closure for @a result_cb.
402    */
403   void *cls;
404 };
405
406
407 /*** NYM ***/
408
409 static struct GNUNET_SOCIAL_Nym *
410 nym_get_or_create (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub_key)
411 {
412   struct GNUNET_SOCIAL_Nym *nym = NULL;
413   struct GNUNET_HashCode pub_key_hash;
414
415   if (NULL == pub_key)
416     return NULL;
417
418   GNUNET_CRYPTO_hash (pub_key, sizeof (*pub_key), &pub_key_hash);
419
420   if (NULL == nyms)
421     nyms = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
422   else
423     nym = GNUNET_CONTAINER_multihashmap_get (nyms, &pub_key_hash);
424
425   if (NULL == nym)
426   {
427     nym = GNUNET_new (struct GNUNET_SOCIAL_Nym);
428     nym->pub_key = *pub_key;
429     nym->pub_key_hash = pub_key_hash;
430     GNUNET_CONTAINER_multihashmap_put (nyms, &nym->pub_key_hash, nym,
431                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
432   }
433   return nym;
434 }
435
436
437 static void
438 nym_destroy (struct GNUNET_SOCIAL_Nym *nym)
439 {
440   GNUNET_CONTAINER_multihashmap_remove (nyms, &nym->pub_key_hash, nym);
441   GNUNET_free (nym);
442 }
443
444
445 /*** MESSAGE HANDLERS ***/
446
447 /** _notice_place_leave from guests */
448
449 static void
450 host_recv_notice_place_leave_method (void *cls,
451                                      const struct GNUNET_PSYC_MessageMethod *meth,
452                                      uint64_t message_id,
453                                      uint32_t flags,
454                                      const struct GNUNET_SOCIAL_Nym *nym,
455                                      const char *method_name)
456 {
457   struct GNUNET_SOCIAL_Host *hst = cls;
458   if (0 == memcmp (&(struct GNUNET_CRYPTO_EcdsaPublicKey) {},
459                    &nym->pub_key, sizeof (nym->pub_key)))
460     return;
461
462   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
463               "Host received method for message ID %" PRIu64 " from nym %s: %s\n",
464               message_id, GNUNET_h2s (&nym->pub_key_hash), method_name);
465
466   hst->notice_place_leave_nym = (struct GNUNET_SOCIAL_Nym *) nym;
467   hst->notice_place_leave_env = GNUNET_ENV_environment_create ();
468
469   char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&hst->notice_place_leave_nym->pub_key);
470   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
471               "_notice_place_leave: got method from nym %s (%s).\n",
472               GNUNET_h2s (&hst->notice_place_leave_nym->pub_key_hash), str);
473 }
474
475
476 static void
477 host_recv_notice_place_leave_modifier (void *cls,
478                                        const struct GNUNET_MessageHeader *msg,
479                                        uint64_t message_id,
480                                        enum GNUNET_ENV_Operator oper,
481                                        const char *name,
482                                        const void *value,
483                                        uint16_t value_size,
484                                        uint16_t full_value_size)
485 {
486   struct GNUNET_SOCIAL_Host *hst = cls;
487   if (NULL == hst->notice_place_leave_env)
488     return;
489
490   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
491               "Host received modifier for _notice_place_leave message with ID %" PRIu64 ":\n"
492               "%c%s: %.*s\n",
493               message_id, oper, name, value_size, value);
494
495   /* skip _nym, it's added later in eom() */
496   if (0 == memcmp (name, "_nym", sizeof ("_nym"))
497       || 0 == memcmp (name, "_nym_", sizeof ("_nym_") - 1))
498     return;
499
500   GNUNET_ENV_environment_add (hst->notice_place_leave_env,
501                               GNUNET_ENV_OP_SET, name, value, value_size);
502 }
503
504
505 static void
506 host_recv_notice_place_leave_eom (void *cls,
507                                   const struct GNUNET_MessageHeader *msg,
508                                   uint64_t message_id,
509                                   uint8_t cancelled)
510 {
511   struct GNUNET_SOCIAL_Host *hst = cls;
512   if (NULL == hst->notice_place_leave_env)
513     return;
514
515   char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&hst->notice_place_leave_nym->pub_key);
516   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
517               "_notice_place_leave: got EOM from nym %s (%s).\n",
518               GNUNET_h2s (&hst->notice_place_leave_nym->pub_key_hash), str);
519
520   if (GNUNET_YES != cancelled)
521   {
522     if (NULL != hst->farewell_cb)
523       hst->farewell_cb (hst->cb_cls, hst->notice_place_leave_nym,
524                         hst->notice_place_leave_env);
525     /* announce leaving guest to place */
526     GNUNET_ENV_environment_add (hst->notice_place_leave_env, GNUNET_ENV_OP_SET,
527                                 "_nym", hst->notice_place_leave_nym,
528                                 sizeof (*hst->notice_place_leave_nym));
529     GNUNET_SOCIAL_host_announce (hst, "_notice_place_leave",
530                                  hst->notice_place_leave_env,
531                                  NULL, NULL, GNUNET_SOCIAL_ANNOUNCE_NONE);
532     nym_destroy (hst->notice_place_leave_nym);
533   }
534   GNUNET_ENV_environment_destroy (hst->notice_place_leave_env);
535   hst->notice_place_leave_env = NULL;
536 }
537
538
539 /*** SLICER ***/
540
541 /**
542  * Call a method handler for an incoming message part.
543  */
544 int
545 slicer_method_handler_notify (void *cls, const struct GNUNET_HashCode *key,
546                               void *value)
547 {
548   struct GNUNET_SOCIAL_Slicer *slicer = cls;
549   const struct GNUNET_MessageHeader *msg = slicer->msg;
550   struct SlicerMethodCallbacks *cbs = value;
551   uint16_t ptype = ntohs (msg->type);
552
553   switch (ptype)
554   {
555   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD:
556   {
557     if (NULL == cbs->method_cb)
558       break;
559     struct GNUNET_PSYC_MessageMethod *
560       meth = (struct GNUNET_PSYC_MessageMethod *) msg;
561     cbs->method_cb (cbs->cls, meth, slicer->message_id,
562                     ntohl (meth->flags),
563                     nym_get_or_create (&slicer->nym_key),
564                     slicer->method_name);
565     break;
566   }
567
568   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
569   {
570     if (NULL == cbs->modifier_cb)
571       break;
572     struct GNUNET_PSYC_MessageModifier *
573       mod = (struct GNUNET_PSYC_MessageModifier *) msg;
574     cbs->modifier_cb (cbs->cls, &mod->header, slicer->message_id,
575                       mod->oper, (const char *) &mod[1],
576                       (const void *) &mod[1] + ntohs (mod->name_size),
577                       ntohs (mod->header.size) - sizeof (*mod) - ntohs (mod->name_size),
578                       ntohs (mod->value_size));
579     break;
580   }
581
582   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
583   {
584     if (NULL == cbs->modifier_cb)
585       break;
586     cbs->modifier_cb (cbs->cls, msg, slicer->message_id,
587                       slicer->mod_oper, slicer->mod_name, &msg[1],
588                       ntohs (msg->size) - sizeof (*msg),
589                       slicer->mod_full_value_size);
590     break;
591   }
592
593   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
594   {
595     if (NULL == cbs->data_cb)
596       break;
597     uint64_t data_offset = 0; // FIXME
598     cbs->data_cb (cbs->cls, msg, slicer->message_id,
599                   data_offset, &msg[1], ntohs (msg->size) - sizeof (*msg));
600     break;
601   }
602
603   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
604     if (NULL == cbs->eom_cb)
605       break;
606     cbs->eom_cb (cbs->cls, msg, slicer->message_id, GNUNET_NO);
607     break;
608
609   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
610     if (NULL == cbs->eom_cb)
611       break;
612     cbs->eom_cb (cbs->cls, msg, slicer->message_id, GNUNET_YES);
613     break;
614   }
615   return GNUNET_YES;
616 }
617
618
619 /**
620  * Call a method handler for an incoming message part.
621  */
622 int
623 slicer_modifier_handler_notify (void *cls, const struct GNUNET_HashCode *key,
624                                 void *value)
625 {
626   struct GNUNET_SOCIAL_Slicer *slicer = cls;
627   struct SlicerModifierCallbacks *cbs = value;
628
629   cbs->modifier_cb (cbs->cls, slicer->msg, slicer->message_id, slicer->mod_oper,
630                     slicer->mod_name, slicer->mod_value,
631                     slicer->mod_value_size, slicer->mod_full_value_size);
632   return GNUNET_YES;
633 }
634
635
636 /**
637  * Process an incoming message part and call matching handlers.
638  *
639  * @param cls
640  *        Closure.
641  * @param message_id
642  *        ID of the message.
643  * @param flags
644  *        Flags for the message.
645  *        @see enum GNUNET_PSYC_MessageFlags
646  * @param msg
647  *        The message part. as it arrived from the network.
648  */
649 static void
650 slicer_message (void *cls, const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
651                 uint64_t message_id, uint32_t flags, uint64_t fragment_offset,
652                 const struct GNUNET_MessageHeader *msg)
653 {
654   struct GNUNET_SOCIAL_Slicer *slicer = cls;
655   slicer->nym_key = *slave_key;
656
657   uint16_t ptype = ntohs (msg->type);
658   if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == ptype)
659   {
660     struct GNUNET_PSYC_MessageMethod *
661       meth = (struct GNUNET_PSYC_MessageMethod *) msg;
662     slicer->method_name_size = ntohs (meth->header.size) - sizeof (*meth);
663     slicer->method_name = GNUNET_malloc (slicer->method_name_size);
664     memcpy (slicer->method_name, &meth[1], slicer->method_name_size);
665     slicer->message_id = message_id;
666   }
667   else
668   {
669     GNUNET_assert (message_id == slicer->message_id);
670   }
671
672   char *nym_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (slave_key);
673   LOG (GNUNET_ERROR_TYPE_DEBUG,
674        "Slicer received message of type %u and size %u, "
675        "with ID %" PRIu64 " and method %s from %s\n",
676        ptype, ntohs (msg->size), message_id, slicer->method_name, nym_str);
677   GNUNET_free (nym_str);
678
679   slicer->msg = msg;
680
681   /* try-and-slice modifier */
682
683   switch (ptype)
684   {
685   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
686   {
687     struct GNUNET_PSYC_MessageModifier *
688       mod = (struct GNUNET_PSYC_MessageModifier *) msg;
689     slicer->mod_oper = mod->oper;
690     slicer->mod_name_size = ntohs (mod->name_size);
691     slicer->mod_name = GNUNET_malloc (slicer->mod_name_size);
692     memcpy (slicer->mod_name, &mod[1], slicer->mod_name_size);
693     slicer->mod_value = (char *) &mod[1] + slicer->mod_name_size;
694     slicer->mod_full_value_size = ntohs (mod->value_size);
695     slicer->mod_value_remaining = slicer->mod_full_value_size;
696     slicer->mod_value_size
697       = ntohs (mod->header.size) - sizeof (*mod) - slicer->mod_name_size;
698   }
699   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
700     if (ptype == GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT)
701     {
702       slicer->mod_value = (char *) &msg[1];
703       slicer->mod_value_size = ntohs (msg->size) - sizeof (*msg);
704     }
705     slicer->mod_value_remaining -= slicer->mod_value_size;
706     char *name = GNUNET_malloc (slicer->mod_name_size);
707     memcpy (name, slicer->mod_name, slicer->mod_name_size);
708     do
709     {
710       struct GNUNET_HashCode key;
711       uint16_t name_len = strlen (name);
712       GNUNET_CRYPTO_hash (name, name_len, &key);
713       GNUNET_CONTAINER_multihashmap_get_multiple (slicer->modifier_handlers, &key,
714                                                   slicer_modifier_handler_notify,
715                                                   slicer);
716       char *p = strrchr (name, '_');
717       if (NULL == p)
718         break;
719       *p = '\0';
720     } while (1);
721     GNUNET_free (name);
722   }
723
724   /* try-and-slice method */
725
726   char *name = GNUNET_malloc (slicer->method_name_size);
727   memcpy (name, slicer->method_name, slicer->method_name_size);
728   do
729   {
730     struct GNUNET_HashCode key;
731     uint16_t name_len = strlen (name);
732     GNUNET_CRYPTO_hash (name, name_len, &key);
733     GNUNET_CONTAINER_multihashmap_get_multiple (slicer->method_handlers, &key,
734                                                 slicer_method_handler_notify,
735                                                 slicer);
736     char *p = strrchr (name, '_');
737     if (NULL == p)
738       break;
739     *p = '\0';
740   } while (1);
741   GNUNET_free (name);
742
743   if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype)
744     GNUNET_free (slicer->method_name);
745
746   if (0 == slicer->mod_value_remaining && NULL != slicer->mod_name)
747   {
748     GNUNET_free (slicer->mod_name);
749     slicer->mod_name = NULL;
750     slicer->mod_name_size = 0;
751     slicer->mod_value_size = 0;
752     slicer->mod_full_value_size = 0;
753     slicer->mod_oper = 0;
754   }
755
756   slicer->msg = NULL;
757 }
758
759
760 /**
761  * Create a try-and-slice instance.
762  *
763  * A slicer processes incoming messages and notifies callbacks about matching
764  * methods or modifiers encountered.
765  *
766  * @return A new try-and-slice construct.
767  */
768 struct GNUNET_SOCIAL_Slicer *
769 GNUNET_SOCIAL_slicer_create (void)
770 {
771   struct GNUNET_SOCIAL_Slicer *slicer = GNUNET_malloc (sizeof (*slicer));
772   slicer->method_handlers = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
773   slicer->modifier_handlers = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
774   return slicer;
775 }
776
777
778 /**
779  * Add a method to the try-and-slice instance.
780  *
781  * The callbacks are called for messages with a matching @a method_name prefix.
782  *
783  * @param slicer
784  *        The try-and-slice instance to extend.
785  * @param method_name
786  *        Name of the given method, use empty string to match all.
787  * @param method_cb
788  *        Method handler invoked upon a matching message.
789  * @param modifier_cb
790  *        Modifier handler, invoked after @a method_cb
791  *        for each modifier in the message.
792  * @param data_cb
793  *        Data handler, invoked after @a modifier_cb for each data fragment.
794  * @param eom_cb
795  *        Invoked upon reaching the end of a matching message.
796  * @param cls
797  *        Closure for the callbacks.
798  */
799 void
800 GNUNET_SOCIAL_slicer_method_add (struct GNUNET_SOCIAL_Slicer *slicer,
801                                  const char *method_name,
802                                  GNUNET_SOCIAL_MethodCallback method_cb,
803                                  GNUNET_SOCIAL_ModifierCallback modifier_cb,
804                                  GNUNET_SOCIAL_DataCallback data_cb,
805                                  GNUNET_SOCIAL_EndOfMessageCallback eom_cb,
806                                  void *cls)
807 {
808   struct GNUNET_HashCode key;
809   GNUNET_CRYPTO_hash (method_name, strlen (method_name), &key);
810
811   struct SlicerMethodCallbacks *cbs = GNUNET_malloc (sizeof (*cbs));
812   cbs->method_cb = method_cb;
813   cbs->modifier_cb = modifier_cb;
814   cbs->data_cb = data_cb;
815   cbs->eom_cb = eom_cb;
816   cbs->cls = cls;
817
818   GNUNET_CONTAINER_multihashmap_put (slicer->method_handlers, &key, cbs,
819                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
820 }
821
822
823 int
824 slicer_method_remove (void *cls, const struct GNUNET_HashCode *key, void *value)
825 {
826   struct SlicerMethodRemoveClosure *rm_cls = cls;
827   struct GNUNET_SOCIAL_Slicer *slicer = rm_cls->slicer;
828   struct SlicerMethodCallbacks *rm_cbs = &rm_cls->rm_cbs;
829   struct SlicerMethodCallbacks *cbs = value;
830
831   if (cbs->method_cb == rm_cbs->method_cb
832       && cbs->modifier_cb == rm_cbs->modifier_cb
833       && cbs->data_cb == rm_cbs->data_cb
834       && cbs->eom_cb == rm_cbs->eom_cb)
835   {
836     GNUNET_CONTAINER_multihashmap_remove (slicer->method_handlers, key, cbs);
837     GNUNET_free (cbs);
838     return GNUNET_NO;
839   }
840   return GNUNET_YES;
841 }
842
843
844 /**
845  * Remove a registered method from the try-and-slice instance.
846  *
847  * Removes one matching handler registered with the given
848  * @a method_name and  callbacks.
849  *
850  * @param slicer
851  *        The try-and-slice instance.
852  * @param method_name
853  *        Name of the method to remove.
854  * @param method_cb
855  *        Method handler.
856  * @param modifier_cb
857  *        Modifier handler.
858  * @param data_cb
859  *        Data handler.
860  * @param eom_cb
861  *        End of message handler.
862  *
863  * @return #GNUNET_OK if a method handler was removed,
864  *         #GNUNET_NO if no handler matched the given method name and callbacks.
865  */
866 int
867 GNUNET_SOCIAL_slicer_method_remove (struct GNUNET_SOCIAL_Slicer *slicer,
868                                     const char *method_name,
869                                     GNUNET_SOCIAL_MethodCallback method_cb,
870                                     GNUNET_SOCIAL_ModifierCallback modifier_cb,
871                                     GNUNET_SOCIAL_DataCallback data_cb,
872                                     GNUNET_SOCIAL_EndOfMessageCallback eom_cb)
873 {
874   struct GNUNET_HashCode key;
875   GNUNET_CRYPTO_hash (method_name, strlen (method_name), &key);
876
877   struct SlicerMethodRemoveClosure rm_cls;
878   rm_cls.slicer = slicer;
879   struct SlicerMethodCallbacks *rm_cbs = &rm_cls.rm_cbs;
880   rm_cbs->method_cb = method_cb;
881   rm_cbs->modifier_cb = modifier_cb;
882   rm_cbs->data_cb = data_cb;
883   rm_cbs->eom_cb = eom_cb;
884
885   return
886     (GNUNET_SYSERR
887      == GNUNET_CONTAINER_multihashmap_get_multiple (slicer->method_handlers, &key,
888                                                     slicer_method_remove,
889                                                     &rm_cls))
890     ? GNUNET_NO
891     : GNUNET_OK;
892 }
893
894
895 /**
896  * Watch a place for changed objects.
897  *
898  * @param slicer
899  *        The try-and-slice instance.
900  * @param object_filter
901  *        Object prefix to match.
902  * @param modifier_cb
903  *        Function to call when encountering a state modifier.
904  * @param cls
905  *        Closure for callback.
906  */
907 void
908 GNUNET_SOCIAL_slicer_modifier_add (struct GNUNET_SOCIAL_Slicer *slicer,
909                                    const char *object_filter,
910                                    GNUNET_SOCIAL_ModifierCallback modifier_cb,
911                                    void *cls)
912 {
913   struct SlicerModifierCallbacks *cbs = GNUNET_malloc (sizeof *cbs);
914   cbs->modifier_cb = modifier_cb;
915   cbs->cls = cls;
916
917   struct GNUNET_HashCode key;
918   GNUNET_CRYPTO_hash (object_filter, strlen (object_filter), &key);
919   GNUNET_CONTAINER_multihashmap_put (slicer->modifier_handlers, &key, cbs,
920                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
921 }
922
923
924 int
925 slicer_modifier_remove (void *cls, const struct GNUNET_HashCode *key, void *value)
926 {
927   struct SlicerModifierRemoveClosure *rm_cls = cls;
928   struct GNUNET_SOCIAL_Slicer *slicer = rm_cls->slicer;
929   struct SlicerModifierCallbacks *rm_cbs = &rm_cls->rm_cbs;
930   struct SlicerModifierCallbacks *cbs = value;
931
932   if (cbs->modifier_cb == rm_cbs->modifier_cb)
933   {
934     GNUNET_CONTAINER_multihashmap_remove (slicer->modifier_handlers, key, cbs);
935     GNUNET_free (cbs);
936     return GNUNET_NO;
937   }
938   return GNUNET_YES;
939 }
940
941
942 /**
943  * Remove a registered modifier from the try-and-slice instance.
944  *
945  * Removes one matching handler registered with the given
946  * @a object_filter and @a modifier_cb.
947  *
948  * @param slicer
949  *        The try-and-slice instance.
950  * @param object_filter
951  *        Object prefix to match.
952  * @param modifier_cb
953  *        Function to call when encountering a state modifier changes.
954  */
955 int
956 GNUNET_SOCIAL_slicer_modifier_remove (struct GNUNET_SOCIAL_Slicer *slicer,
957                                       const char *object_filter,
958                                       GNUNET_SOCIAL_ModifierCallback modifier_cb)
959 {
960   struct GNUNET_HashCode key;
961   GNUNET_CRYPTO_hash (object_filter, strlen (object_filter), &key);
962
963   struct SlicerModifierRemoveClosure rm_cls;
964   rm_cls.slicer = slicer;
965   struct SlicerModifierCallbacks *rm_cbs = &rm_cls.rm_cbs;
966   rm_cbs->modifier_cb = modifier_cb;
967
968   return
969     (GNUNET_SYSERR
970      == GNUNET_CONTAINER_multihashmap_get_multiple (slicer->modifier_handlers, &key,
971                                                     slicer_modifier_remove,
972                                                     &rm_cls))
973     ? GNUNET_NO
974     : GNUNET_OK;
975  }
976
977
978 int
979 slicer_method_free (void *cls, const struct GNUNET_HashCode *key, void *value)
980 {
981   struct SlicerMethodCallbacks *cbs = value;
982   GNUNET_free (cbs);
983   return GNUNET_YES;
984 }
985
986
987 /**
988  * Destroy a given try-and-slice instance.
989  *
990  * @param slicer
991  *        Slicer to destroy
992  */
993 void
994 GNUNET_SOCIAL_slicer_destroy (struct GNUNET_SOCIAL_Slicer *slicer)
995 {
996   GNUNET_CONTAINER_multihashmap_iterate (slicer->method_handlers,
997                                          slicer_method_free, NULL);
998   GNUNET_CONTAINER_multihashmap_destroy (slicer->method_handlers);
999   GNUNET_free (slicer);
1000 }
1001
1002
1003 /*** PLACE ***/
1004
1005
1006 static void
1007 place_send_connect_msg (struct GNUNET_SOCIAL_Place *plc)
1008 {
1009   uint16_t cmsg_size = ntohs (plc->connect_msg->size);
1010   struct GNUNET_MessageHeader * cmsg = GNUNET_malloc (cmsg_size);
1011   memcpy (cmsg, plc->connect_msg, cmsg_size);
1012   GNUNET_CLIENT_MANAGER_transmit_now (plc->client, cmsg);
1013 }
1014
1015
1016 static void
1017 place_recv_disconnect (void *cls,
1018                        struct GNUNET_CLIENT_MANAGER_Connection *client,
1019                        const struct GNUNET_MessageHeader *msg)
1020 {
1021   struct GNUNET_SOCIAL_Place *
1022     plc = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*plc));
1023
1024   GNUNET_CLIENT_MANAGER_reconnect (client);
1025   place_send_connect_msg (plc);
1026 }
1027
1028
1029 static void
1030 place_recv_result (void *cls,
1031                    struct GNUNET_CLIENT_MANAGER_Connection *client,
1032                    const struct GNUNET_MessageHeader *msg)
1033 {
1034   struct GNUNET_SOCIAL_Place *
1035     plc = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*plc));
1036
1037   const struct GNUNET_OperationResultMessage *
1038     res = (const struct GNUNET_OperationResultMessage *) msg;
1039
1040   uint16_t size = ntohs (msg->size);
1041   if (size < sizeof (*res))
1042   { /* Error, message too small. */
1043     GNUNET_break (0);
1044     return;
1045   }
1046
1047   uint16_t data_size = size - sizeof (*res);
1048   const char *data = (0 < data_size) ? (const char *) &res[1] : NULL;
1049   GNUNET_CLIENT_MANAGER_op_result (plc->client, GNUNET_ntohll (res->op_id),
1050                                    GNUNET_ntohll (res->result_code),
1051                                    data, data_size);
1052 }
1053
1054
1055 static void
1056 op_recv_history_result (void *cls, int64_t result,
1057                         const void *err_msg, uint16_t err_msg_size)
1058 {
1059   LOG (GNUNET_ERROR_TYPE_DEBUG,
1060        "Received history replay result: %" PRId64 ".\n", result);
1061
1062   struct GNUNET_SOCIAL_HistoryRequest *hist = cls;
1063
1064   if (NULL != hist->result_cb)
1065     hist->result_cb (hist->cls, result, err_msg, err_msg_size);
1066
1067   GNUNET_PSYC_receive_destroy (hist->recv);
1068   GNUNET_free (hist);
1069 }
1070
1071
1072 static void
1073 op_recv_state_result (void *cls, int64_t result,
1074                       const void *err_msg, uint16_t err_msg_size)
1075 {
1076   LOG (GNUNET_ERROR_TYPE_DEBUG,
1077        "Received state request result: %" PRId64 ".\n", result);
1078
1079   struct GNUNET_SOCIAL_LookHandle *look = cls;
1080
1081   if (NULL != look->result_cb)
1082     look->result_cb (look->cls, result, err_msg, err_msg_size);
1083
1084   GNUNET_free (look);
1085 }
1086
1087
1088 static void
1089 place_recv_history_result (void *cls,
1090                            struct GNUNET_CLIENT_MANAGER_Connection *client,
1091                            const struct GNUNET_MessageHeader *msg)
1092 {
1093   struct GNUNET_SOCIAL_Place *
1094     plc = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*plc));
1095
1096   const struct GNUNET_OperationResultMessage *
1097     res = (const struct GNUNET_OperationResultMessage *) msg;
1098   struct GNUNET_PSYC_MessageHeader *
1099     pmsg = (struct GNUNET_PSYC_MessageHeader *) &res[1];
1100
1101   LOG (GNUNET_ERROR_TYPE_DEBUG,
1102        "%p Received historic fragment for message #%" PRIu64 ".\n",
1103        plc, GNUNET_ntohll (pmsg->message_id));
1104
1105   GNUNET_ResultCallback result_cb = NULL;
1106   struct GNUNET_SOCIAL_HistoryRequest *hist = NULL;
1107
1108   if (GNUNET_YES != GNUNET_CLIENT_MANAGER_op_find (plc->client,
1109                                                    GNUNET_ntohll (res->op_id),
1110                                                    &result_cb, (void *) &hist))
1111   { /* Operation not found. */
1112     LOG (GNUNET_ERROR_TYPE_WARNING,
1113          "%p Replay operation not found for historic fragment of message #%"
1114          PRIu64 ".\n",
1115          plc, GNUNET_ntohll (pmsg->message_id));
1116     return;
1117   }
1118
1119   uint16_t size = ntohs (msg->size);
1120   if (size < sizeof (*res) + sizeof (*pmsg))
1121   { /* Error, message too small. */
1122     GNUNET_break (0);
1123     return;
1124   }
1125
1126   GNUNET_PSYC_receive_message (hist->recv,
1127                                (const struct GNUNET_PSYC_MessageHeader *) pmsg);
1128 }
1129
1130
1131 static void
1132 place_recv_state_result (void *cls,
1133                          struct GNUNET_CLIENT_MANAGER_Connection *client,
1134                          const struct GNUNET_MessageHeader *msg)
1135 {
1136   struct GNUNET_SOCIAL_Place *
1137     plc = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*plc));
1138
1139   const struct GNUNET_OperationResultMessage *
1140     res = (const struct GNUNET_OperationResultMessage *) msg;
1141
1142   GNUNET_ResultCallback result_cb = NULL;
1143   struct GNUNET_SOCIAL_LookHandle *look = NULL;
1144
1145   if (GNUNET_YES != GNUNET_CLIENT_MANAGER_op_find (plc->client,
1146                                                    GNUNET_ntohll (res->op_id),
1147                                                    &result_cb, (void *) &look))
1148   { /* Operation not found. */
1149     return;
1150   }
1151
1152   const struct GNUNET_MessageHeader *
1153     mod = (struct GNUNET_MessageHeader *) &res[1];
1154   uint16_t mod_size = ntohs (mod->size);
1155   if (ntohs (msg->size) - sizeof (*res) != mod_size)
1156   {
1157     GNUNET_break_op (0);
1158     LOG (GNUNET_ERROR_TYPE_WARNING,
1159          "Invalid modifier size in state result: %u - %u != %u\n",
1160          ntohs (msg->size), sizeof (*res), mod_size);
1161     return;
1162   }
1163   switch (ntohs (mod->type))
1164   {
1165   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
1166   {
1167     const struct GNUNET_PSYC_MessageModifier *
1168       pmod = (const struct GNUNET_PSYC_MessageModifier *) mod;
1169
1170     const char *name = (const char *) &pmod[1];
1171     uint16_t name_size = ntohs (pmod->name_size);
1172     if ('\0' != name[name_size - 1])
1173     {
1174       GNUNET_break_op (0);
1175       LOG (GNUNET_ERROR_TYPE_WARNING,
1176            "Invalid modifier name in state result\n");
1177       return;
1178     }
1179     look->mod_value_size = ntohs (pmod->value_size);
1180     look->var_cb (look->cls, mod, name, name + name_size,
1181                   mod_size - sizeof (*mod) - name_size,
1182                   look->mod_value_size);
1183     if (look->mod_value_size > mod_size - sizeof (*mod) - name_size)
1184     {
1185         look->mod_value_remaining = look->mod_value_size;
1186         look->mod_name = GNUNET_malloc (name_size);
1187         memcpy (look->mod_name, name, name_size);
1188     }
1189     break;
1190   }
1191
1192   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
1193     look->var_cb (look->cls, mod, look->mod_name, (const char *) &mod[1],
1194                   mod_size - sizeof (*mod), look->mod_value_size);
1195     look->mod_value_remaining -= mod_size - sizeof (*mod);
1196     if (0 == look->mod_value_remaining)
1197     {
1198         GNUNET_free (look->mod_name);
1199     }
1200     break;
1201   }
1202 }
1203
1204
1205 static void
1206 place_recv_message_ack (void *cls,
1207                         struct GNUNET_CLIENT_MANAGER_Connection *client,
1208                         const struct GNUNET_MessageHeader *msg)
1209 {
1210   struct GNUNET_SOCIAL_Place *
1211     plc = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*plc));
1212   GNUNET_PSYC_transmit_got_ack (plc->tmit);
1213 }
1214
1215
1216 static void
1217 place_recv_message (void *cls,
1218                     struct GNUNET_CLIENT_MANAGER_Connection *client,
1219                     const struct GNUNET_MessageHeader *msg)
1220 {
1221   struct GNUNET_SOCIAL_Place *
1222     plc = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*plc));
1223   GNUNET_PSYC_receive_message (plc->recv,
1224                                (const struct GNUNET_PSYC_MessageHeader *) msg);
1225 }
1226
1227
1228 static void
1229 host_recv_message (void *cls,
1230                    struct GNUNET_CLIENT_MANAGER_Connection *client,
1231                    const struct GNUNET_MessageHeader *msg)
1232 {
1233   struct GNUNET_SOCIAL_Host *
1234     hst = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (hst->plc));
1235   GNUNET_PSYC_receive_message (hst->recv,
1236                                (const struct GNUNET_PSYC_MessageHeader *) msg);
1237   GNUNET_PSYC_receive_message (hst->plc.recv,
1238                                (const struct GNUNET_PSYC_MessageHeader *) msg);
1239 }
1240
1241
1242 static void
1243 host_recv_enter_ack (void *cls,
1244                      struct GNUNET_CLIENT_MANAGER_Connection *client,
1245                      const struct GNUNET_MessageHeader *msg)
1246 {
1247   struct GNUNET_SOCIAL_Host *
1248     hst = GNUNET_CLIENT_MANAGER_get_user_context_ (client,
1249                                                    sizeof (struct GNUNET_SOCIAL_Place));
1250
1251   struct GNUNET_PSYC_CountersResultMessage *
1252     cres = (struct GNUNET_PSYC_CountersResultMessage *) msg;
1253   int32_t result = ntohl (cres->result_code);
1254   if (NULL != hst->enter_cb)
1255     hst->enter_cb (hst->cb_cls, result, GNUNET_ntohll (cres->max_message_id));
1256 }
1257
1258
1259 static void
1260 host_recv_enter_request (void *cls,
1261                          struct GNUNET_CLIENT_MANAGER_Connection *client,
1262                          const struct GNUNET_MessageHeader *msg)
1263 {
1264   struct GNUNET_SOCIAL_Host *
1265     hst = GNUNET_CLIENT_MANAGER_get_user_context_ (client,
1266                                                    sizeof (struct GNUNET_SOCIAL_Place));
1267   if (NULL == hst->answer_door_cb)
1268      return;
1269
1270   const char *method_name = NULL;
1271   struct GNUNET_ENV_Environment *env = NULL;
1272   struct GNUNET_PSYC_MessageHeader *entry_pmsg = NULL;
1273   const void *data = NULL;
1274   uint16_t data_size = 0;
1275   char *str;
1276   const struct GNUNET_PSYC_JoinRequestMessage *
1277     req = (const struct GNUNET_PSYC_JoinRequestMessage *) msg;
1278   const struct GNUNET_PSYC_Message *entry_msg = NULL;
1279
1280   do
1281   {
1282     if (sizeof (*req) + sizeof (*entry_msg) <= ntohs (req->header.size))
1283     {
1284       entry_msg = (struct GNUNET_PSYC_Message *) &req[1];
1285       LOG (GNUNET_ERROR_TYPE_DEBUG,
1286            "Received entry_msg of type %u and size %u.\n",
1287            ntohs (entry_msg->header.type), ntohs (entry_msg->header.size));
1288
1289       env = GNUNET_ENV_environment_create ();
1290       entry_pmsg = GNUNET_PSYC_message_header_create_from_psyc (entry_msg);
1291       if (GNUNET_OK != GNUNET_PSYC_message_parse (entry_pmsg, &method_name, env,
1292                                                   &data, &data_size))
1293       {
1294         GNUNET_break_op (0);
1295         str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&req->slave_key);
1296         LOG (GNUNET_ERROR_TYPE_WARNING,
1297              "Ignoring invalid entry request from nym %s.\n",
1298              str);
1299         GNUNET_free (str);
1300         break;
1301       }
1302     }
1303
1304     struct GNUNET_SOCIAL_Nym *nym = nym_get_or_create (&req->slave_key);
1305     hst->answer_door_cb (hst->cb_cls, nym, method_name, env,
1306                          data_size, data);
1307   } while (0);
1308
1309   if (NULL != env)
1310     GNUNET_ENV_environment_destroy (env);
1311   if (NULL != entry_pmsg)
1312     GNUNET_free (entry_pmsg);
1313 }
1314
1315
1316 static void
1317 guest_recv_enter_ack (void *cls,
1318                      struct GNUNET_CLIENT_MANAGER_Connection *client,
1319                      const struct GNUNET_MessageHeader *msg)
1320 {
1321   struct GNUNET_SOCIAL_Guest *
1322     gst = GNUNET_CLIENT_MANAGER_get_user_context_ (client,
1323                                                    sizeof (struct GNUNET_SOCIAL_Place));
1324
1325   struct GNUNET_PSYC_CountersResultMessage *
1326     cres = (struct GNUNET_PSYC_CountersResultMessage *) msg;
1327   int32_t result = ntohl (cres->result_code);
1328   if (NULL != gst->enter_cb)
1329     gst->enter_cb (gst->cb_cls, result, GNUNET_ntohll (cres->max_message_id));
1330 }
1331
1332
1333 static void
1334 guest_recv_join_decision (void *cls,
1335                           struct GNUNET_CLIENT_MANAGER_Connection *client,
1336                           const struct GNUNET_MessageHeader *msg)
1337 {
1338   struct GNUNET_SOCIAL_Guest *
1339     gst = GNUNET_CLIENT_MANAGER_get_user_context_ (client,
1340                                                    sizeof (struct GNUNET_SOCIAL_Place));
1341   const struct GNUNET_PSYC_JoinDecisionMessage *
1342     dcsn = (const struct GNUNET_PSYC_JoinDecisionMessage *) msg;
1343
1344   struct GNUNET_PSYC_Message *pmsg = NULL;
1345   if (ntohs (dcsn->header.size) <= sizeof (*dcsn) + sizeof (*pmsg))
1346     pmsg = (struct GNUNET_PSYC_Message *) &dcsn[1];
1347
1348   if (NULL != gst->entry_dcsn_cb)
1349     gst->entry_dcsn_cb (gst->cb_cls, ntohl (dcsn->is_admitted), pmsg);
1350 }
1351
1352
1353 static struct GNUNET_CLIENT_MANAGER_MessageHandler host_handlers[] =
1354 {
1355   { host_recv_enter_ack, NULL,
1356     GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK,
1357     sizeof (struct GNUNET_PSYC_CountersResultMessage), GNUNET_NO },
1358
1359   { host_recv_enter_request, NULL,
1360     GNUNET_MESSAGE_TYPE_PSYC_JOIN_REQUEST,
1361     sizeof (struct GNUNET_PSYC_JoinRequestMessage), GNUNET_YES },
1362
1363   { host_recv_message, NULL,
1364     GNUNET_MESSAGE_TYPE_PSYC_MESSAGE,
1365     sizeof (struct GNUNET_PSYC_MessageHeader), GNUNET_YES },
1366
1367   { place_recv_message_ack, NULL,
1368     GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK,
1369     sizeof (struct GNUNET_MessageHeader), GNUNET_NO },
1370
1371   { place_recv_history_result, NULL,
1372     GNUNET_MESSAGE_TYPE_PSYC_HISTORY_RESULT,
1373     sizeof (struct GNUNET_OperationResultMessage), GNUNET_YES },
1374
1375   { place_recv_state_result, NULL,
1376     GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT,
1377     sizeof (struct GNUNET_OperationResultMessage), GNUNET_YES },
1378
1379   { place_recv_result, NULL,
1380     GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE,
1381     sizeof (struct GNUNET_OperationResultMessage), GNUNET_YES },
1382
1383   { place_recv_disconnect, NULL, 0, 0, GNUNET_NO },
1384
1385   { NULL, NULL, 0, 0, GNUNET_NO }
1386 };
1387
1388
1389 static struct GNUNET_CLIENT_MANAGER_MessageHandler guest_handlers[] =
1390 {
1391   { guest_recv_enter_ack, NULL,
1392     GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ACK,
1393     sizeof (struct GNUNET_PSYC_CountersResultMessage), GNUNET_NO },
1394
1395   { host_recv_enter_request, NULL,
1396     GNUNET_MESSAGE_TYPE_PSYC_JOIN_REQUEST,
1397     sizeof (struct GNUNET_PSYC_JoinRequestMessage), GNUNET_YES },
1398
1399   { place_recv_message, NULL,
1400     GNUNET_MESSAGE_TYPE_PSYC_MESSAGE,
1401     sizeof (struct GNUNET_PSYC_MessageHeader), GNUNET_YES },
1402
1403   { place_recv_message_ack, NULL,
1404     GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK,
1405     sizeof (struct GNUNET_MessageHeader), GNUNET_NO },
1406
1407   { guest_recv_join_decision, NULL,
1408     GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION,
1409     sizeof (struct GNUNET_PSYC_JoinDecisionMessage), GNUNET_YES },
1410
1411   { place_recv_history_result, NULL,
1412     GNUNET_MESSAGE_TYPE_PSYC_HISTORY_RESULT,
1413     sizeof (struct GNUNET_OperationResultMessage), GNUNET_YES },
1414
1415   { place_recv_state_result, NULL,
1416     GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT,
1417     sizeof (struct GNUNET_OperationResultMessage), GNUNET_YES },
1418
1419   { place_recv_result, NULL,
1420     GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE,
1421     sizeof (struct GNUNET_OperationResultMessage), GNUNET_YES },
1422
1423   { place_recv_disconnect, NULL, 0, 0, GNUNET_NO },
1424
1425   { NULL, NULL, 0, 0, GNUNET_NO }
1426 };
1427
1428
1429 static void
1430 place_cleanup (struct GNUNET_SOCIAL_Place *plc)
1431 {
1432   if (NULL != plc->tmit)
1433     GNUNET_PSYC_transmit_destroy (plc->tmit);
1434   if (NULL != plc->recv)
1435     GNUNET_PSYC_receive_destroy (plc->recv);
1436   if (NULL != plc->connect_msg)
1437     GNUNET_free (plc->connect_msg);
1438   if (NULL != plc->disconnect_cb)
1439     plc->disconnect_cb (plc->disconnect_cls);
1440
1441   if (NULL != core)
1442   {
1443     GNUNET_CORE_disconnect (core);
1444     core = NULL;
1445   }
1446   if (NULL != namestore)
1447   {
1448     GNUNET_NAMESTORE_disconnect (namestore);
1449     namestore = NULL;
1450   }
1451   if (NULL != gns)
1452   {
1453     GNUNET_GNS_disconnect (gns);
1454     gns = NULL;
1455   }
1456 }
1457
1458
1459 static void
1460 host_cleanup (void *cls)
1461 {
1462   struct GNUNET_SOCIAL_Host *hst = cls;
1463   place_cleanup (&hst->plc);
1464   GNUNET_PSYC_receive_destroy (hst->recv);
1465   GNUNET_SOCIAL_slicer_destroy (hst->slicer);
1466   GNUNET_free (hst);
1467 }
1468
1469
1470 static void
1471 guest_cleanup (void *cls)
1472 {
1473   struct GNUNET_SOCIAL_Guest *gst = cls;
1474   place_cleanup (&gst->plc);
1475   GNUNET_free (gst);
1476 }
1477
1478
1479 /*** HOST ***/
1480
1481 /**
1482  * Enter a place as host.
1483  *
1484  * A place is created upon first entering, and it is active until permanently
1485  * left using GNUNET_SOCIAL_host_leave().
1486  *
1487  * @param cfg
1488  *        Configuration to contact the social service.
1489  * @param ego
1490  *        Identity of the host.
1491  * @param place_key
1492  *        Private-public key pair of the place.
1493  *        NULL for ephemeral places.
1494  * @param policy
1495  *        Policy specifying entry and history restrictions for the place.
1496  * @param slicer
1497  *        Slicer to handle incoming messages.
1498  * @param answer_door_cb
1499  *        Function to handle new nyms that want to enter.
1500  * @param farewell_cb
1501  *        Function to handle departing nyms.
1502  * @param cls
1503  *        Closure for the callbacks.
1504  *
1505  * @return Handle for the host.
1506  */
1507 struct GNUNET_SOCIAL_Host *
1508 GNUNET_SOCIAL_host_enter (const struct GNUNET_CONFIGURATION_Handle *cfg,
1509                           const struct GNUNET_IDENTITY_Ego *ego,
1510                           const struct GNUNET_CRYPTO_EddsaPrivateKey *place_key,
1511                           enum GNUNET_PSYC_Policy policy,
1512                           struct GNUNET_SOCIAL_Slicer *slicer,
1513                           GNUNET_SOCIAL_HostEnterCallback enter_cb,
1514                           GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb,
1515                           GNUNET_SOCIAL_FarewellCallback farewell_cb,
1516                           void *cls)
1517 {
1518   struct GNUNET_SOCIAL_Host *hst = GNUNET_malloc (sizeof (*hst));
1519   struct GNUNET_SOCIAL_Place *plc = &hst->plc;
1520   struct HostEnterRequest *req = GNUNET_malloc (sizeof (*req));
1521
1522   if (NULL != place_key)
1523   {
1524     hst->place_key = *place_key;
1525   }
1526   else
1527   {
1528     struct GNUNET_CRYPTO_EddsaPrivateKey *
1529       ephemeral_key = GNUNET_CRYPTO_eddsa_key_create ();
1530     hst->place_key = *ephemeral_key;
1531     GNUNET_CRYPTO_eddsa_key_get_public (&hst->place_key, &plc->pub_key);
1532     GNUNET_CRYPTO_eddsa_key_clear (ephemeral_key);
1533     GNUNET_free (ephemeral_key);
1534   }
1535
1536   req->header.size = htons (sizeof (*req));
1537   req->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER);
1538   req->policy = policy;
1539   req->place_key = hst->place_key;
1540   req->host_key = plc->ego_key;
1541
1542   plc->connect_msg = (struct GNUNET_MessageHeader *) req;
1543   plc->cfg = cfg;
1544   plc->is_host = GNUNET_YES;
1545   plc->slicer = slicer;
1546
1547   plc->ego_key = *GNUNET_IDENTITY_ego_get_private_key (ego);
1548   GNUNET_CRYPTO_eddsa_key_get_public (place_key, &plc->pub_key);
1549
1550   hst->enter_cb = enter_cb;
1551   hst->answer_door_cb = answer_door_cb;
1552   hst->farewell_cb = farewell_cb;
1553   hst->cb_cls = cls;
1554
1555   plc->client = GNUNET_CLIENT_MANAGER_connect (cfg, "social", host_handlers);
1556   GNUNET_CLIENT_MANAGER_set_user_context_ (plc->client, hst, sizeof (*plc));
1557
1558   plc->tmit = GNUNET_PSYC_transmit_create (plc->client);
1559   plc->recv = GNUNET_PSYC_receive_create (NULL, slicer_message, plc->slicer);
1560
1561   hst->slicer = GNUNET_SOCIAL_slicer_create ();
1562   GNUNET_SOCIAL_slicer_method_add (hst->slicer, "_notice_place_leave",
1563                                    host_recv_notice_place_leave_method,
1564                                    host_recv_notice_place_leave_modifier,
1565                                    NULL, host_recv_notice_place_leave_eom, hst);
1566   hst->recv = GNUNET_PSYC_receive_create (NULL, slicer_message, hst->slicer);
1567
1568   place_send_connect_msg (plc);
1569   return hst;
1570 }
1571
1572
1573 /**
1574  * Enter a place as host.
1575  *
1576  * A place is created upon first entering, and it is active until permanently
1577  * left using GNUNET_SOCIAL_host_leave().
1578  *
1579  * @param cfg
1580  *        Configuration to contact the social service.
1581  * @param ego
1582  *        Identity of the host.
1583  * @param gns_name
1584  *        GNS name in the zone of the @a ego that contains the
1585  *        public key of the place in a PLACE record.
1586  * @param policy
1587  *        Policy specifying entry and history restrictions for the place.
1588  * @param slicer
1589  *        Slicer to handle incoming messages.
1590  * @param answer_door_cb
1591  *        Function to handle new nyms that want to enter.
1592  * @param farewell_cb
1593  *        Function to handle departing nyms.
1594  * @param cls
1595  *        Closure for the callbacks.
1596  *
1597  * @return Handle for the host.
1598  */
1599 struct GNUNET_SOCIAL_Host *
1600 GNUNET_SOCIAL_host_enter_by_name (const struct GNUNET_CONFIGURATION_Handle *cfg,
1601                                   struct GNUNET_IDENTITY_Ego *ego,
1602                                   const char *gns_name,
1603                                   enum GNUNET_PSYC_Policy policy,
1604                                   struct GNUNET_SOCIAL_Slicer *slicer,
1605                                   GNUNET_SOCIAL_HostEnterCallback enter_cb,
1606                                   GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb,
1607                                   GNUNET_SOCIAL_FarewellCallback farewell_cb,
1608                                   void *cls)
1609 {
1610   struct GNUNET_CRYPTO_EddsaPrivateKey place_key = {};
1611
1612   /* FIXME:
1613    * 1. get public key by looking up PLACE entry under gns_name
1614    *    in the zone of the ego.
1615    * 2. get private key from $GNUNET_DATA_HOME/social/places/PUB_KEY_HASH
1616    */
1617
1618   return GNUNET_SOCIAL_host_enter (cfg, ego, &place_key, policy, slicer,
1619                                    enter_cb, answer_door_cb, farewell_cb, cls);
1620 }
1621
1622
1623 /**
1624  * Decision whether to admit @a nym into the place or refuse entry.
1625  *
1626  * @param hst
1627  *        Host of the place.
1628  * @param nym
1629  *        Handle for the entity that wanted to enter.
1630  * @param is_admitted
1631  *        #GNUNET_YES    if @a nym is admitted,
1632  *        #GNUNET_NO     if @a nym is refused entry,
1633  *        #GNUNET_SYSERR if we cannot answer the request.
1634  * @param method_name
1635  *        Method name for the rejection message.
1636  * @param env
1637  *        Environment containing variables for the message, or NULL.
1638  * @param data
1639  *        Data for the rejection message to send back.
1640  * @param data_size
1641  *        Number of bytes in @a data for method.
1642  * @return #GNUNET_OK on success,
1643  *         #GNUNET_SYSERR if the message is too large.
1644  */
1645 int
1646 GNUNET_SOCIAL_host_entry_decision (struct GNUNET_SOCIAL_Host *hst,
1647                                    struct GNUNET_SOCIAL_Nym *nym,
1648                                    int is_admitted,
1649                                    const struct GNUNET_PSYC_Message *entry_resp)
1650 {
1651   struct GNUNET_PSYC_JoinDecisionMessage *dcsn;
1652   uint16_t entry_resp_size
1653     = (NULL != entry_resp) ? ntohs (entry_resp->header.size) : 0;
1654
1655   if (GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD < sizeof (*dcsn) + entry_resp_size)
1656     return GNUNET_SYSERR;
1657
1658   dcsn = GNUNET_malloc (sizeof (*dcsn) + entry_resp_size);
1659   dcsn->header.size = htons (sizeof (*dcsn) + entry_resp_size);
1660   dcsn->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION);
1661   dcsn->is_admitted = htonl (is_admitted);
1662   dcsn->slave_key = nym->pub_key;
1663
1664   if (0 < entry_resp_size)
1665     memcpy (&dcsn[1], entry_resp, entry_resp_size);
1666
1667   GNUNET_CLIENT_MANAGER_transmit (hst->plc.client, &dcsn->header);
1668   return GNUNET_OK;
1669 }
1670
1671
1672 /**
1673  * Throw @a nym out of the place.
1674  *
1675  * The @a nym reference will remain valid until the
1676  * #GNUNET_SOCIAL_FarewellCallback is invoked,
1677  * which should be very soon after this call.
1678  *
1679  * @param host
1680  *        Host of the place.
1681  * @param nym
1682  *        Handle for the entity to be ejected.
1683  */
1684 void
1685 GNUNET_SOCIAL_host_eject (struct GNUNET_SOCIAL_Host *hst,
1686                           const struct GNUNET_SOCIAL_Nym *nym)
1687 {
1688   struct GNUNET_ENV_Environment *env = GNUNET_ENV_environment_create ();
1689   GNUNET_ENV_environment_add (env, GNUNET_ENV_OP_SET,
1690                               "_nym", &nym->pub_key, sizeof (nym->pub_key));
1691   GNUNET_SOCIAL_host_announce (hst, "_notice_place_leave", env, NULL, NULL,
1692                                GNUNET_SOCIAL_ANNOUNCE_NONE);
1693 }
1694
1695
1696 /**
1697  * Get the public key of a @a nym.
1698  *
1699  * Suitable, for example, to be used with GNUNET_NAMESTORE_zone_to_name().
1700  *
1701  * @param nym
1702  *        Pseudonym to map to a cryptographic identifier.
1703  *
1704  * @return Public key of nym.
1705  */
1706 const struct GNUNET_CRYPTO_EcdsaPublicKey *
1707 GNUNET_SOCIAL_nym_get_key (const struct GNUNET_SOCIAL_Nym *nym)
1708 {
1709   return &nym->pub_key;
1710 }
1711
1712
1713 /**
1714  * Get the hash of the public key of a @a nym.
1715  *
1716  * @param nym
1717  *        Pseudonym to map to a cryptographic identifier.
1718  *
1719  * @return Hash of the public key of nym.
1720  */
1721 const struct GNUNET_HashCode *
1722 GNUNET_SOCIAL_nym_get_key_hash (const struct GNUNET_SOCIAL_Nym *nym)
1723 {
1724   return &nym->pub_key_hash;
1725 }
1726
1727
1728 /**
1729  * Obtain the private-public key pair of the hosted place.
1730  *
1731  * The public part is suitable for storing in GNS within a PLACE record,
1732  * along with peer IDs to join at.
1733  *
1734  * @param host
1735  *        Host of the place.
1736  *
1737  * @return Private-public key pair of the hosted place.
1738  */
1739 const struct GNUNET_CRYPTO_EddsaPrivateKey *
1740 GNUNET_SOCIAL_host_get_place_key (struct GNUNET_SOCIAL_Host *hst)
1741 {
1742   return &hst->place_key;
1743 }
1744
1745
1746 /**
1747  * Connected to core service.
1748  */
1749 static void
1750 core_connected_cb  (void *cls, const struct GNUNET_PeerIdentity *my_identity)
1751 {
1752   this_peer = *my_identity;
1753   // FIXME
1754 }
1755
1756
1757 /**
1758  * Advertise the place in the GNS zone of the @e ego of the @a host.
1759  *
1760  * @param hst
1761  *        Host of the place.
1762  * @param name
1763  *        The name for the PLACE record to put in the zone.
1764  * @param peer_count
1765  *        Number of elements in the @a peers array.
1766  * @param peers
1767  *        List of peers to put in the PLACE record to advertise
1768  *        as entry points to the place in addition to the origin.
1769  * @param expiration_time
1770  *        Expiration time of the record, use 0 to remove the record.
1771  * @param password
1772  *        Password used to encrypt the record or NULL to keep it cleartext.
1773  * @param result_cb
1774  *        Function called with the result of the operation.
1775  * @param result_cls
1776  *        Closure for @a result_cb
1777  */
1778 void
1779 GNUNET_SOCIAL_host_advertise (struct GNUNET_SOCIAL_Host *hst,
1780                               const char *name,
1781                               uint32_t peer_count,
1782                               const struct GNUNET_PeerIdentity *peers,
1783                               struct GNUNET_TIME_Absolute expiration_time,
1784                               const char *password,
1785                               GNUNET_NAMESTORE_ContinuationWithStatus result_cb,
1786                               void *result_cls)
1787 {
1788   struct GNUNET_SOCIAL_Place *plc = &hst->plc;
1789   if (NULL == namestore)
1790     namestore = GNUNET_NAMESTORE_connect (plc->cfg);
1791   if (NULL == core)
1792     core = GNUNET_CORE_connect (plc->cfg, NULL, core_connected_cb, NULL, NULL,
1793                                 NULL, GNUNET_NO, NULL, GNUNET_NO, NULL);
1794
1795   struct GNUNET_GNSRECORD_Data rd = { };
1796   rd.record_type = GNUNET_GNSRECORD_TYPE_PLACE;
1797   rd.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1798   rd.expiration_time = expiration_time.abs_value_us;
1799
1800   struct GNUNET_GNSRECORD_PlaceData *
1801     rec = GNUNET_malloc (sizeof (*rec) + peer_count * sizeof (*peers));
1802   rec->place_key = plc->pub_key;
1803   rec->origin = this_peer;
1804   rec->relay_count = htonl (peer_count);
1805   memcpy (&rec[1], peers, peer_count * sizeof (*peers));
1806
1807   rd.data = rec;
1808   rd.data_size = sizeof (*rec) + peer_count * sizeof (*peers);
1809
1810   GNUNET_NAMESTORE_records_store (namestore, &hst->plc.ego_key,
1811                                   name, 1, &rd, result_cb, result_cls);
1812 }
1813
1814
1815 /**
1816  * Send a message to all nyms that are present in the place.
1817  *
1818  * This function is restricted to the host.  Nyms can only send requests
1819  * to the host who can decide to relay it to everyone in the place.
1820  *
1821  * @param host  Host of the place.
1822  * @param method_name Method to use for the announcement.
1823  * @param env  Environment containing variables for the message and operations
1824  *          on objects of the place.  Can be NULL.
1825  * @param notify Function to call to get the payload of the announcement.
1826  * @param notify_cls Closure for @a notify.
1827  * @param flags Flags for this announcement.
1828  *
1829  * @return NULL on error (announcement already in progress?).
1830  */
1831 struct GNUNET_SOCIAL_Announcement *
1832 GNUNET_SOCIAL_host_announce (struct GNUNET_SOCIAL_Host *hst,
1833                              const char *method_name,
1834                              const struct GNUNET_ENV_Environment *env,
1835                              GNUNET_PSYC_TransmitNotifyData notify_data,
1836                              void *notify_data_cls,
1837                              enum GNUNET_SOCIAL_AnnounceFlags flags)
1838 {
1839   if (GNUNET_OK ==
1840       GNUNET_PSYC_transmit_message (hst->plc.tmit, method_name, env,
1841                                     NULL, notify_data, notify_data_cls, flags))
1842     return (struct GNUNET_SOCIAL_Announcement *) hst->plc.tmit;
1843   else
1844     return NULL;
1845 }
1846
1847
1848 /**
1849  * Resume transmitting announcement.
1850  *
1851  * @param a
1852  *        The announcement to resume.
1853  */
1854 void
1855 GNUNET_SOCIAL_host_announce_resume (struct GNUNET_SOCIAL_Announcement *a)
1856 {
1857   GNUNET_PSYC_transmit_resume ((struct GNUNET_PSYC_TransmitHandle *) a);
1858 }
1859
1860
1861 /**
1862  * Cancel announcement.
1863  *
1864  * @param a
1865  *        The announcement to cancel.
1866  */
1867 void
1868 GNUNET_SOCIAL_host_announce_cancel (struct GNUNET_SOCIAL_Announcement *a)
1869 {
1870   GNUNET_PSYC_transmit_cancel ((struct GNUNET_PSYC_TransmitHandle *) a);
1871 }
1872
1873
1874 /**
1875  * Obtain handle for a hosted place.
1876  *
1877  * The returned handle can be used to access the place API.
1878  *
1879  * @param host  Handle for the host.
1880  *
1881  * @return Handle for the hosted place, valid as long as @a host is valid.
1882  */
1883 struct GNUNET_SOCIAL_Place *
1884 GNUNET_SOCIAL_host_get_place (struct GNUNET_SOCIAL_Host *hst)
1885 {
1886   return &hst->plc;
1887 }
1888
1889
1890 /**
1891  * Stop hosting a place.
1892  *
1893  * Invalidates host handle.
1894  *
1895  * @param host  Host leaving the place.
1896  * @param keep_active  Keep the place active after last host disconnected.
1897  */
1898 void
1899 GNUNET_SOCIAL_host_leave (struct GNUNET_SOCIAL_Host *hst,
1900                           int keep_active,
1901                           GNUNET_ContinuationCallback leave_cb,
1902                           void *leave_cls)
1903 {
1904   struct GNUNET_SOCIAL_Place *plc = &hst->plc;
1905
1906  /* FIXME: send msg to service */
1907
1908   plc->is_disconnecting = GNUNET_YES;
1909   plc->disconnect_cb = leave_cb;
1910   plc->disconnect_cls = leave_cls;
1911
1912   GNUNET_CLIENT_MANAGER_disconnect (plc->client, GNUNET_YES,
1913                                     &host_cleanup, hst);
1914 }
1915
1916
1917 /*** GUEST ***/
1918
1919 static struct GuestEnterRequest *
1920 guest_enter_request_create (const struct GNUNET_CRYPTO_EcdsaPrivateKey *guest_key,
1921                             const struct GNUNET_CRYPTO_EddsaPublicKey *place_key,
1922                             const struct GNUNET_PeerIdentity *origin,
1923                             size_t relay_count,
1924                             const struct GNUNET_PeerIdentity *relays,
1925                             const struct GNUNET_PSYC_Message *join_msg)
1926 {
1927   uint16_t join_msg_size = ntohs (join_msg->header.size);
1928   uint16_t relay_size = relay_count * sizeof (*relays);
1929
1930   struct GuestEnterRequest *
1931     req = GNUNET_malloc (sizeof (*req) + relay_size + join_msg_size);
1932
1933   req->header.size = htons (sizeof (*req) + relay_size + join_msg_size);
1934   req->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER);
1935   req->place_key = *place_key;
1936   req->guest_key = *guest_key;
1937   req->origin = *origin;
1938   req->relay_count = htonl (relay_count);
1939
1940   uint16_t p = sizeof (*req);
1941   if (0 < relay_size)
1942   {
1943     memcpy ((char *) req + p, relays, relay_size);
1944     p += relay_size;
1945   }
1946
1947   memcpy ((char *) req + p, join_msg, join_msg_size);
1948   return req;
1949 }
1950
1951 /**
1952  * Request entry to a place as a guest.
1953  *
1954  * @param cfg Configuration to contact the social service.
1955  * @param ego  Identity of the guest.
1956  * @param crypto_address Public key of the place to enter.
1957  * @param origin Peer identity of the origin of the underlying multicast group.
1958  * @param relay_count Number of elements in the @a relays array.
1959  * @param relays Relays for the underlying multicast group.
1960  * @param method_name Method name for the message.
1961  * @param env Environment containing variables for the message, or NULL.
1962  * @param data Payload for the message to give to the enter callback.
1963  * @param data_size Number of bytes in @a data.
1964  * @param slicer Slicer to use for processing incoming requests from guests.
1965  *
1966  * @return NULL on errors, otherwise handle for the guest.
1967  */
1968 struct GNUNET_SOCIAL_Guest *
1969 GNUNET_SOCIAL_guest_enter (const struct GNUNET_CONFIGURATION_Handle *cfg,
1970                            const struct GNUNET_IDENTITY_Ego *ego,
1971                            const struct GNUNET_CRYPTO_EddsaPublicKey *place_key,
1972                            const struct GNUNET_PeerIdentity *origin,
1973                            uint32_t relay_count,
1974                            const struct GNUNET_PeerIdentity *relays,
1975                            const struct GNUNET_PSYC_Message *entry_msg,
1976                            struct GNUNET_SOCIAL_Slicer *slicer,
1977                            GNUNET_SOCIAL_GuestEnterCallback local_enter_cb,
1978                            GNUNET_SOCIAL_EntryDecisionCallback entry_dcsn_cb,
1979                            void *cls)
1980 {
1981   struct GNUNET_SOCIAL_Guest *gst = GNUNET_malloc (sizeof (*gst));
1982   struct GNUNET_SOCIAL_Place *plc = &gst->plc;
1983
1984   plc->ego_key = *GNUNET_IDENTITY_ego_get_private_key (ego);
1985   plc->pub_key = *place_key;
1986   plc->cfg = cfg;
1987   plc->is_host = GNUNET_YES;
1988   plc->slicer = slicer;
1989
1990   gst->enter_cb = local_enter_cb;
1991   gst->entry_dcsn_cb = entry_dcsn_cb;
1992   gst->cb_cls = cls;
1993
1994   plc->client = GNUNET_CLIENT_MANAGER_connect (cfg, "social", guest_handlers);
1995   GNUNET_CLIENT_MANAGER_set_user_context_ (plc->client, gst, sizeof (*plc));
1996
1997   plc->tmit = GNUNET_PSYC_transmit_create (plc->client);
1998   plc->recv = GNUNET_PSYC_receive_create (NULL, slicer_message, plc->slicer);
1999
2000   struct GuestEnterRequest *
2001     req = guest_enter_request_create (&plc->ego_key, place_key, origin,
2002                                       relay_count, relays, entry_msg);
2003   plc->connect_msg = &req->header;
2004   place_send_connect_msg (plc);
2005   return gst;
2006 }
2007
2008
2009 /**
2010  * Result of a GNS name lookup for entering a place.
2011  *
2012  * @see GNUNET_SOCIAL_guest_enter_by_name
2013  */
2014 static void
2015 gns_result_guest_enter (void *cls, uint32_t rd_count,
2016                         const struct GNUNET_GNSRECORD_Data *rd)
2017 {
2018   struct GNUNET_SOCIAL_Guest *gst = cls;
2019   struct GNUNET_SOCIAL_Place *plc = &gst->plc;
2020
2021   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2022               "%p GNS result: %u records.\n", gst, rd_count);
2023
2024   const struct GNUNET_GNSRECORD_PlaceData *
2025     rec = (const struct GNUNET_GNSRECORD_PlaceData *) rd->data;
2026
2027   if (0 == rd_count)
2028   {
2029     if (NULL != gst->enter_cb)
2030       gst->enter_cb (gst->cb_cls, GNUNET_SYSERR, 0);
2031     return;
2032   }
2033
2034   if (rd->data_size < sizeof (*rec))
2035   {
2036     GNUNET_break_op (0);
2037     if (NULL != gst->enter_cb)
2038       gst->enter_cb (gst->cb_cls, GNUNET_SYSERR, 0);
2039     return;
2040   }
2041
2042   uint16_t relay_count = ntohl (rec->relay_count);
2043   struct GNUNET_PeerIdentity *relays = NULL;
2044
2045   if (0 < relay_count)
2046   {
2047     if (rd->data_size == sizeof (*rec) + relay_count * sizeof (struct GNUNET_PeerIdentity))
2048     {
2049       relays = (struct GNUNET_PeerIdentity *) &rec[1];
2050     }
2051     else
2052     {
2053       relay_count = 0;
2054       GNUNET_break_op (0);
2055     }
2056   }
2057
2058   struct GuestEnterRequest *
2059     req = guest_enter_request_create (&plc->ego_key, &rec->place_key,
2060                                       &rec->origin, relay_count, relays,
2061                                       (struct GNUNET_PSYC_Message *) plc->connect_msg);
2062   GNUNET_free (plc->connect_msg);
2063   plc->connect_msg = &req->header;
2064   plc->pub_key = req->place_key;
2065
2066   plc->tmit = GNUNET_PSYC_transmit_create (plc->client);
2067   plc->recv = GNUNET_PSYC_receive_create (NULL, slicer_message, plc->slicer);
2068
2069   place_send_connect_msg (plc);
2070 }
2071
2072
2073 /**
2074  * Request entry to a place by name as a guest.
2075  *
2076  * @param cfg
2077  *        Configuration to contact the social service.
2078  * @param ego
2079  *        Identity of the guest.
2080  * @param gns_name
2081  *        GNS name of the place to enter.  Either in the form of
2082  *        'room.friend.gnu', or 'NYMPUBKEY.zkey'.  This latter case refers to
2083  *        the 'PLACE' record of the empty label ("+") in the GNS zone with the
2084  *        nym's public key 'NYMPUBKEY', and can be used to request entry to a
2085  *        pseudonym's place directly.
2086  * @param password
2087  *        Password to decrypt the record, or NULL for cleartext records.
2088  * @param join_msg
2089  *        Entry request message.
2090  * @param slicer
2091  *        Slicer to use for processing incoming requests from guests.
2092  * @param local_enter_cb
2093  *        Called upon connection established to the social service.
2094  * @param entry_decision_cb
2095  *        Called upon receiving entry decision.
2096  *
2097  * @return NULL on errors, otherwise handle for the guest.
2098  */
2099 struct GNUNET_SOCIAL_Guest *
2100 GNUNET_SOCIAL_guest_enter_by_name (const struct GNUNET_CONFIGURATION_Handle *cfg,
2101                                    const struct GNUNET_IDENTITY_Ego *ego,
2102                                    const char *gns_name, const char *password,
2103                                    const struct GNUNET_PSYC_Message *join_msg,
2104                                    struct GNUNET_SOCIAL_Slicer *slicer,
2105                                    GNUNET_SOCIAL_GuestEnterCallback local_enter_cb,
2106                                    GNUNET_SOCIAL_EntryDecisionCallback entry_decision_cb,
2107                                    void *cls)
2108 {
2109   struct GNUNET_SOCIAL_Guest *gst = GNUNET_malloc (sizeof (*gst));
2110   struct GNUNET_SOCIAL_Place *plc = &gst->plc;
2111
2112   GNUNET_assert (NULL != join_msg);
2113
2114   gst->enter_cb = local_enter_cb;
2115   gst->entry_dcsn_cb = entry_decision_cb;
2116   gst->cb_cls = cls;
2117
2118   plc->ego_key = *GNUNET_IDENTITY_ego_get_private_key (ego);
2119   plc->cfg = cfg;
2120   plc->is_host = GNUNET_NO;
2121   plc->slicer = slicer;
2122
2123   uint16_t join_msg_size = ntohs (join_msg->header.size);
2124   plc->connect_msg = GNUNET_malloc (join_msg_size);
2125   memcpy (plc->connect_msg, join_msg, join_msg_size);
2126
2127   if (NULL == gns)
2128     gns = GNUNET_GNS_connect (cfg);
2129
2130   plc->client = GNUNET_CLIENT_MANAGER_connect (cfg, "social", guest_handlers);
2131   GNUNET_CLIENT_MANAGER_set_user_context_ (plc->client, gst, sizeof (*plc));
2132
2133   struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
2134   GNUNET_IDENTITY_ego_get_public_key (ego, &ego_pub_key);
2135   GNUNET_GNS_lookup (gns, gns_name, &ego_pub_key,
2136                      GNUNET_GNSRECORD_TYPE_PLACE, GNUNET_GNS_LO_DEFAULT,
2137                      NULL, gns_result_guest_enter, gst);
2138   return gst;
2139 }
2140
2141
2142 /**
2143  * Talk to the host of the place.
2144  *
2145  * @param place
2146  *        Place where we want to talk to the host.
2147  * @param method_name
2148  *        Method to invoke on the host.
2149  * @param env
2150  *        Environment containing variables for the message, or NULL.
2151  * @param notify_data
2152  *        Function to use to get the payload for the method.
2153  * @param notify_data_cls
2154  *        Closure for @a notify_data.
2155  * @param flags
2156  *        Flags for the message being sent.
2157  *
2158  * @return NULL if we are already trying to talk to the host,
2159  *         otherwise handle to cancel the request.
2160  */
2161 struct GNUNET_SOCIAL_TalkRequest *
2162 GNUNET_SOCIAL_guest_talk (struct GNUNET_SOCIAL_Guest *gst,
2163                           const char *method_name,
2164                           const struct GNUNET_ENV_Environment *env,
2165                           GNUNET_PSYC_TransmitNotifyData notify_data,
2166                           void *notify_data_cls,
2167                           enum GNUNET_SOCIAL_TalkFlags flags)
2168 {
2169   struct GNUNET_SOCIAL_Place *plc = &gst->plc;
2170   GNUNET_assert (NULL != plc->tmit);
2171
2172   if (GNUNET_OK ==
2173       GNUNET_PSYC_transmit_message (plc->tmit, method_name, env,
2174                                     NULL, notify_data, notify_data_cls, flags))
2175     return (struct GNUNET_SOCIAL_TalkRequest *) plc->tmit;
2176   else
2177     return NULL;
2178 }
2179
2180
2181 /**
2182  * Resume talking to the host of the place.
2183  *
2184  * @param tr
2185  *        Talk request to resume.
2186  */
2187 void
2188 GNUNET_SOCIAL_guest_talk_resume (struct GNUNET_SOCIAL_TalkRequest *tr)
2189 {
2190   GNUNET_PSYC_transmit_resume ((struct GNUNET_PSYC_TransmitHandle *) tr);
2191 }
2192
2193
2194 /**
2195  * Cancel talking to the host of the place.
2196  *
2197  * @param tr
2198  *        Talk request to cancel.
2199  */
2200 void
2201 GNUNET_SOCIAL_guest_talk_cancel (struct GNUNET_SOCIAL_TalkRequest *tr)
2202 {
2203   GNUNET_PSYC_transmit_cancel ((struct GNUNET_PSYC_TransmitHandle *) tr);
2204 }
2205
2206
2207 /**
2208  * Leave a place temporarily or permanently.
2209  *
2210  * Notifies the owner of the place about leaving, and destroys the place handle.
2211  *
2212  * @param place
2213  *        Place to leave.
2214  * @param keep_active
2215  *        Keep place active after last application disconnected.
2216  *        #GNUNET_YES or #GNUNET_NO
2217  * @param env
2218  *        Optional environment for the leave message if @a keep_active
2219  *        is #GNUNET_NO.  NULL if not needed.
2220  * @param leave_cb
2221  *        Called upon disconnecting from the social service.
2222  */
2223 void
2224 GNUNET_SOCIAL_guest_leave (struct GNUNET_SOCIAL_Guest *gst,
2225                            int keep_active,
2226                            struct GNUNET_ENV_Environment *env,
2227                            GNUNET_ContinuationCallback leave_cb,
2228                            void *leave_cls)
2229 {
2230   struct GNUNET_SOCIAL_Place *plc = &gst->plc;
2231
2232   plc->is_disconnecting = GNUNET_YES;
2233   plc->disconnect_cb = leave_cb;
2234   plc->disconnect_cls = leave_cls;
2235
2236   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2237               "Guest: leaving place.\n");
2238
2239   if (GNUNET_NO == keep_active && NULL != plc->tmit)
2240   {
2241     GNUNET_SOCIAL_guest_talk (gst, "_notice_place_leave", env, NULL, NULL,
2242                               GNUNET_SOCIAL_TALK_NONE);
2243   }
2244
2245   GNUNET_CLIENT_MANAGER_disconnect (plc->client, GNUNET_YES,
2246                                     &guest_cleanup, gst);
2247 }
2248
2249
2250 /**
2251  * Obtain handle for a place entered as guest.
2252  *
2253  * The returned handle can be used to access the place API.
2254  *
2255  * @param guest  Handle for the guest.
2256  *
2257  * @return Handle for the place, valid as long as @a guest is valid.
2258  */
2259 struct GNUNET_SOCIAL_Place *
2260 GNUNET_SOCIAL_guest_get_place (struct GNUNET_SOCIAL_Guest *gst)
2261 {
2262   return &gst->plc;
2263 }
2264
2265
2266 static struct GNUNET_SOCIAL_HistoryRequest *
2267 place_history_replay (struct GNUNET_SOCIAL_Place *plc,
2268                       uint64_t start_message_id,
2269                       uint64_t end_message_id,
2270                       uint64_t message_limit,
2271                       const char *method_prefix,
2272                       uint32_t flags,
2273                       struct GNUNET_SOCIAL_Slicer *slicer,
2274                       GNUNET_ResultCallback result_cb,
2275                       void *cls)
2276 {
2277   struct GNUNET_PSYC_HistoryRequestMessage *req;
2278   struct GNUNET_SOCIAL_HistoryRequest *hist = GNUNET_malloc (sizeof (*hist));
2279   hist->plc = plc;
2280   hist->recv = GNUNET_PSYC_receive_create (NULL, slicer_message, slicer);
2281   hist->result_cb = result_cb;
2282   hist->cls = cls;
2283   hist->op_id = GNUNET_CLIENT_MANAGER_op_add (plc->client,
2284                                               &op_recv_history_result, hist);
2285
2286   GNUNET_assert (NULL != method_prefix);
2287   uint16_t method_size = strnlen (method_prefix,
2288                                   GNUNET_SERVER_MAX_MESSAGE_SIZE
2289                                   - sizeof (*req)) + 1;
2290   GNUNET_assert ('\0' == method_prefix[method_size - 1]);
2291   req = GNUNET_malloc (sizeof (*req) + method_size);
2292   req->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_HISTORY_REPLAY);
2293   req->header.size = htons (sizeof (*req) + method_size);
2294   req->start_message_id = GNUNET_htonll (start_message_id);
2295   req->end_message_id = GNUNET_htonll (end_message_id);
2296   req->message_limit = GNUNET_htonll (message_limit);
2297   req->flags = htonl (flags);
2298   req->op_id = GNUNET_htonll (hist->op_id);
2299   memcpy (&req[1], method_prefix, method_size);
2300
2301   GNUNET_CLIENT_MANAGER_transmit (plc->client, &req->header);
2302   return hist;
2303 }
2304
2305
2306 /**
2307  * Learn about the history of a place.
2308  *
2309  * Messages are returned through the @a slicer function
2310  * and have the #GNUNET_PSYC_MESSAGE_HISTORIC flag set.
2311  *
2312  * @param place
2313  *        Place we want to learn more about.
2314  * @param start_message_id
2315  *        First historic message we are interested in.
2316  * @param end_message_id
2317  *        Last historic message we are interested in (inclusive).
2318  * @param method_prefix
2319  *        Only retrieve messages with this method prefix.
2320  * @param flags
2321  *        OR'ed GNUNET_PSYC_HistoryReplayFlags
2322  * @param slicer
2323  *        Slicer to use for retrieved messages.
2324  *        Can be the same as the slicer of the place.
2325  * @param result_cb
2326  *        Function called after all messages retrieved.
2327  *        NULL if not needed.
2328  * @param cls Closure for @a result_cb.
2329  */
2330 struct GNUNET_SOCIAL_HistoryRequest *
2331 GNUNET_SOCIAL_place_history_replay (struct GNUNET_SOCIAL_Place *plc,
2332                                     uint64_t start_message_id,
2333                                     uint64_t end_message_id,
2334                                     const char *method_prefix,
2335                                     uint32_t flags,
2336                                     struct GNUNET_SOCIAL_Slicer *slicer,
2337                                     GNUNET_ResultCallback result_cb,
2338                                     void *cls)
2339 {
2340   return place_history_replay (plc, start_message_id, end_message_id, 0,
2341                                method_prefix, flags, slicer, result_cb, cls);
2342 }
2343
2344
2345 /**
2346  * Learn about the history of a place.
2347  *
2348  * Sends messages through the slicer function of the place where
2349  * start_message_id <= message_id <= end_message_id.
2350  * The messages will have the #GNUNET_PSYC_MESSAGE_HISTORIC flag set.
2351  *
2352  * To get the latest message, use 0 for both the start and end message ID.
2353  *
2354  * @param place
2355  *        Place we want to learn more about.
2356  * @param message_limit
2357  *        Maximum number of historic messages we are interested in.
2358  * @param method_prefix
2359  *        Only retrieve messages with this method prefix.
2360  * @param flags
2361  *        OR'ed GNUNET_PSYC_HistoryReplayFlags
2362  * @param result_cb
2363  *        Function called after all messages retrieved.
2364  *        NULL if not needed.
2365  * @param cls Closure for @a result_cb.
2366  */
2367 struct GNUNET_SOCIAL_HistoryRequest *
2368 GNUNET_SOCIAL_place_history_replay_latest (struct GNUNET_SOCIAL_Place *plc,
2369                                            uint64_t message_limit,
2370                                            const char *method_prefix,
2371                                            uint32_t flags,
2372                                            struct GNUNET_SOCIAL_Slicer *slicer,
2373                                            GNUNET_ResultCallback result_cb,
2374                                            void *cls)
2375 {
2376   return place_history_replay (plc, 0, 0, message_limit, method_prefix, flags,
2377                                slicer, result_cb, cls);
2378 }
2379
2380
2381 /**
2382  * Cancel learning about the history of a place.
2383  *
2384  * @param hist
2385  *        History lesson to cancel.
2386  */
2387 void
2388 GNUNET_SOCIAL_place_history_replay_cancel (struct GNUNET_SOCIAL_HistoryRequest *hist)
2389 {
2390   GNUNET_PSYC_receive_destroy (hist->recv);
2391   GNUNET_CLIENT_MANAGER_op_cancel (hist->plc->client, hist->op_id);
2392   GNUNET_free (hist);
2393 }
2394
2395
2396 /**
2397  * Request matching state variables.
2398  */
2399 static struct GNUNET_SOCIAL_LookHandle *
2400 place_state_get (struct GNUNET_SOCIAL_Place *plc,
2401                  uint16_t type, const char *name,
2402                  GNUNET_PSYC_StateVarCallback var_cb,
2403                  GNUNET_ResultCallback result_cb, void *cls)
2404 {
2405   struct GNUNET_PSYC_StateRequestMessage *req;
2406   struct GNUNET_SOCIAL_LookHandle *look = GNUNET_malloc (sizeof (*look));
2407   look->plc = plc;
2408   look->var_cb = var_cb;
2409   look->result_cb = result_cb;
2410   look->cls = cls;
2411   look->op_id = GNUNET_CLIENT_MANAGER_op_add (plc->client,
2412                                               &op_recv_state_result, look);
2413
2414   GNUNET_assert (NULL != name);
2415   size_t name_size = strnlen (name, GNUNET_SERVER_MAX_MESSAGE_SIZE
2416                               - sizeof (*req)) + 1;
2417   req = GNUNET_malloc (sizeof (*req) + name_size);
2418   req->header.type = htons (type);
2419   req->header.size = htons (sizeof (*req) + name_size);
2420   req->op_id = GNUNET_htonll (look->op_id);
2421   memcpy (&req[1], name, name_size);
2422
2423   GNUNET_CLIENT_MANAGER_transmit (plc->client, &req->header);
2424   return look;
2425 }
2426
2427
2428 /**
2429  * Look at a particular object in the place.
2430  *
2431  * The best matching object is returned (its name might be less specific than
2432  * what was requested).
2433  *
2434  * @param place
2435  *        The place where to look.
2436  * @param full_name
2437  *        Full name of the object.
2438  * @param value_size
2439  *        Set to the size of the returned value.
2440  *
2441  * @return NULL if there is no such object at this place.
2442  */
2443 struct GNUNET_SOCIAL_LookHandle *
2444 GNUNET_SOCIAL_place_look_at (struct GNUNET_SOCIAL_Place *plc,
2445                              const char *full_name,
2446                              GNUNET_PSYC_StateVarCallback var_cb,
2447                              GNUNET_ResultCallback result_cb,
2448                              void *cls)
2449 {
2450   return place_state_get (plc, GNUNET_MESSAGE_TYPE_PSYC_STATE_GET,
2451                           full_name, var_cb, result_cb, cls);
2452 }
2453
2454
2455 /**
2456  * Look for objects in the place with a matching name prefix.
2457  *
2458  * @param place
2459  *        The place where to look.
2460  * @param name_prefix
2461  *        Look at objects with names beginning with this value.
2462  * @param var_cb
2463  *        Function to call for each object found.
2464  * @param cls
2465  *        Closure for callback function.
2466  *
2467  * @return Handle that can be used to stop looking at objects.
2468  */
2469 struct GNUNET_SOCIAL_LookHandle *
2470 GNUNET_SOCIAL_place_look_for (struct GNUNET_SOCIAL_Place *plc,
2471                               const char *name_prefix,
2472                               GNUNET_PSYC_StateVarCallback var_cb,
2473                               GNUNET_ResultCallback result_cb,
2474                               void *cls)
2475 {
2476   return place_state_get (plc, GNUNET_MESSAGE_TYPE_PSYC_STATE_GET_PREFIX,
2477                           name_prefix, var_cb, result_cb, cls);
2478 }
2479
2480
2481 /**
2482  * Cancel a state request operation.
2483  *
2484  * @param sr
2485  *        Handle for the operation to cancel.
2486  */
2487 void
2488 GNUNET_SOCIAL_place_look_cancel (struct GNUNET_SOCIAL_LookHandle *look)
2489 {
2490   GNUNET_CLIENT_MANAGER_op_cancel (look->plc->client, look->op_id);
2491   GNUNET_free (look);
2492 }
2493
2494
2495 /**
2496  * Add public key to the GNS zone of the @e ego.
2497  *
2498  * @param cfg
2499  *        Configuration.
2500  * @param ego
2501  *        Ego.
2502  * @param name
2503  *        The name for the PKEY record to put in the zone.
2504  * @param pub_key
2505  *        Public key to add.
2506  * @param expiration_time
2507  *        Expiration time of the record, use 0 to remove the record.
2508  * @param result_cb
2509  *        Function called with the result of the operation.
2510  * @param result_cls
2511  *        Closure for @a result_cb
2512  */
2513 void
2514 GNUNET_SOCIAL_zone_add_pkey (const struct GNUNET_CONFIGURATION_Handle *cfg,
2515                              const struct GNUNET_IDENTITY_Ego *ego,
2516                              const char *name,
2517                              const struct GNUNET_CRYPTO_EcdsaPublicKey *pub_key,
2518                              struct GNUNET_TIME_Absolute expiration_time,
2519                              GNUNET_NAMESTORE_ContinuationWithStatus result_cb,
2520                              void *result_cls)
2521 {
2522   if (NULL == namestore)
2523     namestore = GNUNET_NAMESTORE_connect (cfg);
2524
2525   struct GNUNET_GNSRECORD_Data rd = { };
2526   rd.record_type = GNUNET_GNSRECORD_TYPE_PKEY;
2527   rd.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
2528   rd.expiration_time = expiration_time.abs_value_us;
2529   rd.data = pub_key;
2530   rd.data_size = sizeof (*pub_key);
2531
2532   GNUNET_NAMESTORE_records_store (namestore,
2533                                   GNUNET_IDENTITY_ego_get_private_key (ego),
2534                                   name, 1, &rd, result_cb, result_cls);
2535 }
2536
2537
2538 /* end of social_api.c */