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