- const
[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., 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   int32_t result = ntohl (cres->result_code) + INT32_MIN;
644   if (NULL != hst->enter_cb)
645     hst->enter_cb (hst->cb_cls, result, GNUNET_ntohll (cres->max_message_id));
646 }
647
648
649 static void
650 host_recv_enter_request (void *cls,
651                          struct GNUNET_CLIENT_MANAGER_Connection *client,
652                          const struct GNUNET_MessageHeader *msg)
653 {
654   struct GNUNET_SOCIAL_Host *
655     hst = GNUNET_CLIENT_MANAGER_get_user_context_ (client,
656                                                    sizeof (struct GNUNET_SOCIAL_Place));
657   if (NULL == hst->answer_door_cb)
658      return;
659
660   const char *method_name = NULL;
661   struct GNUNET_ENV_Environment *env = NULL;
662   const void *data = NULL;
663   uint16_t data_size = 0;
664   char *str;
665   const struct GNUNET_PSYC_JoinRequestMessage *
666     req = (const struct GNUNET_PSYC_JoinRequestMessage *) msg;
667   const struct GNUNET_PSYC_Message *entry_msg = NULL;
668
669   if (sizeof (*req) + sizeof (*entry_msg) <= ntohs (req->header.size))
670   {
671     entry_msg = (struct GNUNET_PSYC_Message *) &req[1];
672     LOG (GNUNET_ERROR_TYPE_DEBUG,
673          "Received entry_msg of type %u and size %u.\n",
674          ntohs (entry_msg->header.type), ntohs (entry_msg->header.size));
675
676     env = GNUNET_ENV_environment_create ();
677     if (GNUNET_OK != GNUNET_PSYC_message_parse (entry_msg, &method_name, env,
678                                                 &data, &data_size))
679     {
680       GNUNET_break_op (0);
681       str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&req->slave_key);
682       LOG (GNUNET_ERROR_TYPE_WARNING,
683            "Ignoring invalid entry request from nym %s.\n",
684            str);
685       GNUNET_free (str);
686       GNUNET_ENV_environment_destroy (env);
687       return;
688     }
689   }
690
691   struct GNUNET_SOCIAL_Nym *nym = nym_get_or_create (&req->slave_key);
692   hst->answer_door_cb (hst->cb_cls, nym, method_name, env,
693                        data_size, data);
694
695   if (NULL != env)
696     GNUNET_ENV_environment_destroy (env);
697 }
698
699
700 static void
701 guest_recv_enter_ack (void *cls,
702                      struct GNUNET_CLIENT_MANAGER_Connection *client,
703                      const struct GNUNET_MessageHeader *msg)
704 {
705   struct GNUNET_SOCIAL_Guest *
706     gst = GNUNET_CLIENT_MANAGER_get_user_context_ (client,
707                                                    sizeof (struct GNUNET_SOCIAL_Place));
708
709   struct GNUNET_PSYC_CountersResultMessage *
710     cres = (struct GNUNET_PSYC_CountersResultMessage *) msg;
711   int32_t result = ntohl (cres->result_code) + INT32_MIN;
712   if (NULL != gst->enter_cb)
713     gst->enter_cb (gst->cb_cls, result, GNUNET_ntohll (cres->max_message_id));
714 }
715
716
717 static void
718 guest_recv_join_decision (void *cls,
719                           struct GNUNET_CLIENT_MANAGER_Connection *client,
720                           const struct GNUNET_MessageHeader *msg)
721 {
722   struct GNUNET_SOCIAL_Guest *
723     gst = GNUNET_CLIENT_MANAGER_get_user_context_ (client,
724                                                    sizeof (struct GNUNET_SOCIAL_Place));
725   const struct GNUNET_PSYC_JoinDecisionMessage *
726     dcsn = (const struct GNUNET_PSYC_JoinDecisionMessage *) msg;
727
728   struct GNUNET_PSYC_Message *pmsg = NULL;
729   if (ntohs (dcsn->header.size) <= sizeof (*dcsn) + sizeof (*pmsg))
730     pmsg = (struct GNUNET_PSYC_Message *) &dcsn[1];
731
732   if (NULL != gst->entry_dcsn_cb)
733     gst->entry_dcsn_cb (gst->cb_cls, ntohl (dcsn->is_admitted), pmsg);
734 }
735
736
737 static struct GNUNET_CLIENT_MANAGER_MessageHandler host_handlers[] =
738 {
739   { &host_recv_enter_ack, NULL,
740     GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK,
741     sizeof (struct GNUNET_PSYC_CountersResultMessage), GNUNET_NO },
742
743   { &host_recv_enter_request, NULL,
744     GNUNET_MESSAGE_TYPE_PSYC_JOIN_REQUEST,
745     sizeof (struct GNUNET_PSYC_JoinRequestMessage), GNUNET_YES },
746
747   { &place_recv_message, NULL,
748     GNUNET_MESSAGE_TYPE_PSYC_MESSAGE,
749     sizeof (struct GNUNET_PSYC_MessageHeader), GNUNET_YES },
750
751   { &place_recv_message_ack, NULL,
752     GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK,
753     sizeof (struct GNUNET_MessageHeader), GNUNET_NO },
754
755   { &place_recv_disconnect, NULL, 0, 0, GNUNET_NO },
756
757   { NULL, NULL, 0, 0, GNUNET_NO }
758 };
759
760
761 static struct GNUNET_CLIENT_MANAGER_MessageHandler guest_handlers[] =
762 {
763   { &guest_recv_enter_ack, NULL,
764     GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ACK,
765     sizeof (struct GNUNET_PSYC_CountersResultMessage), GNUNET_NO },
766
767   { &host_recv_enter_request, NULL,
768     GNUNET_MESSAGE_TYPE_PSYC_JOIN_REQUEST,
769     sizeof (struct GNUNET_PSYC_JoinRequestMessage), GNUNET_YES },
770
771   { &place_recv_message, NULL,
772     GNUNET_MESSAGE_TYPE_PSYC_MESSAGE,
773     sizeof (struct GNUNET_PSYC_MessageHeader), GNUNET_YES },
774
775   { &place_recv_message_ack, NULL,
776     GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK,
777     sizeof (struct GNUNET_MessageHeader), GNUNET_NO },
778
779   { &guest_recv_join_decision, NULL,
780     GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION,
781     sizeof (struct GNUNET_PSYC_JoinDecisionMessage), GNUNET_YES },
782
783   { &place_recv_disconnect, NULL, 0, 0, GNUNET_NO },
784
785   { NULL, NULL, 0, 0, GNUNET_NO }
786 };
787
788
789 static void
790 place_cleanup (struct GNUNET_SOCIAL_Place *plc)
791 {
792   GNUNET_PSYC_transmit_destroy (plc->tmit);
793   GNUNET_PSYC_receive_destroy (plc->recv);
794   GNUNET_free (plc->connect_msg);
795   if (NULL != plc->disconnect_cb)
796     plc->disconnect_cb (plc->disconnect_cls);
797 }
798
799
800 static void
801 host_cleanup (void *cls)
802 {
803   struct GNUNET_SOCIAL_Host *hst = cls;
804   place_cleanup (&hst->plc);
805   GNUNET_free (hst);
806 }
807
808
809 static void
810 guest_cleanup (void *cls)
811 {
812   struct GNUNET_SOCIAL_Guest *gst = cls;
813   place_cleanup (&gst->plc);
814   GNUNET_free (gst);
815 }
816
817
818 /**
819  * Enter a place as host.
820  *
821  * A place is created upon first entering, and it is active until permanently
822  * left using GNUNET_SOCIAL_host_leave().
823  *
824  * @param cfg
825  *        Configuration to contact the social service.
826  * @param ego
827  *        Identity of the host.
828  * @param place_key
829  *        Private-public key pair of the place.
830  *        NULL for ephemeral places.
831  * @param policy
832  *        Policy specifying entry and history restrictions for the place.
833  * @param slicer
834  *        Slicer to handle incoming messages.
835  * @param answer_door_cb
836  *        Function to handle new nyms that want to enter.
837  * @param farewell_cb
838  *        Function to handle departing nyms.
839  * @param cls
840  *        Closure for the callbacks.
841  *
842  * @return Handle for the host.
843  */
844 struct GNUNET_SOCIAL_Host *
845 GNUNET_SOCIAL_host_enter (const struct GNUNET_CONFIGURATION_Handle *cfg,
846                           const struct GNUNET_IDENTITY_Ego *ego,
847                           const struct GNUNET_CRYPTO_EddsaPrivateKey *place_key,
848                           enum GNUNET_PSYC_Policy policy,
849                           struct GNUNET_SOCIAL_Slicer *slicer,
850                           GNUNET_SOCIAL_HostEnterCallback enter_cb,
851                           GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb,
852                           GNUNET_SOCIAL_FarewellCallback farewell_cb,
853                           void *cls)
854 {
855   struct GNUNET_SOCIAL_Host *hst = GNUNET_malloc (sizeof (*hst));
856   struct GNUNET_SOCIAL_Place *plc = &hst->plc;
857   struct HostEnterRequest *req = GNUNET_malloc (sizeof (*req));
858
859   if (NULL != place_key)
860   {
861     hst->place_key = *place_key;
862   }
863   else
864   {
865     struct GNUNET_CRYPTO_EddsaPrivateKey *
866       ephemeral_key = GNUNET_CRYPTO_eddsa_key_create ();
867     hst->place_key = *ephemeral_key;
868     GNUNET_CRYPTO_eddsa_key_get_public (&hst->place_key, &plc->pub_key);
869     GNUNET_CRYPTO_eddsa_key_clear (ephemeral_key);
870     GNUNET_free (ephemeral_key);
871   }
872   plc->ego_key = *GNUNET_IDENTITY_ego_get_private_key (ego);
873
874   req->header.size = htons (sizeof (*req));
875   req->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER);
876   req->policy = policy;
877   req->place_key = hst->place_key;
878   req->host_key = plc->ego_key;
879
880   plc->connect_msg = (struct GNUNET_MessageHeader *) req;
881   plc->cfg = cfg;
882   plc->is_host = GNUNET_YES;
883   plc->slicer = slicer;
884
885   hst->plc.ego_key = *GNUNET_IDENTITY_ego_get_private_key (ego);
886   hst->enter_cb = enter_cb;
887   hst->answer_door_cb = answer_door_cb;
888   hst->cb_cls = cls;
889
890   plc->client = GNUNET_CLIENT_MANAGER_connect (cfg, "social", host_handlers);
891   GNUNET_CLIENT_MANAGER_set_user_context_ (plc->client, hst, sizeof (*plc));
892
893   plc->tmit = GNUNET_PSYC_transmit_create (plc->client);
894   plc->recv = GNUNET_PSYC_receive_create (NULL, &slicer_message, plc->slicer);
895
896   place_send_connect_msg (plc);
897   return hst;
898 }
899
900
901 /**
902  * Enter a place as host.
903  *
904  * A place is created upon first entering, and it is active until permanently
905  * left using GNUNET_SOCIAL_host_leave().
906  *
907  * @param cfg
908  *        Configuration to contact the social service.
909  * @param ego
910  *        Identity of the host.
911  * @param gns_name
912  *        GNS name in the zone of the @a ego that contains the
913  *        public key of the place in a PLACE record.
914  * @param policy
915  *        Policy specifying entry and history restrictions for the place.
916  * @param slicer
917  *        Slicer to handle incoming messages.
918  * @param answer_door_cb
919  *        Function to handle new nyms that want to enter.
920  * @param farewell_cb
921  *        Function to handle departing nyms.
922  * @param cls
923  *        Closure for the callbacks.
924  *
925  * @return Handle for the host.
926  */
927 struct GNUNET_SOCIAL_Host *
928 GNUNET_SOCIAL_host_enter_by_name (const struct GNUNET_CONFIGURATION_Handle *cfg,
929                                   struct GNUNET_IDENTITY_Ego *ego,
930                                   const char *gns_name,
931                                   enum GNUNET_PSYC_Policy policy,
932                                   struct GNUNET_SOCIAL_Slicer *slicer,
933                                   GNUNET_SOCIAL_HostEnterCallback enter_cb,
934                                   GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb,
935                                   GNUNET_SOCIAL_FarewellCallback farewell_cb,
936                                   void *cls)
937 {
938   struct GNUNET_CRYPTO_EddsaPrivateKey place_key = {};
939
940   /* FIXME:
941    * 1. get public key by looking up PLACE entry under gns_name
942    *    in the zone of the ego.
943    * 2. get private key from $GNUNET_DATA_HOME/social/places/PUB_KEY_HASH
944    */
945
946   return GNUNET_SOCIAL_host_enter (cfg, ego, &place_key, policy, slicer,
947                                    enter_cb, answer_door_cb, farewell_cb, cls);
948 }
949
950
951 /**
952  * Decision whether to admit @a nym into the place or refuse entry.
953  *
954  * @param hst
955  *        Host of the place.
956  * @param nym
957  *        Handle for the entity that wanted to enter.
958  * @param is_admitted
959  *        #GNUNET_YES    if @a nym is admitted,
960  *        #GNUNET_NO     if @a nym is refused entry,
961  *        #GNUNET_SYSERR if we cannot answer the request.
962  * @param method_name
963  *        Method name for the rejection message.
964  * @param env
965  *        Environment containing variables for the message, or NULL.
966  * @param data
967  *        Data for the rejection message to send back.
968  * @param data_size
969  *        Number of bytes in @a data for method.
970  * @return #GNUNET_OK on success,
971  *         #GNUNET_SYSERR if the message is too large.
972  */
973 int
974 GNUNET_SOCIAL_host_entry_decision (struct GNUNET_SOCIAL_Host *hst,
975                                    struct GNUNET_SOCIAL_Nym *nym,
976                                    int is_admitted,
977                                    const struct GNUNET_PSYC_Message *entry_resp)
978 {
979   struct GNUNET_PSYC_JoinDecisionMessage *dcsn;
980   uint16_t entry_resp_size
981     = (NULL != entry_resp) ? ntohs (entry_resp->header.size) : 0;
982
983   if (GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD < sizeof (*dcsn) + entry_resp_size)
984     return GNUNET_SYSERR;
985
986   dcsn = GNUNET_malloc (sizeof (*dcsn) + entry_resp_size);
987   dcsn->header.size = htons (sizeof (*dcsn) + entry_resp_size);
988   dcsn->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION);
989   dcsn->is_admitted = htonl (is_admitted);
990   dcsn->slave_key = nym->pub_key;
991
992   if (0 < entry_resp_size)
993     memcpy (&dcsn[1], entry_resp, entry_resp_size);
994
995   GNUNET_CLIENT_MANAGER_transmit (hst->plc.client, &dcsn->header);
996   return GNUNET_OK;
997 }
998
999
1000 /**
1001  * Throw @a nym out of the place.
1002  *
1003  * The @a nym reference will remain valid until the
1004  * #GNUNET_SOCIAL_FarewellCallback is invoked,
1005  * which should be very soon after this call.
1006  *
1007  * @param host  Host of the place.
1008  * @param nym  Handle for the entity to be ejected.
1009  */
1010 void
1011 GNUNET_SOCIAL_host_eject (struct GNUNET_SOCIAL_Host *host,
1012                           struct GNUNET_SOCIAL_Nym *nym)
1013 {
1014
1015 }
1016
1017
1018 /**
1019  * Get the public key of a @a nym.
1020  *
1021  * Suitable, for example, to be used with GNUNET_NAMESTORE_zone_to_name().
1022  *
1023  * @param nym Pseudonym to map to a cryptographic identifier.
1024  * @param[out] nym_key Set to the public key of the nym.
1025  */
1026 struct GNUNET_CRYPTO_EcdsaPublicKey *
1027 GNUNET_SOCIAL_nym_get_key (struct GNUNET_SOCIAL_Nym *nym)
1028 {
1029   return &nym->pub_key;
1030 }
1031
1032
1033 /**
1034  * Obtain the private-public key pair of the hosted place.
1035  *
1036  * The public part is suitable for storing in GNS within a PLACE record,
1037  * along with peer IDs to join at.
1038  *
1039  * @param host
1040  *        Host of the place.
1041  *
1042  * @return Private-public key pair of the hosted place.
1043  */
1044 const struct GNUNET_CRYPTO_EddsaPrivateKey *
1045 GNUNET_SOCIAL_host_get_place_key (struct GNUNET_SOCIAL_Host *hst)
1046 {
1047   return &hst->place_key;
1048 }
1049
1050
1051 static void
1052 namestore_result_host_advertise (void *cls, int32_t success, const char *emsg)
1053 {
1054
1055 }
1056
1057
1058 /**
1059  * Connected to core service.
1060  */
1061 static void
1062 core_connected_cb  (void *cls, const struct GNUNET_PeerIdentity *my_identity)
1063 {
1064   this_peer = *my_identity;
1065   // FIXME
1066 }
1067
1068
1069 /**
1070  * Advertise the place in the GNS zone of the @e ego of the @a host.
1071  *
1072  * @param hst  Host of the place.
1073  * @param name The name for the PLACE record to put in the zone.
1074  * @param peer_count Number of elements in the @a peers array.
1075  * @param peers List of peers in the PLACE record that can be used to send join
1076  *        requests to.
1077  * @param expiration_time Expiration time of the record, use 0 to remove the record.
1078  * @param password Password used to encrypt the record.
1079  */
1080 void
1081 GNUNET_SOCIAL_host_advertise (struct GNUNET_SOCIAL_Host *hst,
1082                               const char *name,
1083                               size_t peer_count,
1084                               const struct GNUNET_PeerIdentity *peers,
1085                               struct GNUNET_TIME_Relative expiration_time,
1086                               const char *password)
1087 {
1088   struct GNUNET_SOCIAL_Place *plc = &hst->plc;
1089   if (NULL == namestore)
1090     namestore = GNUNET_NAMESTORE_connect (plc->cfg);
1091   if (NULL == core)
1092     core = GNUNET_CORE_connect (plc->cfg, NULL, core_connected_cb, NULL, NULL,
1093                                 NULL, GNUNET_NO, NULL, GNUNET_NO, NULL);
1094
1095   struct GNUNET_GNSRECORD_Data rd = { 0 };
1096   rd.record_type = GNUNET_GNSRECORD_TYPE_PLACE;
1097   rd.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1098   rd.expiration_time
1099     = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_WEEKS, 1).rel_value_us;
1100
1101   struct GNUNET_GNSRECORD_PlaceData *rec = GNUNET_malloc (sizeof (*rec));
1102   rec->place_key = plc->pub_key;
1103   rec->origin = this_peer;
1104   rec->relay_count = htons (0); // FIXME
1105
1106   rd.data_size = sizeof (*rec);
1107   rd.data = rec;
1108
1109   GNUNET_NAMESTORE_records_store (namestore, &hst->plc.ego_key,
1110                                   name, 1, &rd, namestore_result_host_advertise,
1111                                   hst);
1112 }
1113
1114
1115 /**
1116  * Send a message to all nyms that are present in the place.
1117  *
1118  * This function is restricted to the host.  Nyms can only send requests
1119  * to the host who can decide to relay it to everyone in the place.
1120  *
1121  * @param host  Host of the place.
1122  * @param method_name Method to use for the announcement.
1123  * @param env  Environment containing variables for the message and operations
1124  *          on objects of the place.  Can be NULL.
1125  * @param notify Function to call to get the payload of the announcement.
1126  * @param notify_cls Closure for @a notify.
1127  * @param flags Flags for this announcement.
1128  *
1129  * @return NULL on error (announcement already in progress?).
1130  */
1131 struct GNUNET_SOCIAL_Announcement *
1132 GNUNET_SOCIAL_host_announce (struct GNUNET_SOCIAL_Host *hst,
1133                              const char *method_name,
1134                              const struct GNUNET_ENV_Environment *env,
1135                              GNUNET_PSYC_TransmitNotifyData notify_data,
1136                              void *notify_data_cls,
1137                              enum GNUNET_SOCIAL_AnnounceFlags flags)
1138 {
1139   if (GNUNET_OK ==
1140       GNUNET_PSYC_transmit_message (hst->plc.tmit, method_name, env,
1141                                     NULL, notify_data, notify_data_cls, flags));
1142   return (struct GNUNET_SOCIAL_Announcement *) hst->plc.tmit;
1143 }
1144
1145
1146 /**
1147  * Resume transmitting announcement.
1148  *
1149  * @param a
1150  *        The announcement to resume.
1151  */
1152 void
1153 GNUNET_SOCIAL_host_announce_resume (struct GNUNET_SOCIAL_Announcement *a)
1154 {
1155   GNUNET_PSYC_transmit_resume ((struct GNUNET_PSYC_TransmitHandle *) a);
1156 }
1157
1158
1159 /**
1160  * Cancel announcement.
1161  *
1162  * @param a
1163  *        The announcement to cancel.
1164  */
1165 void
1166 GNUNET_SOCIAL_host_announce_cancel (struct GNUNET_SOCIAL_Announcement *a)
1167 {
1168   GNUNET_PSYC_transmit_cancel ((struct GNUNET_PSYC_TransmitHandle *) a);
1169 }
1170
1171
1172 /**
1173  * Obtain handle for a hosted place.
1174  *
1175  * The returned handle can be used to access the place API.
1176  *
1177  * @param host  Handle for the host.
1178  *
1179  * @return Handle for the hosted place, valid as long as @a host is valid.
1180  */
1181 struct GNUNET_SOCIAL_Place *
1182 GNUNET_SOCIAL_host_get_place (struct GNUNET_SOCIAL_Host *hst)
1183 {
1184   return &hst->plc;
1185 }
1186
1187
1188 /**
1189  * Stop hosting a place.
1190  *
1191  * Invalidates host handle.
1192  *
1193  * @param host  Host leaving the place.
1194  * @param keep_active  Keep the place active after last host disconnected.
1195  */
1196 void
1197 GNUNET_SOCIAL_host_leave (struct GNUNET_SOCIAL_Host *hst,
1198                           int keep_active,
1199                           GNUNET_ContinuationCallback leave_cb,
1200                           void *leave_cls)
1201 {
1202   struct GNUNET_SOCIAL_Place *plc = &hst->plc;
1203
1204  /* FIXME: send msg to service */
1205
1206   plc->is_disconnecting = GNUNET_YES;
1207   plc->disconnect_cb = leave_cb;
1208   plc->disconnect_cls = leave_cls;
1209
1210   GNUNET_CLIENT_MANAGER_disconnect (plc->client, GNUNET_YES,
1211                                     &host_cleanup, hst);
1212 }
1213
1214
1215 static struct GuestEnterRequest *
1216 guest_enter_request_create (const struct GNUNET_CRYPTO_EcdsaPrivateKey *guest_key,
1217                             const struct GNUNET_CRYPTO_EddsaPublicKey *place_key,
1218                             const struct GNUNET_PeerIdentity *origin,
1219                             size_t relay_count,
1220                             const struct GNUNET_PeerIdentity *relays,
1221                             const struct GNUNET_PSYC_Message *join_msg)
1222 {
1223   uint16_t join_msg_size = ntohs (join_msg->header.size);
1224   uint16_t relay_size = relay_count * sizeof (*relays);
1225
1226   struct GuestEnterRequest *
1227     req = GNUNET_malloc (sizeof (*req) + relay_size + join_msg_size);
1228
1229   req->header.size = htons (sizeof (*req) + relay_size + join_msg_size);
1230   req->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER);
1231   req->place_key = *place_key;
1232   req->guest_key = *guest_key;
1233   req->origin = *origin;
1234   req->relay_count = relay_count;
1235
1236   uint16_t p = sizeof (*req);
1237   if (0 < relay_size)
1238   {
1239     memcpy ((char *) req + p, relays, relay_size);
1240     p += relay_size;
1241   }
1242
1243   memcpy ((char *) req + p, join_msg, join_msg_size);
1244   return req;
1245 }
1246
1247 /**
1248  * Request entry to a place as a guest.
1249  *
1250  * @param cfg Configuration to contact the social service.
1251  * @param ego  Identity of the guest.
1252  * @param crypto_address Public key of the place to enter.
1253  * @param origin Peer identity of the origin of the underlying multicast group.
1254  * @param relay_count Number of elements in the @a relays array.
1255  * @param relays Relays for the underlying multicast group.
1256  * @param method_name Method name for the message.
1257  * @param env Environment containing variables for the message, or NULL.
1258  * @param data Payload for the message to give to the enter callback.
1259  * @param data_size Number of bytes in @a data.
1260  * @param slicer Slicer to use for processing incoming requests from guests.
1261  *
1262  * @return NULL on errors, otherwise handle for the guest.
1263  */
1264 struct GNUNET_SOCIAL_Guest *
1265 GNUNET_SOCIAL_guest_enter (const struct GNUNET_CONFIGURATION_Handle *cfg,
1266                            const struct GNUNET_IDENTITY_Ego *ego,
1267                            const struct GNUNET_CRYPTO_EddsaPublicKey *place_key,
1268                            const struct GNUNET_PeerIdentity *origin,
1269                            uint32_t relay_count,
1270                            const struct GNUNET_PeerIdentity *relays,
1271                            const struct GNUNET_PSYC_Message *entry_msg,
1272                            struct GNUNET_SOCIAL_Slicer *slicer,
1273                            GNUNET_SOCIAL_GuestEnterCallback local_enter_cb,
1274                            GNUNET_SOCIAL_EntryDecisionCallback entry_dcsn_cb,
1275                            void *cls)
1276 {
1277   struct GNUNET_SOCIAL_Guest *gst = GNUNET_malloc (sizeof (*gst));
1278   struct GNUNET_SOCIAL_Place *plc = &gst->plc;
1279
1280   struct GuestEnterRequest *
1281     req = guest_enter_request_create (&plc->ego_key, place_key, origin,
1282                                       relay_count, relays, entry_msg);
1283   plc->connect_msg = &req->header;
1284   plc->ego_key = *GNUNET_IDENTITY_ego_get_private_key (ego);
1285   plc->pub_key = *place_key;
1286   plc->cfg = cfg;
1287   plc->is_host = GNUNET_YES;
1288   plc->slicer = slicer;
1289
1290   gst->enter_cb = local_enter_cb;
1291   gst->entry_dcsn_cb = entry_dcsn_cb;
1292   gst->cb_cls = cls;
1293
1294   plc->client = GNUNET_CLIENT_MANAGER_connect (cfg, "social", guest_handlers);
1295   GNUNET_CLIENT_MANAGER_set_user_context_ (plc->client, gst, sizeof (*plc));
1296
1297   plc->tmit = GNUNET_PSYC_transmit_create (plc->client);
1298   plc->recv = GNUNET_PSYC_receive_create (NULL, &slicer_message, plc->slicer);
1299
1300   place_send_connect_msg (plc);
1301   return gst;
1302 }
1303
1304
1305 /**
1306  * Result of a GNS name lookup for entering a place.
1307  *
1308  * @see GNUNET_SOCIAL_guest_enter_by_name
1309  */
1310 static void
1311 gns_result_guest_enter (void *cls, uint32_t rd_count,
1312                         const struct GNUNET_GNSRECORD_Data *rd)
1313 {
1314   struct GNUNET_SOCIAL_Guest *gst = cls;
1315   struct GNUNET_SOCIAL_Place *plc = &gst->plc;
1316
1317   const struct GNUNET_GNSRECORD_PlaceData *
1318     rec = (const struct GNUNET_GNSRECORD_PlaceData *) rd->data;
1319
1320   if (0 == rd_count)
1321   {
1322     if (NULL != gst->enter_cb)
1323       gst->enter_cb (gst->cb_cls, GNUNET_SYSERR, 0);
1324     return;
1325   }
1326
1327
1328   if (rd->data_size < sizeof (*rec))
1329   {
1330     GNUNET_break_op (0);
1331     if (NULL != gst->enter_cb)
1332       gst->enter_cb (gst->cb_cls, GNUNET_SYSERR, 0);
1333     return;
1334   }
1335
1336   struct GuestEnterRequest *
1337     req = (struct GuestEnterRequest *) plc->connect_msg;
1338   uint16_t req_size = ntohs (req->header.size);
1339
1340   struct GNUNET_PeerIdentity *relays = NULL;
1341   uint16_t relay_count = ntohs (rec->relay_count);
1342
1343   if (0 < relay_count)
1344   {
1345     uint16_t relay_size = relay_count * sizeof (struct GNUNET_PeerIdentity);
1346     struct GuestEnterRequest *
1347       req2 = GNUNET_malloc (req_size + relay_size);
1348
1349     req2->header.size = htons (req_size + relay_size);
1350     req2->header.type = req->header.type;
1351     req2->guest_key = req->guest_key;
1352
1353     uint16_t p = sizeof (*req);
1354     if (0 < relay_size)
1355     {
1356       memcpy ((char *) req2 + p, relays, relay_size);
1357       p += relay_size;
1358     }
1359
1360     memcpy ((char *) req + p, &req[1], req_size - sizeof (*req));
1361
1362     plc->connect_msg = &req2->header;
1363     GNUNET_free (req);
1364     req = req2;
1365   }
1366
1367   req->place_key = rec->place_key;
1368   req->origin = rec->origin;
1369   req->relay_count = rec->relay_count;
1370   memcpy (&req[1], &rec[1],
1371           ntohl (rec->relay_count) * sizeof (struct GNUNET_PeerIdentity));
1372
1373   plc->connect_msg = &req->header;
1374   plc->pub_key = req->place_key;
1375
1376   plc->tmit = GNUNET_PSYC_transmit_create (plc->client);
1377   plc->recv = GNUNET_PSYC_receive_create (NULL, &slicer_message, plc);
1378
1379   place_send_connect_msg (plc);
1380 }
1381
1382 /**
1383  * Request entry to a place as a guest.
1384  *
1385  * @param cfg  Configuration to contact the social service.
1386  * @param ego  Identity of the guest.
1387  * @param address GNS name of the place to enter.  Either in the form of
1388  *        'room.friend.gnu', or 'NYMPUBKEY.zkey'.  This latter case refers to
1389  *        the 'PLACE' record of the empty label ("+") in the GNS zone with the
1390  *        nym's public key 'NYMPUBKEY', and can be used to request entry to a
1391  *        pseudonym's place directly.
1392  * @param method_name Method name for the message.
1393  * @param env Environment containing variables for the message, or NULL.
1394  * @param data Payload for the message to give to the enter callback.
1395  * @param data_size Number of bytes in @a data.
1396  * @param slicer Slicer to use for processing incoming requests from guests.
1397  *
1398  * @return NULL on errors, otherwise handle for the guest.
1399  */
1400 struct GNUNET_SOCIAL_Guest *
1401 GNUNET_SOCIAL_guest_enter_by_name (const struct GNUNET_CONFIGURATION_Handle *cfg,
1402                                    struct GNUNET_IDENTITY_Ego *ego,
1403                                    char *gns_name,
1404                                    const struct GNUNET_PSYC_Message *join_msg,
1405                                    struct GNUNET_SOCIAL_Slicer *slicer,
1406                                    GNUNET_SOCIAL_GuestEnterCallback local_enter_cb,
1407                                    GNUNET_SOCIAL_EntryDecisionCallback entry_decision_cb,
1408                                    void *cls)
1409 {
1410   struct GNUNET_SOCIAL_Guest *gst = GNUNET_malloc (sizeof (*gst));
1411   struct GNUNET_SOCIAL_Place *plc = &gst->plc;
1412
1413   gst->enter_cb = local_enter_cb;
1414   gst->cb_cls = cls;
1415
1416   plc->ego_key = *GNUNET_IDENTITY_ego_get_private_key (ego);
1417   plc->cfg = cfg;
1418   plc->is_host = GNUNET_NO;
1419   plc->slicer = slicer;
1420
1421   struct GuestEnterRequest *
1422     req = guest_enter_request_create (&plc->ego_key, NULL, NULL, 0, NULL,
1423                                       join_msg);
1424   plc->connect_msg = &req->header;
1425
1426   /* FIXME: get the public key of the origin and relays
1427    *        by looking up the PLACE record of gns_name.
1428    */
1429   if (NULL == gns)
1430     gns = GNUNET_GNS_connect (cfg);
1431
1432   plc->client = GNUNET_CLIENT_MANAGER_connect (cfg, "social", guest_handlers);
1433   GNUNET_CLIENT_MANAGER_set_user_context_ (plc->client, gst, sizeof (*plc));
1434
1435   struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
1436   GNUNET_IDENTITY_ego_get_public_key (ego, &ego_pub_key);
1437   GNUNET_GNS_lookup (gns, gns_name, &ego_pub_key,
1438                      GNUNET_GNSRECORD_TYPE_PLACE, GNUNET_GNS_LO_DEFAULT,
1439                      NULL, gns_result_guest_enter, gst);
1440
1441   return gst;
1442 }
1443
1444
1445 /**
1446  * Talk to the host of the place.
1447  *
1448  * @param place
1449  *        Place where we want to talk to the host.
1450  * @param method_name
1451  *        Method to invoke on the host.
1452  * @param env
1453  *        Environment containing variables for the message, or NULL.
1454  * @param notify_data
1455  *        Function to use to get the payload for the method.
1456  * @param notify_data_cls
1457  *        Closure for @a notify_data.
1458  * @param flags
1459  *        Flags for the message being sent.
1460  *
1461  * @return NULL if we are already trying to talk to the host,
1462  *         otherwise handle to cancel the request.
1463  */
1464 struct GNUNET_SOCIAL_TalkRequest *
1465 GNUNET_SOCIAL_guest_talk (struct GNUNET_SOCIAL_Guest *gst,
1466                           const char *method_name,
1467                           const struct GNUNET_ENV_Environment *env,
1468                           GNUNET_PSYC_TransmitNotifyData notify_data,
1469                           void *notify_data_cls,
1470                           enum GNUNET_SOCIAL_TalkFlags flags)
1471 {
1472   if (GNUNET_OK ==
1473       GNUNET_PSYC_transmit_message (gst->plc.tmit, method_name, env,
1474                                     NULL, notify_data, notify_data_cls, flags));
1475   return (struct GNUNET_SOCIAL_TalkRequest *) gst->plc.tmit;
1476 }
1477
1478
1479 /**
1480  * Resume talking to the host of the place.
1481  *
1482  * @param tr
1483  *        Talk request to resume.
1484  */
1485 void
1486 GNUNET_SOCIAL_guest_talk_resume (struct GNUNET_SOCIAL_TalkRequest *tr)
1487 {
1488   GNUNET_PSYC_transmit_resume ((struct GNUNET_PSYC_TransmitHandle *) tr);
1489 }
1490
1491
1492 /**
1493  * Cancel talking to the host of the place.
1494  *
1495  * @param tr
1496  *        Talk request to cancel.
1497  */
1498 void
1499 GNUNET_SOCIAL_guest_talk_cancel (struct GNUNET_SOCIAL_TalkRequest *tr)
1500 {
1501   GNUNET_PSYC_transmit_cancel ((struct GNUNET_PSYC_TransmitHandle *) tr);
1502 }
1503
1504
1505 /**
1506  * Leave a place permanently.
1507  *
1508  * Notifies the owner of the place about leaving, and destroys the place handle.
1509  *
1510  * @param place Place to leave permanently.
1511  * @param keep_active Keep place active after last application disconnected.
1512  */
1513 void
1514 GNUNET_SOCIAL_guest_leave (struct GNUNET_SOCIAL_Guest *gst,
1515                            int keep_active,
1516                            GNUNET_ContinuationCallback leave_cb,
1517                            void *leave_cls)
1518 {
1519   struct GNUNET_SOCIAL_Place *plc = &gst->plc;
1520
1521   /* FIXME: send msg to service */
1522
1523   plc->is_disconnecting = GNUNET_YES;
1524   plc->disconnect_cb = leave_cb;
1525   plc->disconnect_cls = leave_cls;
1526
1527   GNUNET_CLIENT_MANAGER_disconnect (plc->client, GNUNET_YES,
1528                                     &guest_cleanup, gst);
1529 }
1530
1531
1532 /**
1533  * Obtain handle for a place entered as guest.
1534  *
1535  * The returned handle can be used to access the place API.
1536  *
1537  * @param guest  Handle for the guest.
1538  *
1539  * @return Handle for the place, valid as long as @a guest is valid.
1540  */
1541 struct GNUNET_SOCIAL_Place *
1542 GNUNET_SOCIAL_guest_get_place (struct GNUNET_SOCIAL_Guest *gst)
1543 {
1544   return &gst->plc;
1545 }
1546
1547
1548 /**
1549  * A history lesson.
1550  */
1551 struct GNUNET_SOCIAL_HistoryLesson;
1552
1553 /**
1554  * Learn about the history of a place.
1555  *
1556  * Sends messages through the slicer function of the place where
1557  * start_message_id <= message_id <= end_message_id.
1558  * The messages will have the #GNUNET_PSYC_MESSAGE_HISTORIC flag set.
1559  *
1560  * To get the latest message, use 0 for both the start and end message ID.
1561  *
1562  * @param place Place we want to learn more about.
1563  * @param start_message_id First historic message we are interested in.
1564  * @param end_message_id Last historic message we are interested in (inclusive).
1565  * @param slicer Slicer to use to process history.  Can be the same as the
1566  *               slicer of the place, as the HISTORIC flag allows distinguishing
1567  *               old messages from fresh ones.
1568  * @param finish_cb Function called after the last message in the history lesson
1569  *              is passed through the @a slicer. NULL if not needed.
1570  * @param finish_cb_cls Closure for @a finish_cb.
1571  * @return Handle to abort history lesson, never NULL (multiple lessons
1572  *         at the same time are allowed).
1573  */
1574 struct GNUNET_SOCIAL_HistoryLesson *
1575 GNUNET_SOCIAL_place_get_history (struct GNUNET_SOCIAL_Place *place,
1576                                  uint64_t start_message_id,
1577                                  uint64_t end_message_id,
1578                                  const struct GNUNET_SOCIAL_Slicer *slicer,
1579                                  void (*finish_cb)(void *),
1580                                  void *finish_cb_cls)
1581 {
1582   return NULL;
1583 }
1584
1585
1586 /**
1587  * Stop processing messages from the history lesson.
1588  *
1589  * Must not be called after the finish callback of the history lesson is called.
1590  *
1591  * @param hist History lesson to cancel.
1592  */
1593 void
1594 GNUNET_SOCIAL_place_get_history_cancel (struct GNUNET_SOCIAL_HistoryLesson *hist)
1595 {
1596
1597 }
1598
1599
1600 struct GNUNET_SOCIAL_WatchHandle;
1601
1602 /**
1603  * Watch a place for changed objects.
1604  *
1605  * @param place
1606  *        Place to watch.
1607  * @param object_filter
1608  *        Object prefix to match.
1609  * @param state_var_cb
1610  *        Function to call when an object/state var changes.
1611  * @param cls
1612  *        Closure for callback.
1613  *
1614  * @return Handle that can be used to cancel watching.
1615  */
1616 struct GNUNET_SOCIAL_WatchHandle *
1617 GNUNET_SOCIAL_place_watch (struct GNUNET_SOCIAL_Place *place,
1618                            const char *object_filter,
1619                            GNUNET_PSYC_StateVarCallback state_var_cb,
1620                            void *cls)
1621 {
1622   return NULL;
1623 }
1624
1625
1626 /**
1627  * Cancel watching a place for changed objects.
1628  *
1629  * @param wh Watch handle to cancel.
1630  */
1631 void
1632 GNUNET_SOCIAL_place_watch_cancel (struct GNUNET_SOCIAL_WatchHandle *wh)
1633 {
1634
1635 }
1636
1637
1638 struct GNUNET_SOCIAL_LookHandle;
1639
1640
1641 /**
1642  * Look at objects in the place with a matching name prefix.
1643  *
1644  * @param place
1645  *        The place to look its objects at.
1646  * @param name_prefix
1647  *        Look at objects with names beginning with this value.
1648  * @param state_var_cb
1649  *        Function to call for each object found.
1650  * @param cls
1651  *        Closure for callback function.
1652  *
1653  * @return Handle that can be used to stop looking at objects.
1654  */
1655 struct GNUNET_SOCIAL_LookHandle *
1656 GNUNET_SOCIAL_place_look (struct GNUNET_SOCIAL_Place *place,
1657                           const char *name_prefix,
1658                           GNUNET_PSYC_StateVarCallback state_var_cb,
1659                           void *cls)
1660 {
1661   return NULL;
1662 }
1663
1664
1665 /**
1666  * Stop looking at objects.
1667  *
1668  * @param lh Look handle to stop.
1669  */
1670 void
1671 GNUNET_SOCIAL_place_look_cancel (struct GNUNET_SOCIAL_LookHandle *lh)
1672 {
1673
1674 }
1675
1676
1677
1678 /**
1679  * Look at a particular object in the place.
1680  *
1681  * The best matching object is returned (its name might be less specific than
1682  * what was requested).
1683  *
1684  * @param place The place to look the object at.
1685  * @param full_name Full name of the object.
1686  * @param value_size Set to the size of the returned value.
1687  * @return NULL if there is no such object at this place.
1688  */
1689 const void *
1690 GNUNET_SOCIAL_place_look_at (struct GNUNET_SOCIAL_Place *place,
1691                              const char *full_name,
1692                              size_t *value_size)
1693 {
1694   return NULL;
1695 }
1696
1697
1698 /* end of social_api.c */