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