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