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