social: implement enter/leave/messaging; psyc: improvements and fixes
[oweals/gnunet.git] / src / social / social_api.c
1  /*
2  * This file is part of GNUnet
3  * (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., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /**
22  * @file social/social_api.c
23  * @brief Social service; implements social interactions using the PSYC service.
24  * @author Gabor X Toth
25  */
26
27 #include <inttypes.h>
28 #include <string.h>
29
30 #include "platform.h"
31 #include "gnunet_util_lib.h"
32 #include "gnunet_env_lib.h"
33 #include "gnunet_core_service.h"
34 #include "gnunet_identity_service.h"
35 #include "gnunet_namestore_service.h"
36 #include "gnunet_gns_service.h"
37 #include "gnunet_psyc_service.h"
38 #include "gnunet_psyc_util_lib.h"
39 #include "gnunet_social_service.h"
40 #include "social.h"
41
42 #define LOG(kind,...) GNUNET_log_from (kind, "social-api",__VA_ARGS__)
43
44
45 static struct GNUNET_CORE_Handle *core;
46 static struct GNUNET_GNS_Handle *gns;
47 static struct GNUNET_NAMESTORE_Handle *namestore;
48 static struct GNUNET_PeerIdentity this_peer;
49
50 /**
51  * Handle for a place where social interactions happen.
52  */
53 struct GNUNET_SOCIAL_Place
54 {
55   /**
56    * Configuration to use.
57    */
58   const struct GNUNET_CONFIGURATION_Handle *cfg;
59
60   /**
61    * Client connection to the service.
62    */
63   struct GNUNET_CLIENT_MANAGER_Connection *client;
64
65   /**
66    * Transmission handle;
67    */
68   struct GNUNET_PSYC_TransmitHandle *tmit;
69
70   /**
71    * Receipt handle;
72    */
73   struct GNUNET_PSYC_ReceiveHandle *recv;
74
75   /**
76    * Message to send on reconnect.
77    */
78   struct GNUNET_MessageHeader *connect_msg;
79
80   /**
81    * Slicer for processing incoming methods.
82    */
83   struct GNUNET_SOCIAL_Slicer *slicer;
84
85   /**
86    * Function called after disconnected from the service.
87    */
88   GNUNET_ContinuationCallback disconnect_cb;
89
90   /**
91    * Closure for @a disconnect_cb.
92    */
93   void *disconnect_cls;
94
95   /**
96    * Public key of the place.
97    */
98   struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
99
100   /**
101    * Private key of the ego.
102    */
103   struct GNUNET_CRYPTO_EcdsaPrivateKey ego_key;
104
105   /**
106    * Does this place belong to a host (#GNUNET_YES) or guest (#GNUNET_NO)?
107    */
108   uint8_t is_host;
109
110   /**
111    * Is this place in the process of disconnecting from the service?
112    * #GNUNET_YES or #GNUNET_NO
113    */
114   uint8_t is_disconnecting;
115 };
116
117
118 /**
119  * Host handle for a place that we entered.
120  */
121 struct GNUNET_SOCIAL_Host
122 {
123   struct GNUNET_SOCIAL_Place plc;
124
125   struct GNUNET_CRYPTO_EddsaPrivateKey place_key;
126
127   GNUNET_SOCIAL_HostEnterCallback enter_cb;
128
129   GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb;
130
131   GNUNET_SOCIAL_FarewellCallback farewell_cb;
132
133   /**
134    * Closure for callbacks.
135    */
136   void *cb_cls;
137 };
138
139
140 /**
141  * Guest handle for place that we entered.
142  */
143 struct GNUNET_SOCIAL_Guest
144 {
145   struct GNUNET_SOCIAL_Place plc;
146
147   GNUNET_SOCIAL_GuestEnterCallback enter_cb;
148
149   GNUNET_SOCIAL_EntryDecisionCallback entry_dcsn_cb;
150
151   /**
152    * Closure for callbacks.
153    */
154   void *cb_cls;
155 };
156
157
158 /**
159  * Handle for a pseudonym of another user in the network.
160  */
161 struct GNUNET_SOCIAL_Nym
162 {
163   struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
164   struct GNUNET_HashCode pub_key_hash;
165 };
166
167
168 /**
169  * Hash map of all nyms.
170  * pub_key_hash -> struct GNUNET_SOCIAL_Nym *
171  */
172 struct GNUNET_CONTAINER_MultiHashMap *nyms;
173
174
175 /**
176  * Handle for a try-and-slice instance.
177  */
178 struct GNUNET_SOCIAL_Slicer
179 {
180   /**
181    * Message handlers: method_name -> SlicerCallbacks
182    */
183   struct GNUNET_CONTAINER_MultiHashMap *handlers;
184
185
186   /**
187    * Currently being processed message part.
188    */
189   const struct GNUNET_MessageHeader *msg;
190
191   /**
192    * ID of currently being received message.
193    */
194   uint64_t message_id;
195
196   /**
197    * Method name of currently being received message.
198    */
199   char *method_name;
200
201   /**
202    * Public key of the nym the current message originates from.
203    */
204   struct GNUNET_CRYPTO_EcdsaPublicKey nym_key;
205
206   /**
207    * Size of @a method_name (including terminating \0).
208    */
209   uint16_t method_name_size;
210 };
211
212
213 /**
214  * Callbacks for a slicer method handler.
215  */
216 struct SlicerCallbacks
217 {
218   GNUNET_SOCIAL_MethodCallback method_cb;
219   GNUNET_SOCIAL_ModifierCallback modifier_cb;
220   GNUNET_SOCIAL_DataCallback data_cb;
221   GNUNET_SOCIAL_EndOfMessageCallback eom_cb;
222   void *cls;
223 };
224
225
226 struct SlicerRemoveClosure
227 {
228   struct GNUNET_SOCIAL_Slicer *slicer;
229   struct SlicerCallbacks rm_cbs;
230 };
231
232
233 /**
234  * Handle for an announcement request.
235  */
236 struct GNUNET_SOCIAL_Announcement
237 {
238
239 };
240
241
242 struct GNUNET_SOCIAL_WatchHandle
243 {
244
245 };
246
247
248 struct GNUNET_SOCIAL_LookHandle
249 {
250
251 };
252
253
254 /**
255  * A talk request.
256  */
257 struct GNUNET_SOCIAL_TalkRequest
258 {
259
260 };
261
262
263 /**
264  * A history lesson.
265  */
266 struct GNUNET_SOCIAL_HistoryLesson
267 {
268
269 };
270
271
272 static struct GNUNET_SOCIAL_Nym *
273 nym_get_or_create (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub_key)
274 {
275   struct GNUNET_SOCIAL_Nym *nym = NULL;
276   struct GNUNET_HashCode pub_key_hash;
277
278   if (NULL == pub_key)
279     return NULL;
280
281   GNUNET_CRYPTO_hash (pub_key, sizeof (*pub_key), &pub_key_hash);
282
283   if (NULL == nyms)
284     nyms = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
285   else
286     nym = GNUNET_CONTAINER_multihashmap_get (nyms, &pub_key_hash);
287
288   if (NULL == nym)
289   {
290     nym = GNUNET_new (struct GNUNET_SOCIAL_Nym);
291     nym->pub_key = *pub_key;
292     nym->pub_key_hash = pub_key_hash;
293     GNUNET_CONTAINER_multihashmap_put (nyms, &nym->pub_key_hash, nym,
294                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
295   }
296   return nym;
297 }
298
299
300 static void
301 nym_destroy (struct GNUNET_SOCIAL_Nym *nym)
302 {
303   GNUNET_CONTAINER_multihashmap_remove (nyms, &nym->pub_key_hash, nym);
304   GNUNET_free (nym);
305 }
306
307
308 /**
309  * Call a handler for an incoming message part.
310  *
311  * @param cls
312  * @param key
313  * @param value
314  *
315  * @return
316  */
317 int
318 slicer_handler_notify (void *cls, const struct GNUNET_HashCode *key,
319                        void *value)
320 {
321   struct GNUNET_SOCIAL_Slicer *slicer = cls;
322   const struct GNUNET_MessageHeader *msg = slicer->msg;
323   struct SlicerCallbacks *cbs = value;
324   uint16_t ptype = ntohs (msg->type);
325
326   switch (ptype)
327   {
328   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD:
329   {
330     if (NULL == cbs->method_cb)
331       break;
332     struct GNUNET_PSYC_MessageMethod *
333       meth = (struct GNUNET_PSYC_MessageMethod *) msg;
334     cbs->method_cb (cbs->cls, meth, slicer->message_id,
335                     ntohl (meth->flags),
336                     nym_get_or_create (&slicer->nym_key),
337                     slicer->method_name);
338     break;
339   }
340
341   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
342   {
343     if (NULL == cbs->modifier_cb)
344       break;
345     struct GNUNET_PSYC_MessageModifier *
346       mod = (struct GNUNET_PSYC_MessageModifier *) msg;
347     cbs->modifier_cb (cbs->cls, mod, slicer->message_id,
348                       mod->oper, (const char *) &mod[1],
349                       (const void *) &mod[1] + ntohs (mod->name_size),
350                       ntohs (mod->value_size));
351     break;
352   }
353
354   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
355   {
356     if (NULL == cbs->modifier_cb)
357       break;
358     /* FIXME: concatenate until done */
359     break;
360   }
361
362   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
363   {
364     if (NULL == cbs->data_cb)
365       break;
366     uint64_t data_offset = 0; // FIXME
367     cbs->data_cb (cbs->cls, msg, slicer->message_id,
368                   data_offset, &msg[1], ntohs (msg->size) - sizeof (*msg));
369     break;
370   }
371
372   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
373     if (NULL == cbs->eom_cb)
374       break;
375     cbs->eom_cb (cbs->cls, msg, slicer->message_id, GNUNET_NO);
376     break;
377
378   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
379     if (NULL == cbs->eom_cb)
380       break;
381     cbs->eom_cb (cbs->cls, msg, slicer->message_id, GNUNET_YES);
382     break;
383   }
384   return GNUNET_YES;
385 }
386
387
388 /**
389  * Process an incoming message part and call matching handlers.
390  *
391  * @param cls
392  *        Closure.
393  * @param message_id
394  *        ID of the message.
395  * @param flags
396  *        Flags for the message.
397  *        @see enum GNUNET_PSYC_MessageFlags
398  * @param msg
399  *        The message part. as it arrived from the network.
400  */
401 static void
402 slicer_message (void *cls, uint64_t message_id, uint64_t fragment_offset,
403                 uint32_t flags, const struct GNUNET_MessageHeader *msg)
404 {
405   struct GNUNET_SOCIAL_Slicer *slicer = cls;
406   uint16_t ptype = ntohs (msg->type);
407   if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == ptype)
408   {
409     struct GNUNET_PSYC_MessageMethod *
410       meth = (struct GNUNET_PSYC_MessageMethod *) msg;
411     slicer->method_name_size = ntohs (meth->header.size) - sizeof (*meth);
412     slicer->method_name = GNUNET_malloc (slicer->method_name_size);
413     memcpy (slicer->method_name, &meth[1], slicer->method_name_size);
414     slicer->message_id = message_id;
415   }
416   else
417   {
418     GNUNET_assert (message_id == slicer->message_id);
419   }
420
421   LOG (GNUNET_ERROR_TYPE_WARNING,
422        "Slicer received message of type %u and size %u, "
423        "with ID %" PRIu64 " and method %s\n",
424        ptype, ntohs (msg->size), message_id, slicer->method_name);
425
426   slicer->msg = msg;
427   char *name = GNUNET_malloc (slicer->method_name_size);
428   memcpy (name, slicer->method_name, slicer->method_name_size);
429   do
430   {
431     struct GNUNET_HashCode key;
432     uint16_t name_len = strlen (name);
433     GNUNET_CRYPTO_hash (name, name_len, &key);
434     GNUNET_CONTAINER_multihashmap_get_multiple (slicer->handlers, &key,
435                                                 &slicer_handler_notify, slicer);
436     char *p = strrchr (name, '_');
437     if (NULL == p)
438       break;
439     *p = '\0';
440   } while (1);
441   GNUNET_free (name);
442   slicer->msg = NULL;
443
444   if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype)
445     GNUNET_free (slicer->method_name);
446 }
447
448
449 /**
450  * Create a try-and-slice instance.
451  *
452  * @return A new try-and-slice construct.
453  */
454 struct GNUNET_SOCIAL_Slicer *
455 GNUNET_SOCIAL_slicer_create (void)
456 {
457   struct GNUNET_SOCIAL_Slicer *slicer = GNUNET_malloc (sizeof (*slicer));
458   slicer->handlers = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
459   return slicer;
460 }
461
462
463 /**
464  * Add a method to the try-and-slice instance.
465  *
466  * A slicer processes messages and calls methods that match a message. A match
467  * happens whenever the method name of a message starts with the method_name
468  * parameter given here.
469  *
470  * @param slicer The try-and-slice instance to extend.
471  * @param method_name Name of the given method, use empty string for default.
472  * @param method Method to invoke.
473  * @param method_cls Closure for method.
474  */
475 void
476 GNUNET_SOCIAL_slicer_add (struct GNUNET_SOCIAL_Slicer *slicer,
477                           const char *method_name,
478                           GNUNET_SOCIAL_MethodCallback method_cb,
479                           GNUNET_SOCIAL_ModifierCallback modifier_cb,
480                           GNUNET_SOCIAL_DataCallback data_cb,
481                           GNUNET_SOCIAL_EndOfMessageCallback eom_cb,
482                           void *cls)
483 {
484   struct GNUNET_HashCode key;
485   GNUNET_CRYPTO_hash (method_name, strlen (method_name), &key);
486
487   struct SlicerCallbacks *cbs = GNUNET_malloc (sizeof (*cbs));
488   cbs->method_cb = method_cb;
489   cbs->modifier_cb = modifier_cb;
490   cbs->data_cb = data_cb;
491   cbs->eom_cb = eom_cb;
492   cbs->cls = cls;
493
494   GNUNET_CONTAINER_multihashmap_put (slicer->handlers, &key, cbs,
495                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
496 }
497
498
499 int
500 slicer_remove_handler (void *cls, const struct GNUNET_HashCode *key, void *value)
501 {
502   struct SlicerRemoveClosure *rm_cls = cls;
503   struct GNUNET_SOCIAL_Slicer *slicer = rm_cls->slicer;
504   struct SlicerCallbacks *rm_cbs = &rm_cls->rm_cbs;
505   struct SlicerCallbacks *cbs = value;
506
507   if (cbs->method_cb == rm_cbs->method_cb
508       && cbs->modifier_cb == rm_cbs->modifier_cb
509       && cbs->data_cb == rm_cbs->data_cb
510       && cbs->eom_cb == rm_cbs->eom_cb)
511   {
512     GNUNET_CONTAINER_multihashmap_remove (slicer->handlers, key, cbs);
513     GNUNET_free (cbs);
514     return GNUNET_NO;
515   }
516   return GNUNET_YES;
517 }
518
519
520 /**
521  * Remove a registered method from the try-and-slice instance.
522  *
523  * Removes the first matching handler registered with @a method and the given callbacks.
524  *
525  * @param slicer The try-and-slice instance.
526  * @param method_name Name of the method to remove.
527  * @param method Method handler.
528  *
529  * @return #GNUNET_OK if a method handler was removed,
530  *         #GNUNET_NO if no handler matched the given method name and callbacks.
531  */
532 int
533 GNUNET_SOCIAL_slicer_remove (struct GNUNET_SOCIAL_Slicer *slicer,
534                              const char *method_name,
535                              GNUNET_SOCIAL_MethodCallback method_cb,
536                              GNUNET_SOCIAL_ModifierCallback modifier_cb,
537                              GNUNET_SOCIAL_DataCallback data_cb,
538                              GNUNET_SOCIAL_EndOfMessageCallback eom_cb)
539 {
540   struct GNUNET_HashCode key;
541   GNUNET_CRYPTO_hash (method_name, strlen (method_name), &key);
542
543   struct SlicerRemoveClosure rm_cls;
544   rm_cls.slicer = slicer;
545   struct SlicerCallbacks *rm_cbs = &rm_cls.rm_cbs;
546   rm_cbs->method_cb = method_cb;
547   rm_cbs->modifier_cb = modifier_cb;
548   rm_cbs->data_cb = data_cb;
549   rm_cbs->eom_cb = eom_cb;
550
551   return
552     (GNUNET_SYSERR
553      == GNUNET_CONTAINER_multihashmap_get_multiple (slicer->handlers, &key,
554                                                     &slicer_remove_handler,
555                                                     &rm_cls))
556     ? GNUNET_NO
557     : GNUNET_OK;
558 }
559
560
561 int
562 slicer_free_handler (void *cls, const struct GNUNET_HashCode *key, void *value)
563 {
564   struct SlicerCallbacks *cbs = value;
565   GNUNET_free (cbs);
566   return GNUNET_YES;
567 }
568
569
570 /**
571  * Destroy a given try-and-slice instance.
572  *
573  * @param slicer
574  *        Slicer to destroy
575  */
576 void
577 GNUNET_SOCIAL_slicer_destroy (struct GNUNET_SOCIAL_Slicer *slicer)
578 {
579   GNUNET_CONTAINER_multihashmap_iterate (slicer->handlers, &slicer_free_handler,
580                                          NULL);
581   GNUNET_CONTAINER_multihashmap_destroy (slicer->handlers);
582   GNUNET_free (slicer);
583 }
584
585
586 static void
587 place_send_connect_msg (struct GNUNET_SOCIAL_Place *plc)
588 {
589   uint16_t cmsg_size = ntohs (plc->connect_msg->size);
590   struct GNUNET_MessageHeader * cmsg = GNUNET_malloc (cmsg_size);
591   memcpy (cmsg, plc->connect_msg, cmsg_size);
592   GNUNET_CLIENT_MANAGER_transmit_now (plc->client, cmsg);
593 }
594
595
596 static void
597 place_recv_message_ack (void *cls,
598                         struct GNUNET_CLIENT_MANAGER_Connection *client,
599                         const struct GNUNET_MessageHeader *msg)
600 {
601   struct GNUNET_SOCIAL_Place *
602     plc = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*plc));
603   GNUNET_PSYC_transmit_got_ack (plc->tmit);
604 }
605
606
607 static void
608 place_recv_message (void *cls,
609                     struct GNUNET_CLIENT_MANAGER_Connection *client,
610                     const struct GNUNET_MessageHeader *msg)
611 {
612   struct GNUNET_SOCIAL_Place *
613     plc = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*plc));
614   GNUNET_PSYC_receive_message (plc->recv,
615                                (const struct GNUNET_PSYC_MessageHeader *) msg);
616 }
617
618
619 static void
620 place_recv_disconnect (void *cls,
621                        struct GNUNET_CLIENT_MANAGER_Connection *client,
622                        const struct GNUNET_MessageHeader *msg)
623 {
624   struct GNUNET_SOCIAL_Place *
625     plc = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*plc));
626
627   GNUNET_CLIENT_MANAGER_reconnect (client);
628   place_send_connect_msg (plc);
629 }
630
631
632 static void
633 host_recv_enter_ack (void *cls,
634                      struct GNUNET_CLIENT_MANAGER_Connection *client,
635                      const struct GNUNET_MessageHeader *msg)
636 {
637   struct GNUNET_SOCIAL_Host *
638     hst = GNUNET_CLIENT_MANAGER_get_user_context_ (client,
639                                                    sizeof (struct GNUNET_SOCIAL_Place));
640
641   struct GNUNET_PSYC_CountersResultMessage *
642     cres = (struct GNUNET_PSYC_CountersResultMessage *) msg;
643   if (NULL != hst->enter_cb)
644     hst->enter_cb (hst->cb_cls, GNUNET_ntohll (cres->max_message_id));
645 }
646
647
648 static void
649 host_recv_enter_request (void *cls,
650                          struct GNUNET_CLIENT_MANAGER_Connection *client,
651                          const struct GNUNET_MessageHeader *msg)
652 {
653   struct GNUNET_SOCIAL_Host *
654     hst = GNUNET_CLIENT_MANAGER_get_user_context_ (client,
655                                                    sizeof (struct GNUNET_SOCIAL_Place));
656   if (NULL == hst->answer_door_cb)
657      return;
658
659   const char *method_name = NULL;
660   struct GNUNET_ENV_Environment *env = NULL;
661   const void *data = NULL;
662   uint16_t data_size = 0;
663
664   const struct GNUNET_PSYC_JoinRequestMessage *
665     req = (const struct GNUNET_PSYC_JoinRequestMessage *) msg;
666   const struct GNUNET_PSYC_Message *entry_msg = NULL;
667   if (sizeof (*req) + sizeof (*entry_msg) <= ntohs (req->header.size))
668   {
669     entry_msg = (struct GNUNET_PSYC_Message *) &req[1];
670     LOG (GNUNET_ERROR_TYPE_DEBUG,
671          "Received entry_msg of type %u and size %u.\n",
672          ntohs (entry_msg->header.type), ntohs (entry_msg->header.size));
673
674     env = GNUNET_ENV_environment_create ();
675     if (GNUNET_OK != GNUNET_PSYC_message_parse (entry_msg, &method_name, env,
676                                                 &data, &data_size))
677     {
678       LOG (GNUNET_ERROR_TYPE_WARNING,
679            "Ignoring invalid entry request from nym %s.\n",
680            GNUNET_CRYPTO_ecdsa_public_key_to_string (&req->slave_key));
681       GNUNET_break_op (0);
682       GNUNET_ENV_environment_destroy (env);
683       return;
684     }
685   }
686
687   struct GNUNET_SOCIAL_Nym *nym = nym_get_or_create (&req->slave_key);
688   hst->answer_door_cb (hst->cb_cls, nym, method_name, env,
689                        data_size, data);
690
691   if (NULL != env)
692     GNUNET_ENV_environment_destroy (env);
693 }
694
695
696 static void
697 guest_recv_enter_ack (void *cls,
698                      struct GNUNET_CLIENT_MANAGER_Connection *client,
699                      const struct GNUNET_MessageHeader *msg)
700 {
701   struct GNUNET_SOCIAL_Guest *
702     gst = GNUNET_CLIENT_MANAGER_get_user_context_ (client,
703                                                    sizeof (struct GNUNET_SOCIAL_Place));
704
705   struct GNUNET_PSYC_CountersResultMessage *
706     cres = (struct GNUNET_PSYC_CountersResultMessage *) msg;
707   if (NULL != gst->enter_cb)
708     gst->enter_cb (gst->cb_cls, ntohl (cres->result_code),
709                    GNUNET_ntohll (cres->max_message_id));
710 }
711
712
713 static void
714 guest_recv_join_decision (void *cls,
715                           struct GNUNET_CLIENT_MANAGER_Connection *client,
716                           const struct GNUNET_MessageHeader *msg)
717 {
718   struct GNUNET_SOCIAL_Guest *
719     gst = GNUNET_CLIENT_MANAGER_get_user_context_ (client,
720                                                    sizeof (struct GNUNET_SOCIAL_Place));
721   const struct GNUNET_PSYC_JoinDecisionMessage *
722     dcsn = (const struct GNUNET_PSYC_JoinDecisionMessage *) msg;
723
724   struct GNUNET_PSYC_Message *pmsg = NULL;
725   if (ntohs (dcsn->header.size) <= sizeof (*dcsn) + sizeof (*pmsg))
726     pmsg = (struct GNUNET_PSYC_Message *) &dcsn[1];
727
728   if (NULL != gst->entry_dcsn_cb)
729     gst->entry_dcsn_cb (gst->cb_cls, ntohl (dcsn->is_admitted), pmsg);
730 }
731
732
733 static struct GNUNET_CLIENT_MANAGER_MessageHandler host_handlers[] =
734 {
735   { &host_recv_enter_ack, NULL,
736     GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK,
737     sizeof (struct CountersResult), GNUNET_NO },
738
739   { &host_recv_enter_request, NULL,
740     GNUNET_MESSAGE_TYPE_PSYC_JOIN_REQUEST,
741     sizeof (struct GNUNET_PSYC_JoinRequestMessage), GNUNET_YES },
742
743   { &place_recv_message, NULL,
744     GNUNET_MESSAGE_TYPE_PSYC_MESSAGE,
745     sizeof (struct GNUNET_PSYC_MessageHeader), GNUNET_YES },
746
747   { &place_recv_message_ack, NULL,
748     GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK,
749     sizeof (struct GNUNET_MessageHeader), GNUNET_NO },
750
751   { &place_recv_disconnect, NULL, 0, 0, GNUNET_NO },
752
753   { NULL, NULL, 0, 0, GNUNET_NO }
754 };
755
756
757 static struct GNUNET_CLIENT_MANAGER_MessageHandler guest_handlers[] =
758 {
759   { &guest_recv_enter_ack, NULL,
760     GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ACK,
761     sizeof (struct CountersResult), GNUNET_NO },
762
763   { &host_recv_enter_request, NULL,
764     GNUNET_MESSAGE_TYPE_PSYC_JOIN_REQUEST,
765     sizeof (struct GNUNET_PSYC_JoinRequestMessage), GNUNET_YES },
766
767   { &place_recv_message, NULL,
768     GNUNET_MESSAGE_TYPE_PSYC_MESSAGE,
769     sizeof (struct GNUNET_PSYC_MessageHeader), GNUNET_YES },
770
771   { &place_recv_message_ack, NULL,
772     GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK,
773     sizeof (struct GNUNET_MessageHeader), GNUNET_NO },
774
775   { &guest_recv_join_decision, NULL,
776     GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION,
777     sizeof (struct GNUNET_PSYC_JoinDecisionMessage), GNUNET_YES },
778
779   { &place_recv_disconnect, NULL, 0, 0, GNUNET_NO },
780
781   { NULL, NULL, 0, 0, GNUNET_NO }
782 };
783
784
785 static void
786 place_cleanup (struct GNUNET_SOCIAL_Place *plc)
787 {
788   GNUNET_PSYC_transmit_destroy (plc->tmit);
789   GNUNET_PSYC_receive_destroy (plc->recv);
790   GNUNET_free (plc->connect_msg);
791   if (NULL != plc->disconnect_cb)
792     plc->disconnect_cb (plc->disconnect_cls);
793 }
794
795
796 static void
797 host_cleanup (void *cls)
798 {
799   struct GNUNET_SOCIAL_Host *hst = cls;
800   place_cleanup (&hst->plc);
801   GNUNET_free (hst);
802 }
803
804
805 static void
806 guest_cleanup (void *cls)
807 {
808   struct GNUNET_SOCIAL_Guest *gst = cls;
809   place_cleanup (&gst->plc);
810   GNUNET_free (gst);
811 }
812
813
814 /**
815  * Enter a place as host.
816  *
817  * A place is created upon first entering, and it is active until permanently
818  * left using GNUNET_SOCIAL_host_leave().
819  *
820  * @param cfg
821  *        Configuration to contact the social service.
822  * @param ego
823  *        Identity of the host.
824  * @param place_key
825  *        Private-public key pair of the place.
826  *        NULL for ephemeral places.
827  * @param policy
828  *        Policy specifying entry and history restrictions for the place.
829  * @param slicer
830  *        Slicer to handle incoming messages.
831  * @param answer_door_cb
832  *        Function to handle new nyms that want to enter.
833  * @param farewell_cb
834  *        Function to handle departing nyms.
835  * @param cls
836  *        Closure for the callbacks.
837  *
838  * @return Handle for the host.
839  */
840 struct GNUNET_SOCIAL_Host *
841 GNUNET_SOCIAL_host_enter (const struct GNUNET_CONFIGURATION_Handle *cfg,
842                           const struct GNUNET_IDENTITY_Ego *ego,
843                           const struct GNUNET_CRYPTO_EddsaPrivateKey *place_key,
844                           enum GNUNET_PSYC_Policy policy,
845                           struct GNUNET_SOCIAL_Slicer *slicer,
846                           GNUNET_SOCIAL_HostEnterCallback enter_cb,
847                           GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb,
848                           GNUNET_SOCIAL_FarewellCallback farewell_cb,
849                           void *cls)
850 {
851   struct GNUNET_SOCIAL_Host *hst = GNUNET_malloc (sizeof (*hst));
852   struct GNUNET_SOCIAL_Place *plc = &hst->plc;
853   struct HostEnterRequest *req = GNUNET_malloc (sizeof (*req));
854
855   if (NULL != place_key)
856   {
857     hst->place_key = *place_key;
858   }
859   else
860   {
861     struct GNUNET_CRYPTO_EddsaPrivateKey *
862       ephemeral_key = GNUNET_CRYPTO_eddsa_key_create ();
863     hst->place_key = *ephemeral_key;
864     GNUNET_CRYPTO_eddsa_key_get_public (&hst->place_key, &plc->pub_key);
865     GNUNET_CRYPTO_eddsa_key_clear (ephemeral_key);
866     GNUNET_free (ephemeral_key);
867   }
868   plc->ego_key = *GNUNET_IDENTITY_ego_get_private_key (ego);
869
870   req->header.size = htons (sizeof (*req));
871   req->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER);
872   req->policy = policy;
873   req->place_key = hst->place_key;
874   req->host_key = plc->ego_key;
875
876   plc->connect_msg = (struct GNUNET_MessageHeader *) req;
877   plc->cfg = cfg;
878   plc->is_host = GNUNET_YES;
879   plc->slicer = slicer;
880
881   hst->plc.ego_key = *GNUNET_IDENTITY_ego_get_private_key (ego);
882   hst->enter_cb = enter_cb;
883   hst->answer_door_cb = answer_door_cb;
884   hst->cb_cls = cls;
885
886   plc->client = GNUNET_CLIENT_MANAGER_connect (cfg, "social", host_handlers);
887   GNUNET_CLIENT_MANAGER_set_user_context_ (plc->client, hst, sizeof (*plc));
888
889   plc->tmit = GNUNET_PSYC_transmit_create (plc->client);
890   plc->recv = GNUNET_PSYC_receive_create (NULL, &slicer_message, plc->slicer);
891
892   place_send_connect_msg (plc);
893   return hst;
894 }
895
896
897 /**
898  * Enter a place as host.
899  *
900  * A place is created upon first entering, and it is active until permanently
901  * left using GNUNET_SOCIAL_host_leave().
902  *
903  * @param cfg
904  *        Configuration to contact the social service.
905  * @param ego
906  *        Identity of the host.
907  * @param gns_name
908  *        GNS name in the zone of the @a ego that contains the
909  *        public key of the place in a PLACE record.
910  * @param policy
911  *        Policy specifying entry and history restrictions for the place.
912  * @param slicer
913  *        Slicer to handle incoming messages.
914  * @param answer_door_cb
915  *        Function to handle new nyms that want to enter.
916  * @param farewell_cb
917  *        Function to handle departing nyms.
918  * @param cls
919  *        Closure for the callbacks.
920  *
921  * @return Handle for the host.
922  */
923 struct GNUNET_SOCIAL_Host *
924 GNUNET_SOCIAL_host_enter_by_name (const struct GNUNET_CONFIGURATION_Handle *cfg,
925                                   struct GNUNET_IDENTITY_Ego *ego,
926                                   const char *gns_name,
927                                   enum GNUNET_PSYC_Policy policy,
928                                   struct GNUNET_SOCIAL_Slicer *slicer,
929                                   GNUNET_SOCIAL_HostEnterCallback enter_cb,
930                                   GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb,
931                                   GNUNET_SOCIAL_FarewellCallback farewell_cb,
932                                   void *cls)
933 {
934   struct GNUNET_CRYPTO_EddsaPrivateKey place_key = {};
935
936   /* FIXME:
937    * 1. get public key by looking up PLACE entry under gns_name
938    *    in the zone of the ego.
939    * 2. get private key from $GNUNET_DATA_HOME/social/places/PUB_KEY_HASH
940    */
941
942   return GNUNET_SOCIAL_host_enter (cfg, ego, &place_key, policy, slicer,
943                                    enter_cb, answer_door_cb, farewell_cb, cls);
944 }
945
946
947 /**
948  * Decision whether to admit @a nym into the place or refuse entry.
949  *
950  * @param hst
951  *        Host of the place.
952  * @param nym
953  *        Handle for the entity that wanted to enter.
954  * @param is_admitted
955  *        #GNUNET_YES    if @a nym is admitted,
956  *        #GNUNET_NO     if @a nym is refused entry,
957  *        #GNUNET_SYSERR if we cannot answer the request.
958  * @param method_name
959  *        Method name for the rejection message.
960  * @param env
961  *        Environment containing variables for the message, or NULL.
962  * @param data
963  *        Data for the rejection message to send back.
964  * @param data_size
965  *        Number of bytes in @a data for method.
966  * @return #GNUNET_OK on success,
967  *         #GNUNET_SYSERR if the message is too large.
968  */
969 int
970 GNUNET_SOCIAL_host_entry_decision (struct GNUNET_SOCIAL_Host *hst,
971                                    struct GNUNET_SOCIAL_Nym *nym,
972                                    int is_admitted,
973                                    const struct GNUNET_PSYC_Message *entry_resp)
974 {
975   struct GNUNET_PSYC_JoinDecisionMessage *dcsn;
976   uint16_t entry_resp_size
977     = (NULL != entry_resp) ? ntohs (entry_resp->header.size) : 0;
978
979   if (GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD < sizeof (*dcsn) + entry_resp_size)
980     return GNUNET_SYSERR;
981
982   dcsn = GNUNET_malloc (sizeof (*dcsn) + entry_resp_size);
983   dcsn->header.size = htons (sizeof (*dcsn) + entry_resp_size);
984   dcsn->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION);
985   dcsn->is_admitted = htonl (is_admitted);
986   dcsn->slave_key = nym->pub_key;
987
988   if (0 < entry_resp_size)
989     memcpy (&dcsn[1], entry_resp, entry_resp_size);
990
991   GNUNET_CLIENT_MANAGER_transmit (hst->plc.client, &dcsn->header);
992   return GNUNET_OK;
993 }
994
995
996 /**
997  * Throw @a nym out of the place.
998  *
999  * The @a nym reference will remain valid until the
1000  * #GNUNET_SOCIAL_FarewellCallback is invoked,
1001  * which should be very soon after this call.
1002  *
1003  * @param host  Host of the place.
1004  * @param nym  Handle for the entity to be ejected.
1005  */
1006 void
1007 GNUNET_SOCIAL_host_eject (struct GNUNET_SOCIAL_Host *host,
1008                           struct GNUNET_SOCIAL_Nym *nym)
1009 {
1010
1011 }
1012
1013
1014 /**
1015  * Get the public key of a @a nym.
1016  *
1017  * Suitable, for example, to be used with GNUNET_NAMESTORE_zone_to_name().
1018  *
1019  * @param nym Pseudonym to map to a cryptographic identifier.
1020  * @param[out] nym_key Set to the public key of the nym.
1021  */
1022 struct GNUNET_CRYPTO_EcdsaPublicKey *
1023 GNUNET_SOCIAL_nym_get_key (struct GNUNET_SOCIAL_Nym *nym)
1024 {
1025   return &nym->pub_key;
1026 }
1027
1028
1029 /**
1030  * Obtain the private-public key pair of the hosted place.
1031  *
1032  * The public part is suitable for storing in GNS within a PLACE record,
1033  * along with peer IDs to join at.
1034  *
1035  * @param host
1036  *        Host of the place.
1037  *
1038  * @return Private-public key pair of the hosted place.
1039  */
1040 const struct GNUNET_CRYPTO_EddsaPrivateKey *
1041 GNUNET_SOCIAL_host_get_place_key (struct GNUNET_SOCIAL_Host *hst)
1042 {
1043   return &hst->place_key;
1044 }
1045
1046
1047 static void
1048 namestore_result_host_advertise (void *cls, int32_t success, const char *emsg)
1049 {
1050
1051 }
1052
1053
1054 /**
1055  * Connected to core service.
1056  */
1057 static void
1058 core_connected_cb  (void *cls, const struct GNUNET_PeerIdentity *my_identity)
1059 {
1060   this_peer = *my_identity;
1061   // FIXME
1062 }
1063
1064
1065 /**
1066  * Advertise the place in the GNS zone of the @e ego of the @a host.
1067  *
1068  * @param hst  Host of the place.
1069  * @param name The name for the PLACE record to put in the zone.
1070  * @param peer_count Number of elements in the @a peers array.
1071  * @param peers List of peers in the PLACE record that can be used to send join
1072  *        requests to.
1073  * @param expiration_time Expiration time of the record, use 0 to remove the record.
1074  * @param password Password used to encrypt the record.
1075  */
1076 void
1077 GNUNET_SOCIAL_host_advertise (struct GNUNET_SOCIAL_Host *hst,
1078                               const char *name,
1079                               size_t peer_count,
1080                               const struct GNUNET_PeerIdentity *peers,
1081                               struct GNUNET_TIME_Relative expiration_time,
1082                               const char *password)
1083 {
1084   struct GNUNET_SOCIAL_Place *plc = &hst->plc;
1085   if (NULL == namestore)
1086     namestore = GNUNET_NAMESTORE_connect (plc->cfg);
1087   if (NULL == core)
1088     core = GNUNET_CORE_connect (plc->cfg, NULL, core_connected_cb, NULL, NULL,
1089                                 NULL, GNUNET_NO, NULL, GNUNET_NO, NULL);
1090
1091   struct GNUNET_GNSRECORD_Data rd = { 0 };
1092   rd.record_type = GNUNET_GNSRECORD_TYPE_PLACE;
1093   rd.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1094   rd.expiration_time
1095     = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_WEEKS, 1).rel_value_us;
1096
1097   struct GNUNET_GNSRECORD_PlaceData *rec = GNUNET_malloc (sizeof (*rec));
1098   rec->place_key = plc->pub_key;
1099   rec->origin = this_peer;
1100   rec->relay_count = htons (0); // FIXME
1101
1102   rd.data_size = sizeof (*rec);
1103   rd.data = rec;
1104
1105   GNUNET_NAMESTORE_records_store (namestore, &hst->plc.ego_key,
1106                                   name, 1, &rd, namestore_result_host_advertise,
1107                                   hst);
1108 }
1109
1110
1111 /**
1112  * Send a message to all nyms that are present in the place.
1113  *
1114  * This function is restricted to the host.  Nyms can only send requests
1115  * to the host who can decide to relay it to everyone in the place.
1116  *
1117  * @param host  Host of the place.
1118  * @param method_name Method to use for the announcement.
1119  * @param env  Environment containing variables for the message and operations
1120  *          on objects of the place.  Can be NULL.
1121  * @param notify Function to call to get the payload of the announcement.
1122  * @param notify_cls Closure for @a notify.
1123  * @param flags Flags for this announcement.
1124  *
1125  * @return NULL on error (announcement already in progress?).
1126  */
1127 struct GNUNET_SOCIAL_Announcement *
1128 GNUNET_SOCIAL_host_announce (struct GNUNET_SOCIAL_Host *hst,
1129                              const char *method_name,
1130                              const struct GNUNET_ENV_Environment *env,
1131                              GNUNET_PSYC_TransmitNotifyData notify_data,
1132                              void *notify_data_cls,
1133                              enum GNUNET_SOCIAL_AnnounceFlags flags)
1134 {
1135   if (GNUNET_OK ==
1136       GNUNET_PSYC_transmit_message (hst->plc.tmit, method_name, env,
1137                                     NULL, notify_data, notify_data_cls, flags));
1138   return (struct GNUNET_SOCIAL_Announcement *) hst->plc.tmit;
1139 }
1140
1141
1142 /**
1143  * Resume transmitting announcement.
1144  *
1145  * @param a
1146  *        The announcement to resume.
1147  */
1148 void
1149 GNUNET_SOCIAL_host_announce_resume (struct GNUNET_SOCIAL_Announcement *a)
1150 {
1151   GNUNET_PSYC_transmit_resume ((struct GNUNET_PSYC_TransmitHandle *) a);
1152 }
1153
1154
1155 /**
1156  * Cancel announcement.
1157  *
1158  * @param a
1159  *        The announcement to cancel.
1160  */
1161 void
1162 GNUNET_SOCIAL_host_announce_cancel (struct GNUNET_SOCIAL_Announcement *a)
1163 {
1164   GNUNET_PSYC_transmit_cancel ((struct GNUNET_PSYC_TransmitHandle *) a);
1165 }
1166
1167
1168 /**
1169  * Obtain handle for a hosted place.
1170  *
1171  * The returned handle can be used to access the place API.
1172  *
1173  * @param host  Handle for the host.
1174  *
1175  * @return Handle for the hosted place, valid as long as @a host is valid.
1176  */
1177 struct GNUNET_SOCIAL_Place *
1178 GNUNET_SOCIAL_host_get_place (struct GNUNET_SOCIAL_Host *hst)
1179 {
1180   return &hst->plc;
1181 }
1182
1183
1184 /**
1185  * Stop hosting a place.
1186  *
1187  * Invalidates host handle.
1188  *
1189  * @param host  Host leaving the place.
1190  * @param keep_active  Keep the place active after last host disconnected.
1191  */
1192 void
1193 GNUNET_SOCIAL_host_leave (struct GNUNET_SOCIAL_Host *hst,
1194                           int keep_active,
1195                           GNUNET_ContinuationCallback leave_cb,
1196                           void *leave_cls)
1197 {
1198   struct GNUNET_SOCIAL_Place *plc = &hst->plc;
1199
1200  /* FIXME: send msg to service */
1201
1202   plc->is_disconnecting = GNUNET_YES;
1203   plc->disconnect_cb = leave_cb;
1204   plc->disconnect_cls = leave_cls;
1205
1206   GNUNET_CLIENT_MANAGER_disconnect (plc->client, GNUNET_YES,
1207                                     &host_cleanup, hst);
1208 }
1209
1210
1211 static struct GuestEnterRequest *
1212 guest_enter_request_create (const struct GNUNET_CRYPTO_EcdsaPrivateKey *guest_key,
1213                             const struct GNUNET_CRYPTO_EddsaPublicKey *place_key,
1214                             const struct GNUNET_PeerIdentity *origin,
1215                             size_t relay_count,
1216                             const struct GNUNET_PeerIdentity *relays,
1217                             const struct GNUNET_PSYC_Message *join_msg)
1218 {
1219   uint16_t join_msg_size = ntohs (join_msg->header.size);
1220   uint16_t relay_size = relay_count * sizeof (*relays);
1221
1222   struct GuestEnterRequest *
1223     req = GNUNET_malloc (sizeof (*req) + relay_size + join_msg_size);
1224
1225   req->header.size = htons (sizeof (*req) + relay_size + join_msg_size);
1226   req->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER);
1227   req->place_key = *place_key;
1228   req->guest_key = *guest_key;
1229   req->origin = *origin;
1230   req->relay_count = relay_count;
1231
1232   uint16_t p = sizeof (*req);
1233   if (0 < relay_size)
1234   {
1235     memcpy ((char *) req + p, relays, relay_size);
1236     p += relay_size;
1237   }
1238
1239   memcpy ((char *) req + p, join_msg, join_msg_size);
1240   return req;
1241 }
1242
1243 /**
1244  * Request entry to a place as a guest.
1245  *
1246  * @param cfg Configuration to contact the social service.
1247  * @param ego  Identity of the guest.
1248  * @param crypto_address Public key of the place to enter.
1249  * @param origin Peer identity of the origin of the underlying multicast group.
1250  * @param relay_count Number of elements in the @a relays array.
1251  * @param relays Relays for the underlying multicast group.
1252  * @param method_name Method name for the message.
1253  * @param env Environment containing variables for the message, or NULL.
1254  * @param data Payload for the message to give to the enter callback.
1255  * @param data_size Number of bytes in @a data.
1256  * @param slicer Slicer to use for processing incoming requests from guests.
1257  *
1258  * @return NULL on errors, otherwise handle for the guest.
1259  */
1260 struct GNUNET_SOCIAL_Guest *
1261 GNUNET_SOCIAL_guest_enter (const struct GNUNET_CONFIGURATION_Handle *cfg,
1262                            const struct GNUNET_IDENTITY_Ego *ego,
1263                            const struct GNUNET_CRYPTO_EddsaPublicKey *place_key,
1264                            const struct GNUNET_PeerIdentity *origin,
1265                            uint32_t relay_count,
1266                            const struct GNUNET_PeerIdentity *relays,
1267                            const struct GNUNET_PSYC_Message *entry_msg,
1268                            struct GNUNET_SOCIAL_Slicer *slicer,
1269                            GNUNET_SOCIAL_GuestEnterCallback local_enter_cb,
1270                            GNUNET_SOCIAL_EntryDecisionCallback entry_dcsn_cb,
1271                            void *cls)
1272 {
1273   struct GNUNET_SOCIAL_Guest *gst = GNUNET_malloc (sizeof (*gst));
1274   struct GNUNET_SOCIAL_Place *plc = &gst->plc;
1275
1276   struct GuestEnterRequest *
1277     req = guest_enter_request_create (&plc->ego_key, place_key, origin,
1278                                       relay_count, relays, entry_msg);
1279   plc->connect_msg = &req->header;
1280   plc->ego_key = *GNUNET_IDENTITY_ego_get_private_key (ego);
1281   plc->pub_key = *place_key;
1282   plc->cfg = cfg;
1283   plc->is_host = GNUNET_YES;
1284   plc->slicer = slicer;
1285
1286   gst->enter_cb = local_enter_cb;
1287   gst->entry_dcsn_cb = entry_dcsn_cb;
1288   gst->cb_cls = cls;
1289
1290   plc->client = GNUNET_CLIENT_MANAGER_connect (cfg, "social", guest_handlers);
1291   GNUNET_CLIENT_MANAGER_set_user_context_ (plc->client, gst, sizeof (*plc));
1292
1293   plc->tmit = GNUNET_PSYC_transmit_create (plc->client);
1294   plc->recv = GNUNET_PSYC_receive_create (NULL, &slicer_message, plc->slicer);
1295
1296   place_send_connect_msg (plc);
1297   return gst;
1298 }
1299
1300
1301 /**
1302  * Result of a GNS name lookup for entering a place.
1303  *
1304  * @see GNUNET_SOCIAL_guest_enter_by_name
1305  */
1306 static void
1307 gns_result_guest_enter (void *cls, uint32_t rd_count,
1308                         const struct GNUNET_GNSRECORD_Data *rd)
1309 {
1310   struct GNUNET_SOCIAL_Guest *gst = cls;
1311   struct GNUNET_SOCIAL_Place *plc = &gst->plc;
1312
1313   const struct GNUNET_GNSRECORD_PlaceData *
1314     rec = (const struct GNUNET_GNSRECORD_PlaceData *) rd->data;
1315
1316   if (0 == rd_count)
1317   {
1318     if (NULL != gst->enter_cb)
1319       gst->enter_cb (gst->cb_cls, GNUNET_SYSERR, 0);
1320     return;
1321   }
1322
1323
1324   if (rd->data_size < sizeof (*rec))
1325   {
1326     GNUNET_break_op (0);
1327     if (NULL != gst->enter_cb)
1328       gst->enter_cb (gst->cb_cls, GNUNET_SYSERR, 0);
1329     return;
1330   }
1331
1332   struct GuestEnterRequest *
1333     req = (struct GuestEnterRequest *) plc->connect_msg;
1334   uint16_t req_size = ntohs (req->header.size);
1335
1336   struct GNUNET_PeerIdentity *relays = NULL;
1337   uint16_t relay_count = ntohs (rec->relay_count);
1338
1339   if (0 < relay_count)
1340   {
1341     uint16_t relay_size = relay_count * sizeof (struct GNUNET_PeerIdentity);
1342     struct GuestEnterRequest *
1343       req2 = GNUNET_malloc (req_size + relay_size);
1344
1345     req2->header.size = htons (req_size + relay_size);
1346     req2->header.type = req->header.type;
1347     req2->guest_key = req->guest_key;
1348
1349     uint16_t p = sizeof (*req);
1350     if (0 < relay_size)
1351     {
1352       memcpy ((char *) req2 + p, relays, relay_size);
1353       p += relay_size;
1354     }
1355
1356     memcpy ((char *) req + p, &req[1], req_size - sizeof (*req));
1357
1358     plc->connect_msg = &req2->header;
1359     GNUNET_free (req);
1360     req = req2;
1361   }
1362
1363   req->place_key = rec->place_key;
1364   req->origin = rec->origin;
1365   req->relay_count = rec->relay_count;
1366   memcpy (&req[1], &rec[1],
1367           ntohl (rec->relay_count) * sizeof (struct GNUNET_PeerIdentity));
1368
1369   plc->connect_msg = &req->header;
1370   plc->pub_key = req->place_key;
1371
1372   plc->tmit = GNUNET_PSYC_transmit_create (plc->client);
1373   plc->recv = GNUNET_PSYC_receive_create (NULL, &slicer_message, plc);
1374
1375   place_send_connect_msg (plc);
1376 }
1377
1378 /**
1379  * Request entry to a place as a guest.
1380  *
1381  * @param cfg  Configuration to contact the social service.
1382  * @param ego  Identity of the guest.
1383  * @param address GNS name of the place to enter.  Either in the form of
1384  *        'room.friend.gnu', or 'NYMPUBKEY.zkey'.  This latter case refers to
1385  *        the 'PLACE' record of the empty label ("+") in the GNS zone with the
1386  *        nym's public key 'NYMPUBKEY', and can be used to request entry to a
1387  *        pseudonym's place directly.
1388  * @param method_name Method name for the message.
1389  * @param env Environment containing variables for the message, or NULL.
1390  * @param data Payload for the message to give to the enter callback.
1391  * @param data_size Number of bytes in @a data.
1392  * @param slicer Slicer to use for processing incoming requests from guests.
1393  *
1394  * @return NULL on errors, otherwise handle for the guest.
1395  */
1396 struct GNUNET_SOCIAL_Guest *
1397 GNUNET_SOCIAL_guest_enter_by_name (const struct GNUNET_CONFIGURATION_Handle *cfg,
1398                                    struct GNUNET_IDENTITY_Ego *ego,
1399                                    char *gns_name,
1400                                    const struct GNUNET_PSYC_Message *join_msg,
1401                                    struct GNUNET_SOCIAL_Slicer *slicer,
1402                                    GNUNET_SOCIAL_GuestEnterCallback local_enter_cb,
1403                                    GNUNET_SOCIAL_EntryDecisionCallback entry_decision_cb,
1404                                    void *cls)
1405 {
1406   struct GNUNET_SOCIAL_Guest *gst = GNUNET_malloc (sizeof (*gst));
1407   struct GNUNET_SOCIAL_Place *plc = &gst->plc;
1408
1409   gst->enter_cb = local_enter_cb;
1410   gst->cb_cls = cls;
1411
1412   plc->ego_key = *GNUNET_IDENTITY_ego_get_private_key (ego);
1413   plc->cfg = cfg;
1414   plc->is_host = GNUNET_NO;
1415   plc->slicer = slicer;
1416
1417   struct GuestEnterRequest *
1418     req = guest_enter_request_create (&plc->ego_key, NULL, NULL, 0, NULL,
1419                                       join_msg);
1420   plc->connect_msg = &req->header;
1421
1422   /* FIXME: get the public key of the origin and relays
1423    *        by looking up the PLACE record of gns_name.
1424    */
1425   if (NULL == gns)
1426     gns = GNUNET_GNS_connect (cfg);
1427
1428   plc->client = GNUNET_CLIENT_MANAGER_connect (cfg, "social", guest_handlers);
1429   GNUNET_CLIENT_MANAGER_set_user_context_ (plc->client, gst, sizeof (*plc));
1430
1431   struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
1432   GNUNET_IDENTITY_ego_get_public_key (ego, &ego_pub_key);
1433   GNUNET_GNS_lookup (gns, gns_name, &ego_pub_key,
1434                      GNUNET_GNSRECORD_TYPE_PLACE, GNUNET_GNS_LO_DEFAULT,
1435                      NULL, gns_result_guest_enter, gst);
1436
1437   return gst;
1438 }
1439
1440
1441 /**
1442  * Talk to the host of the place.
1443  *
1444  * @param place
1445  *        Place where we want to talk to the host.
1446  * @param method_name
1447  *        Method to invoke on the host.
1448  * @param env
1449  *        Environment containing variables for the message, or NULL.
1450  * @param notify_data
1451  *        Function to use to get the payload for the method.
1452  * @param notify_data_cls
1453  *        Closure for @a notify_data.
1454  * @param flags
1455  *        Flags for the message being sent.
1456  *
1457  * @return NULL if we are already trying to talk to the host,
1458  *         otherwise handle to cancel the request.
1459  */
1460 struct GNUNET_SOCIAL_TalkRequest *
1461 GNUNET_SOCIAL_guest_talk (struct GNUNET_SOCIAL_Guest *guest,
1462                           const char *method_name,
1463                           const struct GNUNET_ENV_Environment *env,
1464                           GNUNET_PSYC_TransmitNotifyData notify_data,
1465                           void *notify_data_cls,
1466                           enum GNUNET_SOCIAL_TalkFlags flags)
1467 {
1468   return NULL;
1469 }
1470
1471
1472 /**
1473  * Resume talking to the host of the place.
1474  *
1475  * @param tr
1476  *        Talk request to resume.
1477  */
1478 void
1479 GNUNET_SOCIAL_guest_talk_resume (struct GNUNET_SOCIAL_TalkRequest *tr)
1480 {
1481   GNUNET_PSYC_transmit_resume ((struct GNUNET_PSYC_TransmitHandle *) tr);
1482 }
1483
1484
1485 /**
1486  * Cancel talking to the host of the place.
1487  *
1488  * @param tr
1489  *        Talk request to cancel.
1490  */
1491 void
1492 GNUNET_SOCIAL_guest_talk_cancel (struct GNUNET_SOCIAL_TalkRequest *tr)
1493 {
1494   GNUNET_PSYC_transmit_cancel ((struct GNUNET_PSYC_TransmitHandle *) tr);
1495 }
1496
1497
1498 /**
1499  * Leave a place permanently.
1500  *
1501  * Notifies the owner of the place about leaving, and destroys the place handle.
1502  *
1503  * @param place Place to leave permanently.
1504  * @param keep_active Keep place active after last application disconnected.
1505  */
1506 void
1507 GNUNET_SOCIAL_guest_leave (struct GNUNET_SOCIAL_Guest *gst,
1508                            int keep_active,
1509                            GNUNET_ContinuationCallback leave_cb,
1510                            void *leave_cls)
1511 {
1512   struct GNUNET_SOCIAL_Place *plc = &gst->plc;
1513
1514   /* FIXME: send msg to service */
1515
1516   plc->is_disconnecting = GNUNET_YES;
1517   plc->disconnect_cb = leave_cb;
1518   plc->disconnect_cls = leave_cls;
1519
1520   GNUNET_CLIENT_MANAGER_disconnect (plc->client, GNUNET_YES,
1521                                     &guest_cleanup, gst);
1522 }
1523
1524
1525 /**
1526  * Obtain handle for a place entered as guest.
1527  *
1528  * The returned handle can be used to access the place API.
1529  *
1530  * @param guest  Handle for the guest.
1531  *
1532  * @return Handle for the place, valid as long as @a guest is valid.
1533  */
1534 struct GNUNET_SOCIAL_Place *
1535 GNUNET_SOCIAL_guest_get_place (struct GNUNET_SOCIAL_Guest *gst)
1536 {
1537   return &gst->plc;
1538 }
1539
1540
1541 /**
1542  * A history lesson.
1543  */
1544 struct GNUNET_SOCIAL_HistoryLesson;
1545
1546 /**
1547  * Learn about the history of a place.
1548  *
1549  * Sends messages through the slicer function of the place where
1550  * start_message_id <= message_id <= end_message_id.
1551  * The messages will have the #GNUNET_PSYC_MESSAGE_HISTORIC flag set.
1552  *
1553  * To get the latest message, use 0 for both the start and end message ID.
1554  *
1555  * @param place Place we want to learn more about.
1556  * @param start_message_id First historic message we are interested in.
1557  * @param end_message_id Last historic message we are interested in (inclusive).
1558  * @param slicer Slicer to use to process history.  Can be the same as the
1559  *               slicer of the place, as the HISTORIC flag allows distinguishing
1560  *               old messages from fresh ones.
1561  * @param finish_cb Function called after the last message in the history lesson
1562  *              is passed through the @a slicer. NULL if not needed.
1563  * @param finish_cb_cls Closure for @a finish_cb.
1564  * @return Handle to abort history lesson, never NULL (multiple lessons
1565  *         at the same time are allowed).
1566  */
1567 struct GNUNET_SOCIAL_HistoryLesson *
1568 GNUNET_SOCIAL_place_get_history (struct GNUNET_SOCIAL_Place *place,
1569                                  uint64_t start_message_id,
1570                                  uint64_t end_message_id,
1571                                  const struct GNUNET_SOCIAL_Slicer *slicer,
1572                                  void (*finish_cb)(void *),
1573                                  void *finish_cb_cls)
1574 {
1575   return NULL;
1576 }
1577
1578
1579 /**
1580  * Stop processing messages from the history lesson.
1581  *
1582  * Must not be called after the finish callback of the history lesson is called.
1583  *
1584  * @param hist History lesson to cancel.
1585  */
1586 void
1587 GNUNET_SOCIAL_place_get_history_cancel (struct GNUNET_SOCIAL_HistoryLesson *hist)
1588 {
1589
1590 }
1591
1592
1593 struct GNUNET_SOCIAL_WatchHandle;
1594
1595 /**
1596  * Watch a place for changed objects.
1597  *
1598  * @param place Place to watch.
1599  * @param object_filter Object prefix to match.
1600  * @param state_cb Function to call when an object/state changes.
1601  * @param state_cb_cls Closure for callback.
1602  *
1603  * @return Handle that can be used to cancel watching.
1604  */
1605 struct GNUNET_SOCIAL_WatchHandle *
1606 GNUNET_SOCIAL_place_watch (struct GNUNET_SOCIAL_Place *place,
1607                            const char *object_filter,
1608                            GNUNET_PSYC_StateCallback state_cb,
1609                            void *state_cb_cls)
1610 {
1611   return NULL;
1612 }
1613
1614
1615 /**
1616  * Cancel watching a place for changed objects.
1617  *
1618  * @param wh Watch handle to cancel.
1619  */
1620 void
1621 GNUNET_SOCIAL_place_watch_cancel (struct GNUNET_SOCIAL_WatchHandle *wh)
1622 {
1623
1624 }
1625
1626
1627 struct GNUNET_SOCIAL_LookHandle;
1628
1629
1630 /**
1631  * Look at objects in the place with a matching name prefix.
1632  *
1633  * @param place The place to look its objects at.
1634  * @param name_prefix Look at objects with names beginning with this value.
1635  * @param state_cb Function to call for each object found.
1636  * @param state_cb_cls Closure for callback function.
1637  *
1638  * @return Handle that can be used to stop looking at objects.
1639  */
1640 struct GNUNET_SOCIAL_LookHandle *
1641 GNUNET_SOCIAL_place_look (struct GNUNET_SOCIAL_Place *place,
1642                           const char *name_prefix,
1643                           GNUNET_PSYC_StateCallback state_cb,
1644                           void *state_cb_cls)
1645 {
1646   return NULL;
1647 }
1648
1649
1650 /**
1651  * Stop looking at objects.
1652  *
1653  * @param lh Look handle to stop.
1654  */
1655 void
1656 GNUNET_SOCIAL_place_look_cancel (struct GNUNET_SOCIAL_LookHandle *lh)
1657 {
1658
1659 }
1660
1661
1662
1663 /**
1664  * Look at a particular object in the place.
1665  *
1666  * The best matching object is returned (its name might be less specific than
1667  * what was requested).
1668  *
1669  * @param place The place to look the object at.
1670  * @param full_name Full name of the object.
1671  * @param value_size Set to the size of the returned value.
1672  * @return NULL if there is no such object at this place.
1673  */
1674 const void *
1675 GNUNET_SOCIAL_place_look_at (struct GNUNET_SOCIAL_Place *place,
1676                              const char *full_name,
1677                              size_t *value_size)
1678 {
1679   return NULL;
1680 }
1681
1682
1683 /* end of social_api.c */