gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r36767 - in gnunet/src: include social


From: gnunet
Subject: [GNUnet-SVN] r36767 - in gnunet/src: include social
Date: Thu, 17 Dec 2015 15:12:45 +0100

Author: tg
Date: 2015-12-17 15:12:44 +0100 (Thu, 17 Dec 2015)
New Revision: 36767

Modified:
   gnunet/src/include/gnunet_gnsrecord_lib.h
   gnunet/src/include/gnunet_protocols.h
   gnunet/src/include/gnunet_social_service.h
   gnunet/src/social/Makefile.am
   gnunet/src/social/gnunet-service-social.c
   gnunet/src/social/social.h
   gnunet/src/social/social_api.c
   gnunet/src/social/test_social.c
Log:
social: API changes for application connections: store/load app subscriptions 
to places

Modified: gnunet/src/include/gnunet_gnsrecord_lib.h
===================================================================
--- gnunet/src/include/gnunet_gnsrecord_lib.h   2015-12-16 17:43:13 UTC (rev 
36766)
+++ gnunet/src/include/gnunet_gnsrecord_lib.h   2015-12-17 14:12:44 UTC (rev 
36767)
@@ -195,7 +195,7 @@
   /**
    * Public key of the place.
    */
-  struct GNUNET_CRYPTO_EddsaPublicKey place_key;
+  struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key;
 
   /**
    * Peer identity of the origin.

Modified: gnunet/src/include/gnunet_protocols.h
===================================================================
--- gnunet/src/include/gnunet_protocols.h       2015-12-16 17:43:13 UTC (rev 
36766)
+++ gnunet/src/include/gnunet_protocols.h       2015-12-17 14:12:44 UTC (rev 
36767)
@@ -2607,19 +2607,39 @@
 /** C->S: request to enter a place as a guest */
 #define GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER 843
 
+/** C->S: request to enter a place as a guest, using a GNS address */
+#define GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_BY_NAME 844
+
 /** S->C: guest enter acknowledgement */
-#define GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ACK 844
+#define GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ACK 845
 
 /** P->S->C: incoming entry request from PSYC */
-#define GNUNET_MESSAGE_TYPE_SOCIAL_ENTRY_REQUEST 845
+#define GNUNET_MESSAGE_TYPE_SOCIAL_ENTRY_REQUEST 846
 
 /** C->S->P: decision about an entry request */
-#define GNUNET_MESSAGE_TYPE_SOCIAL_ENTRY_DECISION 846
+#define GNUNET_MESSAGE_TYPE_SOCIAL_ENTRY_DECISION 847
 
-/** C->S: listen for places */
-#define GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LISTEN 850
+/** C->S: request to leave a place */
+#define GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE 848
 
+/** C->S: add place to GNS zone */
+#define GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_PLACE 849
 
+/** C->S: add nym to GNS zone */
+#define GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_NYM 850
+
+/** C->S: connect application */
+#define GNUNET_MESSAGE_TYPE_SOCIAL_APP_CONNECT 851
+
+/** C->S: detach a place from application */
+#define GNUNET_MESSAGE_TYPE_SOCIAL_APP_DETACH 852
+
+/** S->C: notify about an existing ego */
+#define GNUNET_MESSAGE_TYPE_SOCIAL_APP_EGO 853
+
+/** S->C: notify about an existing place */
+#define GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE 854
+
 
/*******************************************************************************
  * X-VINE DHT messages
  
******************************************************************************/

Modified: gnunet/src/include/gnunet_social_service.h
===================================================================
--- gnunet/src/include/gnunet_social_service.h  2015-12-16 17:43:13 UTC (rev 
36766)
+++ gnunet/src/include/gnunet_social_service.h  2015-12-17 14:12:44 UTC (rev 
36767)
@@ -48,8 +48,22 @@
  */
 #define GNUNET_SOCIAL_VERSION 0x00000000
 
+/**
+ * Maximum size of client ID including '\0' terminator.
+ */
+#define GNUNET_SOCIAL_APP_MAX_ID_SIZE 256
 
 /**
+ * Handle for an application.
+ */
+struct GNUNET_SOCIAL_App;
+
+/**
+ * Handle for an ego (own identity)
+ */
+struct GNUNET_SOCIAL_Ego;
+
+/**
  * Handle for a pseudonym of another user in the network.
  */
 struct GNUNET_SOCIAL_Nym;
@@ -74,7 +88,145 @@
  */
 struct GNUNET_SOCIAL_Slicer;
 
+
+
+
 /**
+ * Handle that can be used to reconnect to a place as host.
+ */
+struct GNUNET_SOCIAL_HostConnection;
+
+/**
+ * Handle that can be used to reconnect to a place as guest.
+ */
+struct GNUNET_SOCIAL_GuestConnection;
+
+/**
+ * Notification about an available identity.
+ *
+ * @param cls
+ *        Closure.
+ * @param pub_key
+ *        Public key of ego.
+ * @param name
+ *        Name of ego.
+ */
+typedef void
+(*GNUNET_SOCIAL_AppEgoCallback) (void *cls,
+                                 struct GNUNET_SOCIAL_Ego *ego,
+                                 const struct GNUNET_CRYPTO_EcdsaPublicKey 
*ego_pub_key,
+                                 const char *name);
+
+
+/**
+ * Notification about a place entered.
+ */
+typedef void
+(*GNUNET_SOCIAL_AppHostPlaceCallback) (void *cls,
+                                       struct GNUNET_SOCIAL_HostConnection 
*hconn,
+                                       struct GNUNET_SOCIAL_Ego *ego,
+                                       const struct 
GNUNET_CRYPTO_EddsaPublicKey *place_pub_key);
+
+/**
+h * Notification about a place entered.
+ */
+typedef void
+(*GNUNET_SOCIAL_AppGuestPlaceCallback) (void *cls,
+                                        struct GNUNET_SOCIAL_GuestConnection 
*gconn,
+                                        struct GNUNET_SOCIAL_Ego *ego,
+                                        const struct 
GNUNET_CRYPTO_EddsaPublicKey *place_pub_key);
+
+
+/**
+ * Establish application connection to the social service.
+ *
+ * The @host_place_cb and @guest_place_cb functions are
+ * initially called for each entered places,
+ * then later each time a new place is entered with the current app ID.
+ *
+ * @param cfg
+ *        Configuration.
+ * @param ego_cb
+ *        Function to notify about an available ego.
+ * @param host_cb
+ *        Function to notify about a place entered as host.
+ * @param guest_cb
+ *        Function to notify about a place entered as guest.
+ * @param cls
+ *        Closure for the callbacks.
+ *
+ * @return Handle that can be used to stop listening.
+ */
+struct GNUNET_SOCIAL_App *
+GNUNET_SOCIAL_app_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
+                           const char *id,
+                           GNUNET_SOCIAL_AppEgoCallback ego_cb,
+                           GNUNET_SOCIAL_AppHostPlaceCallback host_cb,
+                           GNUNET_SOCIAL_AppGuestPlaceCallback guest_cb,
+                           void *cls);
+
+
+/**
+ * Disconnect app.
+ *
+ * @param c
+ *        App handle.
+ */
+void
+GNUNET_SOCIAL_app_disconnect (struct GNUNET_SOCIAL_App *app);
+
+
+/**
+ * Get the public key of @a ego.
+ *
+ * @param ego
+ *        Ego.
+ *
+ * @return Public key of ego.
+ */
+const struct GNUNET_CRYPTO_EcdsaPublicKey *
+GNUNET_SOCIAL_ego_get_pub_key (const struct GNUNET_SOCIAL_Ego *ego);
+
+
+/**
+ * Get the name of @a ego.
+ *
+ * @param ego
+ *        Ego.
+ *
+ * @return Public key of @a ego.
+ */
+const char *
+GNUNET_SOCIAL_ego_get_name (const struct GNUNET_SOCIAL_Ego *ego);
+
+
+/**
+ * Get the public key of a @a nym.
+ *
+ * Suitable, for example, to be used with GNUNET_SOCIAL_zone_add_nym().
+ *
+ * @param nym
+ *        Pseudonym to map to a cryptographic identifier.
+ *
+ * @return Public key of nym.
+ */
+const struct GNUNET_CRYPTO_EcdsaPublicKey *
+GNUNET_SOCIAL_nym_get_pub_key (const struct GNUNET_SOCIAL_Nym *nym);
+
+
+/**
+ * Get the hash of the public key of a @a nym.
+ *
+ * @param nym
+ *        Pseudonym to map to a cryptographic identifier.
+ *
+ * @return Hash of the public key of nym.
+ */
+const struct GNUNET_HashCode *
+GNUNET_SOCIAL_nym_get_pub_key_hash (const struct GNUNET_SOCIAL_Nym *nym);
+
+
+/**
  * Function called upon receiving a message indicating a call to a @e method.
  *
  * This function is called one or more times for each message until all data
@@ -352,7 +504,7 @@
 
 
 /**
- * Function called after the host entered the place.
+ * Function called after the host entered a home.
  *
  * @param cls
  *        Closure.
@@ -359,6 +511,8 @@
  * @param result
  *        #GNUNET_OK on success, or
  *        #GNUNET_SYSERR on error.
+ * @param place_pub_key
+ *        Public key of home.
  * @param max_message_id
  *        Last message ID sent to the channel.
  *        Or 0 if no messages have been sent to the place yet.
@@ -365,6 +519,7 @@
  */
 typedef void
 (*GNUNET_SOCIAL_HostEnterCallback) (void *cls, int result,
+                                    const struct GNUNET_CRYPTO_EddsaPublicKey 
*place_pub_key,
                                     uint64_t max_message_id);
 
 
@@ -385,6 +540,8 @@
  *        Policy specifying entry and history restrictions for the place.
  * @param slicer
  *        Slicer to handle incoming messages.
+ * @param enter_cb
+ *        Function called when the place is entered and ready to use.
  * @param answer_door_cb
  *        Function to handle new nyms that want to enter.
  * @param farewell_cb
@@ -395,9 +552,8 @@
  * @return Handle for the host.
  */
 struct GNUNET_SOCIAL_Host *
-GNUNET_SOCIAL_host_enter (const struct GNUNET_CONFIGURATION_Handle *cfg,
-                          const struct GNUNET_IDENTITY_Ego *ego,
-                          const struct GNUNET_CRYPTO_EddsaPrivateKey 
*place_key,
+GNUNET_SOCIAL_host_enter (const struct GNUNET_SOCIAL_App *app,
+                          const struct GNUNET_SOCIAL_Ego *ego,
                           enum GNUNET_PSYC_Policy policy,
                           struct GNUNET_SOCIAL_Slicer *slicer,
                           GNUNET_SOCIAL_HostEnterCallback enter_cb,
@@ -407,6 +563,34 @@
 
 
 /**
+ * Reconnect to an already entered place as host.
+ *
+ * @param hconn
+ *        Host connection handle.
+ *        @see GNUNET_SOCIAL_app_connect() & 
GNUNET_SOCIAL_AppHostPlaceCallback()
+ * @param slicer
+ *        Slicer to handle incoming messages.
+ * @param enter_cb
+ *        Function called when the place is entered and ready to use.
+ * @param answer_door_cb
+ *        Function to handle new nyms that want to enter.
+ * @param farewell_cb
+ *        Function to handle departing nyms.
+ * @param cls
+ *        Closure for the callbacks.
+ *
+ * @return Handle for the host.
+ */
+struct GNUNET_SOCIAL_Host *
+GNUNET_SOCIAL_host_enter_reconnect (struct GNUNET_SOCIAL_HostConnection *hconn,
+                                    struct GNUNET_SOCIAL_Slicer *slicer,
+                                    GNUNET_SOCIAL_HostEnterCallback enter_cb,
+                                    GNUNET_SOCIAL_AnswerDoorCallback 
answer_door_cb,
+                                    GNUNET_SOCIAL_FarewellCallback farewell_cb,
+                                    void *cls);
+
+
+/**
  * Decision whether to admit @a nym into the place or refuse entry.
  *
  * @param hst
@@ -438,6 +622,8 @@
 /**
  * Throw @a nym out of the place.
  *
+ * Sends a _notice_place_leave announcement to the home.
+ *
  * The @a nym reference will remain valid until the
  * #GNUNET_SOCIAL_FarewellCallback is invoked,
  * which should be very soon after this call.
@@ -446,72 +632,17 @@
  *        Host of the place.
  * @param nym
  *        Handle for the entity to be ejected.
+ * @param env
+ *        Environment for the message or NULL.
+ *        _nym is set to @e nym regardless whether an @e env is provided.
  */
 void
 GNUNET_SOCIAL_host_eject (struct GNUNET_SOCIAL_Host *host,
-                          const struct GNUNET_SOCIAL_Nym *nym);
+                          const struct GNUNET_SOCIAL_Nym *nym,
+                          struct GNUNET_ENV_Environment *env);
 
 
 /**
- * Get the public key of a @a nym.
- *
- * Suitable, for example, to be used with GNUNET_NAMESTORE_zone_to_name().
- *
- * @param nym
- *        Pseudonym to map to a cryptographic identifier.
- *
- * @return Public key of nym.
- */
-const struct GNUNET_CRYPTO_EcdsaPublicKey *
-GNUNET_SOCIAL_nym_get_key (const struct GNUNET_SOCIAL_Nym *nym);
-
-
-/**
- * Get the hash of the public key of a @a nym.
- *
- * @param nym
- *        Pseudonym to map to a cryptographic identifier.
- *
- * @return Hash of the public key of nym.
- */
-const struct GNUNET_HashCode *
-GNUNET_SOCIAL_nym_get_key_hash (const struct GNUNET_SOCIAL_Nym *nym);
-
-
-/**
- * Advertise the place in the GNS zone of the @e ego of the @a host.
- *
- * @param hst
- *        Host of the place.
- * @param name
- *        The name for the PLACE record to put in the zone.
- * @param peer_count
- *        Number of elements in the @a peers array.
- * @param peers
- *        List of peers to put in the PLACE record to advertise
- *        as entry points to the place in addition to the origin.
- * @param expiration_time
- *        Expiration time of the record, use 0 to remove the record.
- * @param password
- *        Password used to encrypt the record.
- *        FIXME: not implemented yet.
- * @param result_cb
- *        Function called with the result of the operation.
- * @param result_cls
- *        Closure for @a result_cb
- */
-void
-GNUNET_SOCIAL_host_advertise (struct GNUNET_SOCIAL_Host *host,
-                              const char *name,
-                              uint32_t peer_count,
-                              const struct GNUNET_PeerIdentity *peers,
-                              struct GNUNET_TIME_Absolute expiration_time,
-                              const char *password,
-                              GNUNET_NAMESTORE_ContinuationWithStatus 
result_cb,
-                              void *result_cls);
-
-
-/**
  * Flags for announcements by a host.
  */
 enum GNUNET_SOCIAL_AnnounceFlags
@@ -602,25 +733,44 @@
 
 
 /**
- * Stop hosting a place.
+ * Disconnect from a home.
  *
  * Invalidates host handle.
  *
- * @param host
- *        Host leaving the place.
- * @param keep_active
- *        Keep the place active after last host disconnected.
- * @param leave_cb
+ * @param hst
+ *        The host to disconnect.
+ * @param disconnect_cb
+ *        Function called after disconnected from the service.
+ * @param cls
+ *        Closure for @a disconnect_cb.
+ */
+void
+GNUNET_SOCIAL_host_disconnect (struct GNUNET_SOCIAL_Host *hst,
+                               GNUNET_ContinuationCallback disconnect_cb,
+                               void *cls);
+
+
+/**
+ * Stop hosting a home.
+ *
+ * Sends a _notice_place_closed announcement to the home.
+ * Invalidates host handle.
+ *
+ * @param hst
+ *        Host leaving.
+ * @param env
+ *        Environment for the message or NULL.
+ * @param disconnect_cb
  *        Function called after the host left the place
- *        and disconnected from the social service.
- * @param leave_cls
- *        Closure for @a leave_cb.
+ *        and disconnected from the service.
+ * @param cls
+ *        Closure for @a disconnect_cb.
  */
 void
-GNUNET_SOCIAL_host_leave (struct GNUNET_SOCIAL_Host *host,
-                          int keep_active,
-                          GNUNET_ContinuationCallback leave_cb,
-                          void *leave_cls);
+GNUNET_SOCIAL_host_leave (struct GNUNET_SOCIAL_Host *hst,
+                          const struct GNUNET_ENV_Environment *env,
+                          GNUNET_ContinuationCallback disconnect_cb,
+                          void *cls);
 
 
 /**
@@ -689,9 +839,9 @@
  * @return NULL on errors, otherwise handle for the guest.
  */
 struct GNUNET_SOCIAL_Guest *
-GNUNET_SOCIAL_guest_enter (const struct GNUNET_CONFIGURATION_Handle *cfg,
-                           const struct GNUNET_IDENTITY_Ego *ego,
-                           const struct GNUNET_CRYPTO_EddsaPublicKey 
*place_key,
+GNUNET_SOCIAL_guest_enter (const struct GNUNET_SOCIAL_App *app,
+                           const struct GNUNET_SOCIAL_Ego *ego,
+                           const struct GNUNET_CRYPTO_EddsaPublicKey 
*place_pub_key,
                            const struct GNUNET_PeerIdentity *origin,
                            uint32_t relay_count,
                            const struct GNUNET_PeerIdentity *relays,
@@ -729,9 +879,10 @@
  * @return NULL on errors, otherwise handle for the guest.
  */
 struct GNUNET_SOCIAL_Guest *
-GNUNET_SOCIAL_guest_enter_by_name (const struct GNUNET_CONFIGURATION_Handle 
*cfg,
-                                   const struct GNUNET_IDENTITY_Ego *ego,
-                                   const char *gns_name, const char *password,
+GNUNET_SOCIAL_guest_enter_by_name (const struct GNUNET_SOCIAL_App *app,
+                                   const struct GNUNET_SOCIAL_Ego *ego,
+                                   const char *gns_name,
+                                   const char *password,
                                    const struct GNUNET_PSYC_Message *join_msg,
                                    struct GNUNET_SOCIAL_Slicer *slicer,
                                    GNUNET_SOCIAL_GuestEnterCallback 
local_enter_cb,
@@ -740,6 +891,28 @@
 
 
 /**
+ * Reconnect to an already entered place as guest.
+ *
+ * @param gconn
+ *        Guest connection handle.
+ *        @see GNUNET_SOCIAL_app_connect() & 
GNUNET_SOCIAL_AppGuestPlaceCallback()
+ * @param slicer
+ *        Slicer to use for processing incoming requests from guests.
+ * @param local_enter_cb
+ *        Called upon connection established to the social service.
+ * @param entry_decision_cb
+ *        Called upon receiving entry decision.
+ *
+ * @return NULL on errors, otherwise handle for the guest.
+ */
+struct GNUNET_SOCIAL_Guest *
+GNUNET_SOCIAL_guest_enter_reconnect (struct GNUNET_SOCIAL_GuestConnection 
*gconn,
+                                     struct GNUNET_SOCIAL_Slicer *slicer,
+                                     GNUNET_SOCIAL_GuestEnterCallback 
local_enter_cb,
+                                     void *cls);
+
+
+/**
  * Flags for talking to the host of a place.
  */
 enum GNUNET_SOCIAL_TalkFlags
@@ -803,6 +976,24 @@
 
 
 /**
+ * Disconnect from a place.
+ *
+ * Invalidates guest handle.
+ *
+ * @param gst
+ *        The guest to disconnect.
+ * @param disconnect_cb
+ *        Function called after disconnected from the service.
+ * @param cls
+ *        Closure for @a disconnect_cb.
+ */
+void
+GNUNET_SOCIAL_guest_disconnect (struct GNUNET_SOCIAL_Guest *gst,
+                                GNUNET_ContinuationCallback disconnect_cb,
+                                void *cls);
+
+
+/**
  * Leave a place temporarily or permanently.
  *
  * Notifies the owner of the place about leaving, and destroys the place 
handle.
@@ -809,20 +1000,16 @@
  *
  * @param place
  *        Place to leave.
- * @param keep_active
- *        Keep place active after last application disconnected.
- *        #GNUNET_YES or #GNUNET_NO
  * @param env
  *        Optional environment for the leave message if @a keep_active
  *        is #GNUNET_NO.  NULL if not needed.
- * @param leave_cb
+ * @param disconnect_cb
  *        Called upon disconnecting from the social service.
  */
 void
 GNUNET_SOCIAL_guest_leave (struct GNUNET_SOCIAL_Guest *gst,
-                           int keep_active,
                            struct GNUNET_ENV_Environment *env,
-                           GNUNET_ContinuationCallback leave_cb,
+                           GNUNET_ContinuationCallback disconnect_cb,
                            void *leave_cls);
 
 
@@ -974,16 +1161,23 @@
 
 
 /**
- * Add public key to the GNS zone of the @e ego.
+ * Advertise a @e place in the GNS zone of @a ego.
  *
- * @param cfg
- *        Configuration.
+ * @param app
+ *        Application handle.
  * @param ego
  *        Ego.
+ * @param place_pub_key
+ *        Public key of place to add.
  * @param name
- *        The name for the PKEY record to put in the zone.
- * @param nym_pub_key
- *        Public key of nym to add.
+ *        The name for the PLACE record to put in the zone.
+ * @param password
+ *        Password used to encrypt the record or NULL to keep it cleartext.
+ * @param relay_count
+ *        Number of elements in the @a relays array.
+ * @param relays
+ *        List of relays to put in the PLACE record to advertise
+ *        as entry points to the place in addition to the origin.
  * @param expiration_time
  *        Expiration time of the record, use 0 to remove the record.
  * @param result_cb
@@ -990,82 +1184,55 @@
  *        Function called with the result of the operation.
  * @param result_cls
  *        Closure for @a result_cb
+ *
+ * @return #GNUNET_OK if the request was sent,
+ *         #GNUNET_SYSERR on error, e.g. the name/password is too long.
  */
-void
-GNUNET_SOCIAL_zone_add_pkey (const struct GNUNET_CONFIGURATION_Handle *cfg,
-                             const struct GNUNET_IDENTITY_Ego *ego,
-                             const char *name,
-                             const struct GNUNET_CRYPTO_EcdsaPublicKey 
*nym_pub_key,
-                             struct GNUNET_TIME_Absolute expiration_time,
-                             GNUNET_NAMESTORE_ContinuationWithStatus result_cb,
-                             void *result_cls);
+int
+GNUNET_SOCIAL_zone_add_place (const struct GNUNET_SOCIAL_App *app,
+                              const struct GNUNET_SOCIAL_Ego *ego,
+                              const char *name,
+                              const char *password,
+                              const struct GNUNET_CRYPTO_EddsaPublicKey 
*place_pub_key,
+                              const struct GNUNET_PeerIdentity *origin,
+                              uint32_t relay_count,
+                              const struct GNUNET_PeerIdentity *relays,
+                              struct GNUNET_TIME_Absolute expiration_time,
+                              GNUNET_ResultCallback result_cb,
+                              void *result_cls);
 
 
 /**
- * Handle for place notifications.
- */
-struct GNUNET_SOCIAL_PlaceListenHandle;
-
-
-/**
- * Notification about a place entered as host.
- */
-typedef void
-(*GNUNET_SOCIAL_PlaceNotifyHostCallback) (void *cls,
-                                          const struct 
GNUNET_CRYPTO_EddsaPrivateKey *place_key,
-                                          enum GNUNET_PSYC_Policy policy);
-
-
-/**
- * Notification about a place entered as guest.
- */
-typedef void
-(*GNUNET_SOCIAL_PlaceNotifyGuestCallback) (void *cls,
-                                           const struct 
GNUNET_CRYPTO_EddsaPublicKey *place_key,
-                                           const struct GNUNET_PeerIdentity 
*origin,
-                                           uint32_t relay_count,
-                                           const struct GNUNET_PeerIdentity 
*relays,
-                                           const struct GNUNET_PSYC_Message 
*entry_msg);
-
-
-/**
- * Start listening for entered places as host or guest.
+ * Add public key to the GNS zone of the @e ego.
  *
- * The @notify_host and @notify_guest functions are
- * initially called with the full list of entered places,
- * then later each time a new place is entered.
- *
  * @param cfg
  *        Configuration.
  * @param ego
- *        Listen for places of this ego.
- * @param notify_host
- *        Function to notify about a place entered as host.
- * @param notify_guest
- *        Function to notify about a place entered as guest..
- * @param notify_cls
- *        Closure for the callbacks.
+ *        Ego.
+ * @param name
+ *        The name for the PKEY record to put in the zone.
+ * @param nym_pub_key
+ *        Public key of nym to add.
+ * @param expiration_time
+ *        Expiration time of the record, use 0 to remove the record.
+ * @param result_cb
+ *        Function called with the result of the operation.
+ * @param result_cls
+ *        Closure for @a result_cb
  *
- * @return Handle that can be used to stop listening.
+ * @return #GNUNET_OK if the request was sent,
+ *         #GNUNET_SYSERR on error, e.g. the name is too long.
  */
-struct GNUNET_SOCIAL_PlaceListenHandle *
-GNUNET_SOCIAL_place_listen_start (const struct GNUNET_CONFIGURATION_Handle 
*cfg,
-                                  const struct GNUNET_IDENTITY_Ego *ego,
-                                  GNUNET_SOCIAL_PlaceNotifyHostCallback 
notify_host,
-                                  GNUNET_SOCIAL_PlaceNotifyGuestCallback 
notify_guest,
-                                  void *notify_cls);
+int
+GNUNET_SOCIAL_zone_add_nym (const struct GNUNET_SOCIAL_App *app,
+                            const struct GNUNET_SOCIAL_Ego *ego,
+                            const char *name,
+                            const struct GNUNET_CRYPTO_EcdsaPublicKey 
*nym_pub_key,
+                            struct GNUNET_TIME_Absolute expiration_time,
+                            GNUNET_ResultCallback result_cb,
+                            void *result_cls);
 
 
-/**
- * Stop listening for entered places.
- *
- * @param h
- *        Listen handle.
- */
-void
-GNUNET_SOCIAL_place_listen_stop (struct GNUNET_SOCIAL_PlaceListenHandle *h);
-
-
 #if 0                           /* keep Emacsens' auto-indent happy */
 {
 #endif

Modified: gnunet/src/social/Makefile.am
===================================================================
--- gnunet/src/social/Makefile.am       2015-12-16 17:43:13 UTC (rev 36766)
+++ gnunet/src/social/Makefile.am       2015-12-17 14:12:44 UTC (rev 36767)
@@ -25,11 +25,6 @@
 libgnunetsocial_la_LIBADD = \
   $(top_builddir)/src/util/libgnunetutil.la \
   $(top_builddir)/src/env/libgnunetenv.la \
-  $(top_builddir)/src/psycstore/libgnunetpsycutil.la \
-  $(top_builddir)/src/core/libgnunetcore.la \
-  $(top_builddir)/src/identity/libgnunetidentity.la \
-  $(top_builddir)/src/gns/libgnunetgns.la \
-  $(top_builddir)/src/namestore/libgnunetnamestore.la \
   $(GN_LIBINTL) $(XLIB)
 libgnunetsocial_la_LDFLAGS = \
   $(GN_LIB_LDFLAGS)  $(WINFLAGS) \
@@ -47,6 +42,10 @@
   $(top_builddir)/src/statistics/libgnunetstatistics.la \
   $(top_builddir)/src/psyc/libgnunetpsyc.la \
   $(top_builddir)/src/psycstore/libgnunetpsycutil.la \
+  $(top_builddir)/src/core/libgnunetcore.la \
+  $(top_builddir)/src/identity/libgnunetidentity.la \
+  $(top_builddir)/src/gns/libgnunetgns.la \
+  $(top_builddir)/src/namestore/libgnunetnamestore.la \
   $(GN_LIBINTL)
 
 

Modified: gnunet/src/social/gnunet-service-social.c
===================================================================
--- gnunet/src/social/gnunet-service-social.c   2015-12-16 17:43:13 UTC (rev 
36766)
+++ gnunet/src/social/gnunet-service-social.c   2015-12-17 14:12:44 UTC (rev 
36767)
@@ -25,11 +25,16 @@
  */
 
 #include <inttypes.h>
+#include <strings.h>
 
 #include "platform.h"
 #include "gnunet_util_lib.h"
 #include "gnunet_constants.h"
 #include "gnunet_protocols.h"
+#include "gnunet_core_service.h"
+#include "gnunet_identity_service.h"
+#include "gnunet_namestore_service.h"
+#include "gnunet_gns_service.h"
 #include "gnunet_statistics_service.h"
 #include "gnunet_psyc_service.h"
 #include "gnunet_psyc_util_lib.h"
@@ -42,10 +47,17 @@
  */
 static const struct GNUNET_CONFIGURATION_Handle *cfg;
 
+/* Handles to other services */
+static struct GNUNET_CORE_Handle *core;
+static struct GNUNET_IDENTITY_Handle *id;
+static struct GNUNET_GNS_Handle *gns;
+static struct GNUNET_NAMESTORE_Handle *namestore;
+static struct GNUNET_STATISTICS_Handle *stats;
+
 /**
- * Handle to the statistics service.
+ * ID of this peer.
  */
-static struct GNUNET_STATISTICS_Handle *stats;
+static struct GNUNET_PeerIdentity this_peer;
 
 /**
  * Notification context, simplifies client broadcasts.
@@ -66,7 +78,7 @@
 
 /**
  * Connected guests per place.
- * H(place_pub_key) -> Guest's pub_key -> struct Guest
+ * H(place_pub_key) -> ego_pub_key -> struct Guest
  */
 static struct GNUNET_CONTAINER_MultiHashMap *place_guests;
 
@@ -74,20 +86,45 @@
  * Places entered as host or guest.
  * H(place_pub_key) -> struct HostEnterRequest OR struct GuestEnterRequest
  */
-static struct GNUNET_CONTAINER_MultiHashMap *places_entered;
+static struct GNUNET_CONTAINER_MultiHashMap *places;
 
 /**
- * Place listener clients.
- * H(ego_pub_key) -> struct PlaceListener
+ * Places entered per application.
+ * H(app_id) -> H(place_pub_key) -> NULL
  */
-static struct GNUNET_CONTAINER_MultiHashMap *place_listeners;
+static struct GNUNET_CONTAINER_MultiHashMap *apps_places;
 
 /**
- * Directory for storing places.
+ * Connected applications.
+ * H(app_id) -> struct Application
  */
+static struct GNUNET_CONTAINER_MultiHashMap *apps;
+
+/**
+ * All egos.
+ * H(ego_pub_key) -> struct Ego
+ */
+static struct GNUNET_CONTAINER_MultiHashMap *egos;
+
+/**
+ * Directory for storing social data.
+ * Default: ~/.local/share/gnunet/social
+ */
+static char *dir_social;
+
+/**
+ * Directory for storing place data.
+ * $dir_social/places
+ */
 static char *dir_places;
 
+/**
+ * Directory for storing app data.
+ * $dir_social/apps
+ */
+static char *dir_apps;
 
+
 /**
  * Message fragment transmission queue.
  */
@@ -157,8 +194,13 @@
   struct GNUNET_PSYC_Channel *channel;
 
   /**
-   * Public key of the channel.
+   * Private key of home in case of a host.
    */
+  struct GNUNET_CRYPTO_EddsaPublicKey key;
+
+  /**
+   * Public key of place.
+   */
   struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
 
   /**
@@ -167,6 +209,21 @@
   struct GNUNET_HashCode pub_key_hash;
 
   /**
+   * Private key of ego.
+   */
+  struct GNUNET_CRYPTO_EcdsaPrivateKey ego_key;
+
+  /**
+   * Public key of ego.
+   */
+  struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
+
+  /**
+   * Hash of @a ego_pub_key.
+   */
+  struct GNUNET_HashCode ego_pub_hash;
+
+  /**
    * Last message ID received for the place.
    * 0 if there is no such message.
    */
@@ -202,11 +259,6 @@
   struct Place plc;
 
   /**
-   * Private key of the channel.
-   */
-  struct GNUNET_CRYPTO_EddsaPrivateKey priv_key;
-
-  /**
    * Handle for the multicast origin.
    */
   struct GNUNET_PSYC_Master *master;
@@ -240,21 +292,6 @@
   struct Place plc;
 
   /**
-   * Private key of the slave.
-   */
-  struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key;
-
-  /**
-   * Public key of the slave.
-   */
-  struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
-
-  /**
-   * Hash of @a pub_key.
-   */
-  struct GNUNET_HashCode pub_key_hash;
-
-  /**
    * Handle for the PSYC slave.
    */
   struct GNUNET_PSYC_Slave *slave;
@@ -293,7 +330,7 @@
 
 
 /**
- * Context for host/guest client.
+ * Context for a client.
  */
 struct Client
 {
@@ -309,13 +346,13 @@
   struct MessageTransmitQueue *tmit_msg;
 
   /**
-   * Ego key for listener clients;
+   * ID for application clients.
    */
-  struct GNUNET_CRYPTO_EcdsaPrivateKey ego_key;
+  char *app_id;
 };
 
 
-struct PlaceListener
+struct Application
 {
   struct ClientListItem *clients_head;
   struct ClientListItem *clients_tail;
@@ -322,6 +359,12 @@
 };
 
 
+struct Ego {
+  struct GNUNET_CRYPTO_EcdsaPrivateKey key;
+  char *name;
+};
+
+
 struct OperationClosure
 {
   struct GNUNET_SERVER_Client *client;
@@ -335,6 +378,18 @@
 psyc_transmit_message (struct Place *plc);
 
 
+static void
+cleanup_place (struct Place *plc);
+
+
+int
+place_entry_cleanup (void *cls, const struct GNUNET_HashCode *key, void *value)
+{
+  cleanup_place (value);
+  return GNUNET_YES;
+}
+
+
 /**
  * Task run during shutdown.
  *
@@ -344,11 +399,34 @@
 static void
 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
+  GNUNET_CONTAINER_multihashmap_iterate (hosts, place_entry_cleanup, NULL);
+  GNUNET_CONTAINER_multihashmap_iterate (guests, place_entry_cleanup, NULL);
+
   if (NULL != nc)
   {
     GNUNET_SERVER_notification_context_destroy (nc);
     nc = NULL;
   }
+  if (NULL != core)
+  {
+    GNUNET_CORE_disconnect (core);
+    core = NULL;
+  }
+  if (NULL != id)
+  {
+    GNUNET_IDENTITY_disconnect (id);
+    id = NULL;
+  }
+  if (NULL != namestore)
+  {
+    GNUNET_NAMESTORE_disconnect (namestore);
+    namestore = NULL;
+  }
+  if (NULL != gns)
+  {
+    GNUNET_GNS_disconnect (gns);
+    gns = NULL;
+  }
   if (NULL != stats)
   {
     GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
@@ -383,7 +461,7 @@
     plc_gst = GNUNET_CONTAINER_multihashmap_get (place_guests,
                                                 &plc->pub_key_hash);
   GNUNET_assert (NULL != plc_gst); // FIXME
-  GNUNET_CONTAINER_multihashmap_remove (plc_gst, &gst->pub_key_hash, gst);
+  GNUNET_CONTAINER_multihashmap_remove (plc_gst, &plc->ego_pub_hash, gst);
 
   if (0 == GNUNET_CONTAINER_multihashmap_size (plc_gst))
   {
@@ -444,15 +522,20 @@
     ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
   if (NULL == ctx)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "%p User context is NULL in client_disconnect()\n", ctx);
-    GNUNET_break (0);
     return;
   }
 
   struct Place *plc = ctx->plc;
+
+  if (NULL != ctx->app_id)
+    GNUNET_free (ctx->app_id);
+
+  GNUNET_free (ctx);
+
   if (NULL == plc)
-    return; // place listener client, nothing to do
+    return; // application client, nothing to do
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "%p Client (%s) disconnected from place %s\n",
@@ -470,40 +553,35 @@
     }
     cli = cli->next;
   }
+}
 
-  if (NULL == plc->clients_head)
-  { /* Last client disconnected. */
-    if (GNUNET_YES != plc->is_disconnected)
-    {
-      plc->is_disconnected = GNUNET_YES;
-      if (NULL != plc->tmit_msgs_head)
-      { /* Send pending messages to PSYC before cleanup. */
-        psyc_transmit_message (plc);
-      }
-      else
-      {
-        cleanup_place (plc);
-      }
-    }
-  }
+
+/**
+ * Send message to a client.
+ */
+static inline void
+client_send_msg (struct GNUNET_SERVER_Client *client,
+                 const struct GNUNET_MessageHeader *msg)
+{
+  GNUNET_SERVER_notification_context_add (nc, client);
+  GNUNET_SERVER_notification_context_unicast (nc, client, msg, GNUNET_NO);
 }
 
 
 /**
- * Send message to all clients connected to the channel.
+ * Send message to all clients connected to a place.
  */
 static void
-client_send_msg (const struct Place *plc,
+place_send_msg (const struct Place *plc,
                  const struct GNUNET_MessageHeader *msg)
 {
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "%p Sending message to clients.\n", plc);
+              "%p Sending message to clients of place.\n", plc);
 
   struct ClientListItem *cli = plc->clients_head;
   while (NULL != cli)
   {
-    GNUNET_SERVER_notification_context_add (nc, cli->client);
-    GNUNET_SERVER_notification_context_unicast (nc, cli->client, msg, 
GNUNET_NO);
+    client_send_msg (cli->client, msg);
     cli = cli->next;
   }
 }
@@ -542,13 +620,31 @@
               "%" PRId64 " (size: %u)\n",
              client, GNUNET_ntohll (op_id), result_code, data_size);
 
-  GNUNET_SERVER_notification_context_add (nc, client);
-  GNUNET_SERVER_notification_context_unicast (nc, client, &res->header,
-                                              GNUNET_NO);
+  client_send_msg (client, &res->header);
   GNUNET_free (res);
 }
 
 
+static void
+client_send_host_enter_ack (struct GNUNET_SERVER_Client *client,
+                            struct Host *hst, uint32_t result)
+{
+  struct Place *plc = &hst->plc;
+
+  struct HostEnterAck hack;
+  hack.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK);
+  hack.header.size = htons (sizeof (hack));
+  hack.result_code = htonl (result);
+  hack.max_message_id = GNUNET_htonll (plc->max_message_id);
+  hack.place_pub_key = plc->pub_key;
+
+  if (NULL != client)
+    client_send_msg (client, &hack.header);
+  else
+    place_send_msg (plc, &hack.header);
+}
+
+
 /**
  * Called after a PSYC master is started.
  */
@@ -560,13 +656,7 @@
   plc->max_message_id = max_message_id;
   plc->is_ready = GNUNET_YES;
 
-  struct GNUNET_PSYC_CountersResultMessage res;
-  res.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK);
-  res.header.size = htons (sizeof (res));
-  res.result_code = htonl (result);
-  res.max_message_id = GNUNET_htonll (plc->max_message_id);
-
-  client_send_msg (plc, &res.header);
+  client_send_host_enter_ack (NULL, hst, result);
 }
 
 
@@ -585,7 +675,7 @@
   GNUNET_CRYPTO_hash (slave_key, sizeof (*slave_key), &slave_key_hash);
   GNUNET_CONTAINER_multihashmap_put (hst->join_reqs, &slave_key_hash, jh,
                                      
GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
-  client_send_msg (&hst->plc, &req->header);
+  place_send_msg (&hst->plc, &req->header);
 }
 
 
@@ -606,7 +696,7 @@
   res.result_code = htonl (result);
   res.max_message_id = GNUNET_htonll (plc->max_message_id);
 
-  client_send_msg (plc, &res.header);
+  place_send_msg (plc, &res.header);
 }
 
 
@@ -620,7 +710,7 @@
                      const struct GNUNET_PSYC_Message *join_msg)
 {
   struct Guest *gst = cls;
-  client_send_msg (&gst->plc, &dcsn->header);
+  place_send_msg (&gst->plc, &dcsn->header);
 }
 
 
@@ -641,7 +731,7 @@
               plc, ntohs (msg->header.size), str);
   GNUNET_free (str);
 
-  client_send_msg (plc, &msg->header);
+  place_send_msg (plc, &msg->header);
 
   /* FIXME: further processing */
 }
@@ -656,55 +746,106 @@
 
 }
 
+/**
+ * Add a place to the @e places hash map.
+ *
+ * @param ereq
+ *        Entry request.
+ *
+ * @return #GNUNET_OK if the place was added
+ *         #GNUNET_NO if the place already exists in the hash map
+ *         #GNUNET_SYSERR on error
+ */
+static int
+place_add (const struct PlaceEnterRequest *ereq)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Adding place to hashmap:\n");
 
+  struct EgoPlacePublicKey ego_place_pub_key = {
+    .ego_pub_key = ereq->ego_pub_key,
+    .place_pub_key = ereq->place_pub_key,
+  };
+  struct GNUNET_HashCode ego_place_pub_hash;
+  GNUNET_CRYPTO_hash (&ego_place_pub_key, sizeof (ego_place_pub_key), 
&ego_place_pub_hash);
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "  ego_place_pub_hash = %s\n", GNUNET_h2s (&ego_place_pub_hash));
+
+  struct GNUNET_MessageHeader *
+    place_msg = GNUNET_CONTAINER_multihashmap_get (places, 
&ego_place_pub_hash);
+  if (NULL != place_msg)
+    return GNUNET_NO;
+
+  place_msg = GNUNET_copy_message (&ereq->header);
+  if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (places, 
&ego_place_pub_hash, place_msg,
+                                                      
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
+  {
+    GNUNET_break (0);
+    GNUNET_free (place_msg);
+    return GNUNET_SYSERR;
+  }
+
+  return GNUNET_OK;
+}
+
 /**
- * Add place to places_entered hash map.
+ * Add a place to the @e app_places hash map.
  *
- * @param ego_pub_hash
- *        H(ego_pub_key)
- * @param place_pub_hash
- *        H(place_pub_key)
+ * @param app_id
+ *        Application ID.
  * @param msg
  *        Entry message.
  *
- * @return Return value of GNUNET_CONTAINER_multihashmap_put ()
+ * @return #GNUNET_OK if the place was added
+ *         #GNUNET_NO if the place already exists in the hash map
+ *         #GNUNET_SYSERR on error
  */
 static int
-place_add (const struct GNUNET_HashCode *ego_pub_hash,
-           const struct GNUNET_HashCode *place_pub_hash,
-           const struct GNUNET_MessageHeader *msg)
+app_place_add (const char *app_id,
+               const struct PlaceEnterRequest *ereq)
 {
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Adding place to hashmap:\n");
+              "Adding app place to hashmap:\n");
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "  ego_pub_hash = %s\n", GNUNET_h2s (ego_pub_hash));
+              "  app_id = %s\n", app_id);
+
+  struct GNUNET_HashCode app_id_hash;
+  GNUNET_CRYPTO_hash (app_id, strlen (app_id) + 1, &app_id_hash);
+
+  struct EgoPlacePublicKey ego_place_pub_key = {
+    .ego_pub_key = ereq->ego_pub_key,
+    .place_pub_key = ereq->place_pub_key,
+  };
+  struct GNUNET_HashCode ego_place_pub_hash;
+  GNUNET_CRYPTO_hash (&ego_place_pub_key, sizeof (ego_place_pub_key), 
&ego_place_pub_hash);
+
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "  place_pub_hash = %s\n", GNUNET_h2s (place_pub_hash));
+              "  ego_place_pub_hash = %s\n", GNUNET_h2s (&ego_place_pub_hash));
 
   struct GNUNET_CONTAINER_MultiHashMap *
-    ego_places = GNUNET_CONTAINER_multihashmap_get (places_entered, 
ego_pub_hash);
-  if (NULL == ego_places)
+    app_places = GNUNET_CONTAINER_multihashmap_get (apps_places, &app_id_hash);
+  if (NULL == app_places)
   {
-    ego_places = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
-    GNUNET_CONTAINER_multihashmap_put (places_entered, ego_pub_hash, 
ego_places,
+    app_places = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
+    GNUNET_CONTAINER_multihashmap_put (apps_places, &app_id_hash, app_places,
                                        
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
   }
 
-  struct GNUNET_MessageHeader *msg_old, *msg_new;
-  if (NULL != (msg_old = GNUNET_CONTAINER_multihashmap_get (ego_places, 
place_pub_hash)))
+  if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (app_places, 
&ego_place_pub_hash))
+    return GNUNET_NO;
+
+  if (GNUNET_SYSERR == place_add (ereq))
+    return GNUNET_SYSERR;
+
+  if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (app_places, 
&ego_place_pub_hash,
+                                                      NULL, 0))
   {
-    GNUNET_free (msg_old);
-    GNUNET_CONTAINER_multihashmap_remove_all (ego_places, place_pub_hash);
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
   }
 
-  uint16_t msg_size = ntohs (msg->size);
-  msg_new = GNUNET_malloc (msg_size);
-  memcpy (msg_new, msg, msg_size);
-  int ret = GNUNET_CONTAINER_multihashmap_put (ego_places, place_pub_hash, 
msg_new,
-                                               
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
-  if (GNUNET_OK != ret)
-    GNUNET_break (0);
-  return ret;
+  return GNUNET_OK;
 }
 
 
@@ -711,55 +852,113 @@
 /**
  * Save place entry message to disk.
  *
- * @param ego_key
- *        Private key of ego.
- * @param place_pub_hash
- *        Hash of public key of place.
+ * @param app_id
+ *        Application ID.
  * @param msg
  *        Entry message.
  */
-static void
-place_save (const struct GNUNET_CRYPTO_EcdsaPrivateKey *ego_key,
-            const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub,
-            const struct GNUNET_MessageHeader *msg)
+static int
+app_place_save (const char *app_id,
+                const struct PlaceEnterRequest *ereq)
 {
+  app_place_add (app_id, ereq);
+
   if (NULL == dir_places)
-    return;
+    return GNUNET_SYSERR;
 
+  struct GNUNET_HashCode ego_pub_hash;
   struct GNUNET_HashCode place_pub_hash;
-  GNUNET_CRYPTO_hash (place_pub, sizeof (place_pub), &place_pub_hash);
+  GNUNET_CRYPTO_hash (&ereq->ego_pub_key, sizeof (ereq->ego_pub_key),
+                      &ego_pub_hash);
+  GNUNET_CRYPTO_hash (&ereq->place_pub_key, sizeof (ereq->place_pub_key),
+                      &place_pub_hash);
 
-  struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub;
-  struct GNUNET_HashCode ego_pub_hash;
-  GNUNET_CRYPTO_ecdsa_key_get_public (ego_key, &ego_pub);
-  GNUNET_CRYPTO_hash (&ego_pub, sizeof (ego_pub), &ego_pub_hash);
+  struct GNUNET_CRYPTO_HashAsciiEncoded ego_pub_hash_ascii;
+  struct GNUNET_CRYPTO_HashAsciiEncoded place_pub_hash_ascii;
+  memcpy (&ego_pub_hash_ascii.encoding,
+          GNUNET_h2s_full (&ego_pub_hash), sizeof (ego_pub_hash_ascii));
+  memcpy (&place_pub_hash_ascii.encoding,
+          GNUNET_h2s_full (&place_pub_hash), sizeof (place_pub_hash_ascii));
 
-  place_add (&ego_pub_hash, &place_pub_hash, msg);
+  char *filename = NULL;
+  GNUNET_asprintf (&filename, "%s%c" "%s%c" "%s%c" "%s",
+                   dir_social, DIR_SEPARATOR,
+                   "places", DIR_SEPARATOR,
+                   ego_pub_hash_ascii.encoding, DIR_SEPARATOR,
+                   place_pub_hash_ascii.encoding);
+  int ret = GNUNET_DISK_directory_create_for_file (filename);
+  if (GNUNET_OK != ret
+      || 0 > GNUNET_DISK_fn_write (filename, ereq, ntohs (ereq->header.size),
+                                   GNUNET_DISK_PERM_USER_READ
+                                   | GNUNET_DISK_PERM_USER_WRITE))
+  {
+    GNUNET_break (0);
+    ret = GNUNET_SYSERR;
+  }
+  GNUNET_free (filename);
 
-  char *ego_pub_hash_str = GNUNET_malloc (sizeof (struct 
GNUNET_CRYPTO_HashAsciiEncoded) + 1);
-  char *place_pub_hash_str = GNUNET_malloc (sizeof (struct 
GNUNET_CRYPTO_HashAsciiEncoded) + 1);
-  memcpy (ego_pub_hash_str, GNUNET_h2s_full (&ego_pub_hash), sizeof (struct 
GNUNET_CRYPTO_HashAsciiEncoded));
-  memcpy (place_pub_hash_str, GNUNET_h2s_full (&place_pub_hash), sizeof 
(struct GNUNET_CRYPTO_HashAsciiEncoded));
+  if (ret == GNUNET_OK)
+  {
+    GNUNET_asprintf (&filename, "%s%c" "%s%c" "%s%c" "%s%c" "%s",
+                     dir_social, DIR_SEPARATOR,
+                     "apps", DIR_SEPARATOR,
+                     app_id, DIR_SEPARATOR,
+                     ego_pub_hash_ascii.encoding, DIR_SEPARATOR,
+                     place_pub_hash_ascii.encoding);
+    ret = GNUNET_DISK_directory_create_for_file (filename);
+    if (GNUNET_OK != ret
+        || 0 > GNUNET_DISK_fn_write (filename, "", 0,
+                                     GNUNET_DISK_PERM_USER_READ
+                                     | GNUNET_DISK_PERM_USER_WRITE))
+    {
+      GNUNET_break (0);
+      ret = GNUNET_SYSERR;
+    }
+    GNUNET_free (filename);
+  }
+  return ret;
+}
 
-  char *filename = GNUNET_malloc (strlen (dir_places) + 1
-                                  + sizeof (struct 
GNUNET_CRYPTO_HashAsciiEncoded) + 1
-                                  + sizeof (struct 
GNUNET_CRYPTO_HashAsciiEncoded) + 1);
-  GNUNET_asprintf (&filename,
-                   "%s%s%s%s%s",
-                   dir_places, DIR_SEPARATOR_STR,
-                   ego_pub_hash_str, DIR_SEPARATOR_STR,
-                   place_pub_hash_str);
 
-  GNUNET_DISK_directory_create_for_file (filename);
-  if (GNUNET_DISK_fn_write (filename, msg, ntohs (msg->size),
-                            GNUNET_DISK_PERM_USER_READ | 
GNUNET_DISK_PERM_USER_WRITE) < 0)
+int
+app_place_remove (const char *app_id,
+                  const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key)
+{
+  struct GNUNET_HashCode place_pub_hash;
+  GNUNET_CRYPTO_hash (place_pub_key, sizeof (*place_pub_key), &place_pub_hash);
+
+  struct GNUNET_CRYPTO_HashAsciiEncoded place_pub_hash_ascii;
+  memcpy (&place_pub_hash_ascii.encoding,
+          GNUNET_h2s_full (&place_pub_hash), sizeof (place_pub_hash_ascii));
+
+  char *app_place_filename = NULL;
+  GNUNET_asprintf (&app_place_filename,
+                   "%s%c" "%s%/",
+                   dir_social, DIR_SEPARATOR,
+                   "apps", DIR_SEPARATOR,
+                   app_id, DIR_SEPARATOR,
+                   place_pub_hash_ascii.encoding);
+
+  struct GNUNET_HashCode app_id_hash;
+  GNUNET_CRYPTO_hash (app_id, strlen (app_id) + 1, &app_id_hash);
+
+  struct GNUNET_CONTAINER_MultiHashMap *
+    app_places = GNUNET_CONTAINER_multihashmap_get (apps_places, &app_id_hash);
+
+  if (NULL != app_places)
+    GNUNET_CONTAINER_multihashmap_remove (app_places, &place_pub_hash, NULL);
+
+  int ret = unlink (app_place_filename);
+  GNUNET_free (app_place_filename);
+  if (0 != ret)
   {
     GNUNET_break (0);
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Error removing app place: unlink returned %d\n", errno);
+    return GNUNET_SYSERR;
   }
 
-  GNUNET_free (ego_pub_hash_str);
-  GNUNET_free (place_pub_hash_str);
-  GNUNET_free (filename);
+  return GNUNET_OK;
 }
 
 
@@ -772,35 +971,34 @@
  *        Returned Host struct.
  *
  * @return #GNUNET_YES if the host entered the place just now,
- *         #GNUNET_NO  if the place is already entered.
+ *         #GNUNET_NO  if the place is already entered,
+ *         #GNUNET_SYSERR if place_pub_key was set
+ *                        but its private key was not found
  */
 static int
 host_enter (const struct HostEnterRequest *hreq, struct Host **ret_hst)
 {
   int ret = GNUNET_NO;
-  struct GNUNET_CRYPTO_EddsaPublicKey place_pub;
   struct GNUNET_HashCode place_pub_hash;
+  GNUNET_CRYPTO_hash (&hreq->place_pub_key, sizeof (hreq->place_pub_key),
+                      &place_pub_hash);
+  struct Host *hst = GNUNET_CONTAINER_multihashmap_get (hosts, 
&place_pub_hash);
 
-  GNUNET_CRYPTO_eddsa_key_get_public (&hreq->place_key, &place_pub);
-  GNUNET_CRYPTO_hash (&place_pub, sizeof (place_pub), &place_pub_hash);
-
-  struct Host *hst = GNUNET_CONTAINER_multihashmap_get (hosts, 
&place_pub_hash);
   if (NULL == hst)
   {
     hst = GNUNET_new (struct Host);
-    hst->policy = ntohl (hreq->policy);
-    hst->priv_key = hreq->place_key;
+    hst->policy = hreq->policy;
     hst->join_reqs = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
 
     struct Place *plc = &hst->plc;
+    place_init (plc);
     plc->is_host = GNUNET_YES;
-    plc->pub_key = place_pub;
+    plc->pub_key = hreq->place_pub_key;
     plc->pub_key_hash = place_pub_hash;
-    place_init (plc);
 
     GNUNET_CONTAINER_multihashmap_put (hosts, &plc->pub_key_hash, plc,
                                        
GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
-    hst->master = GNUNET_PSYC_master_start (cfg, &hst->priv_key, hst->policy,
+    hst->master = GNUNET_PSYC_master_start (cfg, &hreq->place_key, hst->policy,
                                             &psyc_master_started,
                                             &psyc_recv_join_request,
                                             &psyc_recv_message, NULL, hst);
@@ -821,11 +1019,42 @@
 client_recv_host_enter (void *cls, struct GNUNET_SERVER_Client *client,
                         const struct GNUNET_MessageHeader *msg)
 {
-  const struct HostEnterRequest *hreq
-    = (const struct HostEnterRequest *) msg;
-  struct Place *plc;
-  struct Host *hst;
+  struct HostEnterRequest *hreq
+    = (struct HostEnterRequest *) GNUNET_copy_message (msg);
 
+  uint8_t app_id_size = ntohs (hreq->header.size) - sizeof (*hreq);
+  const char *app_id = NULL;
+  uint16_t offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &hreq[1],
+                                                    app_id_size, 1, &app_id);
+  if (0 == offset || offset != app_id_size || app_id == NULL)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "offset = %u, app_id_size = %u, app_id = %s\n",
+                offset, app_id_size, app_id);
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
+
+  struct Host *hst = NULL;
+  struct Place *plc = NULL;
+  int ret = GNUNET_OK;
+
+  struct GNUNET_CRYPTO_EddsaPublicKey empty_pub_key;
+  memset (&empty_pub_key, 0, sizeof (empty_pub_key));
+
+  if (0 == memcmp (&hreq->place_pub_key, &empty_pub_key, sizeof 
(empty_pub_key)))
+  { // no public key set: create new private key & save the place
+    struct GNUNET_CRYPTO_EddsaPrivateKey *
+      place_key = GNUNET_CRYPTO_eddsa_key_create ();
+    hreq->place_key = *place_key;
+    GNUNET_CRYPTO_eddsa_key_get_public (place_key, &hreq->place_pub_key);
+    GNUNET_CRYPTO_eddsa_key_clear (place_key);
+    GNUNET_free (place_key);
+
+    app_place_save (app_id, (const struct PlaceEnterRequest *) hreq);
+  }
+
   switch (host_enter (hreq, &hst))
   {
   case GNUNET_YES:
@@ -835,40 +1064,32 @@
   case GNUNET_NO:
   {
     plc = &hst->plc;
-
-    struct GNUNET_PSYC_CountersResultMessage res;
-    res.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK);
-    res.header.size = htons (sizeof (res));
-    res.result_code = htonl (GNUNET_OK);
-    res.max_message_id = GNUNET_htonll (plc->max_message_id);
-
-    GNUNET_SERVER_notification_context_add (nc, client);
-    GNUNET_SERVER_notification_context_unicast (nc, client, &res.header,
-                                                GNUNET_NO);
+    client_send_host_enter_ack (client, hst, GNUNET_OK);
     break;
   }
   case GNUNET_SYSERR:
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-    return;
+    ret = GNUNET_SYSERR;
   }
 
-  struct GNUNET_CRYPTO_EddsaPublicKey place_pub;
-  GNUNET_CRYPTO_eddsa_key_get_public (&hreq->place_key, &place_pub);
+  if (ret != GNUNET_SYSERR)
+  {
 
-  place_save (&hreq->host_key, &place_pub, msg);
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "%p Client connected as host to place %s.\n",
+                hst, GNUNET_h2s (&plc->pub_key_hash));
 
-  GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-              "%p Client connected as host to place %s.\n",
-              hst, GNUNET_h2s (&plc->pub_key_hash));
+    struct ClientListItem *cli = GNUNET_new (struct ClientListItem);
+    cli->client = client;
+    GNUNET_CONTAINER_DLL_insert (plc->clients_head, plc->clients_tail, cli);
 
-  struct ClientListItem *cli = GNUNET_new (struct ClientListItem);
-  cli->client = client;
-  GNUNET_CONTAINER_DLL_insert (plc->clients_head, plc->clients_tail, cli);
+    struct Client *ctx = GNUNET_new (struct Client);
+    ctx->plc = plc;
+    GNUNET_SERVER_client_set_user_context (client, ctx);
+  }
 
-  struct Client *ctx = GNUNET_new (struct Client);
-  ctx->plc = plc;
-  GNUNET_SERVER_client_set_user_context (client, ctx);
-  GNUNET_SERVER_receive_done (client, GNUNET_OK);
+  GNUNET_CRYPTO_eddsa_key_clear (&hreq->place_key);
+  GNUNET_free (hreq);
+  GNUNET_SERVER_receive_done (client, ret);
 }
 
 
@@ -881,7 +1102,8 @@
  *        Returned Guest struct.
  *
  * @return #GNUNET_YES if the guest entered the place just now,
- *         #GNUNET_NO  if the place is already entered.
+ *         #GNUNET_NO  if the place is already entered,
+ *         #GNUNET_SYSERR on error.
  */
 static int
 guest_enter (const struct GuestEnterRequest *greq, struct Guest **ret_gst)
@@ -889,44 +1111,68 @@
   int ret = GNUNET_NO;
   uint16_t greq_size = ntohs (greq->header.size);
 
-  struct GNUNET_CRYPTO_EcdsaPublicKey gst_pub_key;
-  struct GNUNET_HashCode place_pub_hash, gst_pub_key_hash;
-  GNUNET_CRYPTO_ecdsa_key_get_public (&greq->guest_key, &gst_pub_key);
-  GNUNET_CRYPTO_hash (&gst_pub_key, sizeof (gst_pub_key), &gst_pub_key_hash);
-  GNUNET_CRYPTO_hash (&greq->place_key, sizeof (greq->place_key), 
&place_pub_hash);
+  struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key = greq->ego_pub_key;
+  struct GNUNET_HashCode ego_pub_hash;
+  GNUNET_CRYPTO_hash (&ego_pub_key, sizeof (ego_pub_key), &ego_pub_hash);
+  struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash);
 
+  if (NULL == ego)
+    return GNUNET_SYSERR;
+
+  struct GNUNET_HashCode place_pub_hash;
+  GNUNET_CRYPTO_hash (&greq->place_pub_key, sizeof (greq->place_pub_key),
+                      &place_pub_hash);
+
   struct GNUNET_CONTAINER_MultiHashMap *
     plc_gst = GNUNET_CONTAINER_multihashmap_get (place_guests, 
&place_pub_hash);
   struct Guest *gst = NULL;
-  struct Place *plc;
 
   if (NULL != plc_gst)
-    gst = GNUNET_CONTAINER_multihashmap_get (plc_gst, &gst_pub_key_hash);
+    gst = GNUNET_CONTAINER_multihashmap_get (plc_gst, &ego_pub_hash);
 
   if (NULL == gst || NULL == gst->slave)
   {
     gst = GNUNET_new (struct Guest);
-    gst->priv_key = greq->guest_key;
-    gst->pub_key = gst_pub_key;
-    gst->pub_key_hash = gst_pub_key_hash;
     gst->origin = greq->origin;
     gst->relay_count = ntohl (greq->relay_count);
 
+    uint16_t len;
+    uint16_t remaining = ntohs (greq->header.size) - sizeof (*greq);
+    const char *app_id = (const char *) &greq[1];
+    const char *p = app_id;
+
+    len = strnlen (app_id, remaining);
+    if (len == remaining)
+    {
+      GNUNET_break (0);
+      return GNUNET_SYSERR;
+    }
+    p += len + 1;
+    remaining -= len + 1;
+
     const struct GNUNET_PeerIdentity *relays = NULL;
     uint16_t relay_size = gst->relay_count * sizeof (*relays);
+    if (remaining < relay_size)
+    {
+      GNUNET_break (0);
+      return GNUNET_SYSERR;
+    }
     if (0 < relay_size)
-      relays = (const struct GNUNET_PeerIdentity *) &greq[1];
+      relays = (const struct GNUNET_PeerIdentity *) p;
+    p += relay_size;
+    remaining -= relay_size;
+
     struct GNUNET_PSYC_Message *join_msg = NULL;
     uint16_t join_msg_size = 0;
 
-    if (sizeof (*greq) + relay_size + sizeof (struct GNUNET_MessageHeader)
-        <= greq_size)
+    if (sizeof (struct GNUNET_MessageHeader) <= remaining)
     {
-      join_msg = (struct GNUNET_PSYC_Message *)
-        (((char *) &greq[1]) + relay_size);
+      join_msg = (struct GNUNET_PSYC_Message *) p;
       join_msg_size = ntohs (join_msg->header.size);
+      p += join_msg_size;
+      remaining -= join_msg_size;
     }
-    if (sizeof (*greq) + relay_size + join_msg_size != greq_size)
+    if (0 != remaining)
     {
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                   "%u + %u + %u != %u\n",
@@ -935,17 +1181,20 @@
       GNUNET_free (gst);
       return GNUNET_SYSERR;
     }
-    if (0 < gst->relay_count)
+    if (0 < relay_size)
     {
       gst->relays = GNUNET_malloc (relay_size);
-      memcpy (gst->relays, &greq[1], relay_size);
+      memcpy (gst->relays, relays, relay_size);
     }
 
-    plc = &gst->plc;
+    struct Place *plc = &gst->plc;
+    place_init (plc);
     plc->is_host = GNUNET_NO;
-    plc->pub_key = greq->place_key;
+    plc->pub_key = greq->place_pub_key;
     plc->pub_key_hash = place_pub_hash;
-    place_init (plc);
+    plc->ego_pub_key = ego_pub_key;
+    plc->ego_pub_hash = ego_pub_hash;
+    plc->ego_key = ego->key;
 
     if (NULL == plc_gst)
     {
@@ -953,12 +1202,12 @@
       (void) GNUNET_CONTAINER_multihashmap_put (place_guests, 
&plc->pub_key_hash, plc_gst,
                                                 
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
     }
-    (void) GNUNET_CONTAINER_multihashmap_put (plc_gst, &gst->pub_key_hash, gst,
+    (void) GNUNET_CONTAINER_multihashmap_put (plc_gst, &plc->ego_pub_hash, gst,
                                               
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
     (void) GNUNET_CONTAINER_multihashmap_put (guests, &plc->pub_key_hash, gst,
                                               
GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
     gst->slave
-      = GNUNET_PSYC_slave_join (cfg, &plc->pub_key, &gst->priv_key,
+      = GNUNET_PSYC_slave_join (cfg, &plc->pub_key, &plc->ego_key,
                                 &gst->origin, gst->relay_count, gst->relays,
                                 &psyc_recv_message, NULL, 
&psyc_slave_connected,
                                 &psyc_recv_join_dcsn, gst, join_msg);
@@ -981,6 +1230,18 @@
 {
   const struct GuestEnterRequest *
     greq = (const struct GuestEnterRequest *) msg;
+
+  uint16_t remaining = ntohs (greq->header.size) - sizeof (*greq);
+  const char *app_id = NULL;
+  uint16_t offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &greq[1],
+                                                    remaining, 1, &app_id);
+  if (0 == offset)
+  {
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
+
   struct Guest *gst = NULL;
   struct Place *plc = NULL;
 
@@ -988,6 +1249,7 @@
   {
   case GNUNET_YES:
     plc = &gst->plc;
+    app_place_save (app_id, (const struct PlaceEnterRequest *) greq);
     break;
 
   case GNUNET_NO:
@@ -1000,28 +1262,21 @@
     res.result_code = htonl (GNUNET_OK);
     res.max_message_id = GNUNET_htonll (plc->max_message_id);
 
-    GNUNET_SERVER_notification_context_add (nc, client);
-    GNUNET_SERVER_notification_context_unicast (nc, client, &res.header,
-                                                GNUNET_NO);
+    client_send_msg (client, &res.header);
     if (NULL != gst->join_dcsn)
-    {
-      GNUNET_SERVER_notification_context_add (nc, client);
-      GNUNET_SERVER_notification_context_unicast (nc, client,
-                                                  &gst->join_dcsn->header,
-                                                  GNUNET_NO);
-    }
+      client_send_msg (client, &gst->join_dcsn->header);
+
     break;
   }
   case GNUNET_SYSERR:
+    GNUNET_break (0);
     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
     return;
   }
 
-  place_save (&greq->guest_key, &greq->place_key, msg);
-
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "%p Client connected as guest to place %s.\n",
-              gst, GNUNET_h2s (&gst->plc.pub_key_hash));
+              gst, GNUNET_h2s (&plc->pub_key_hash));
 
   struct ClientListItem *cli = GNUNET_new (struct ClientListItem);
   cli->client = client;
@@ -1034,16 +1289,159 @@
 }
 
 
+struct GuestEnterByNameClosure
+{
+  struct GNUNET_SERVER_Client *client;
+  char *app_id;
+  char *password;
+  struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
+  struct GNUNET_MessageHeader *join_msg;
+};
+
+
+/**
+ * Result of a GNS name lookup for entering a place.
+ *
+ * @see GNUNET_SOCIAL_guest_enter_by_name
+ */
+static void
+gns_result_guest_enter (void *cls, uint32_t rd_count,
+                        const struct GNUNET_GNSRECORD_Data *rd)
+{
+  struct GuestEnterByNameClosure *gcls = cls;
+  GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+              "%p GNS result: %u records.\n", gcls->client, rd_count);
+
+  const struct GNUNET_GNSRECORD_PlaceData *
+    rec = (const struct GNUNET_GNSRECORD_PlaceData *) rd->data;
+
+  if (0 == rd_count || rd->data_size < sizeof (*rec))
+  {
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (gcls->client, GNUNET_SYSERR);
+    return;
+  }
+
+  uint16_t relay_count = ntohl (rec->relay_count);
+  struct GNUNET_PeerIdentity *relays = NULL;
+
+  if (0 < relay_count)
+  {
+    if (rd->data_size == sizeof (*rec) + relay_count * sizeof (struct 
GNUNET_PeerIdentity))
+    {
+      relays = (struct GNUNET_PeerIdentity *) &rec[1];
+    }
+    else
+    {
+      relay_count = 0;
+      GNUNET_break_op (0);
+    }
+  }
+
+  uint16_t app_id_size = strlen (gcls->app_id) + 1;
+  uint16_t relay_size = relay_count * sizeof (*relays);
+  uint16_t join_msg_size = 0;
+  if (NULL != gcls->join_msg)
+    join_msg_size = ntohs (gcls->join_msg->size);
+  uint16_t greq_size = sizeof (struct GuestEnterRequest)
+    + app_id_size + relay_size + join_msg_size;
+  struct GuestEnterRequest *greq = GNUNET_malloc (greq_size);
+  greq->header.size = htons (greq_size);
+  greq->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER);
+  greq->ego_pub_key = gcls->ego_pub_key;
+  greq->place_pub_key = rec->place_pub_key;
+  greq->origin = rec->origin;
+  greq->relay_count = rec->relay_count;
+
+  void *p = &greq[1];
+  memcpy (p, gcls->app_id, app_id_size);
+  p += app_id_size;
+  memcpy (p, relays, relay_size);
+  p += relay_size;
+  memcpy (p, gcls->join_msg, join_msg_size);
+
+  client_recv_guest_enter (NULL, gcls->client, &greq->header);
+
+  GNUNET_free (gcls->app_id);
+  if (NULL != gcls->password)
+    GNUNET_free (gcls->password);
+  if (NULL != gcls->join_msg)
+    GNUNET_free (gcls->join_msg);
+  GNUNET_free (gcls);
+  GNUNET_free (greq);
+}
+
+
+/**
+ * Handle a connecting client entering a place as guest using a GNS address.
+ *
+ * Look up GNS address and generate a GuestEnterRequest from that.
+ */
+static void
+client_recv_guest_enter_by_name (void *cls, struct GNUNET_SERVER_Client 
*client,
+                                 const struct GNUNET_MessageHeader *msg)
+{
+  const struct GuestEnterByNameRequest *
+    greq = (const struct GuestEnterByNameRequest *) msg;
+
+  struct GuestEnterByNameClosure *gcls = GNUNET_malloc (sizeof (*gcls));
+  gcls->client = client;
+  gcls->ego_pub_key = greq->ego_pub_key;
+
+  const char *p = (const char *) &greq[1];
+  const char *app_id = NULL, *password = NULL, *gns_name = NULL;
+  uint16_t remaining = ntohs (greq->header.size) - sizeof (*greq);
+  uint16_t offset = GNUNET_STRINGS_buffer_tokenize (p, remaining, 3,
+                                                    &app_id,
+                                                    &gns_name,
+                                                    &password);
+  p += offset;
+  remaining -= offset;
+
+  if (0 != offset && sizeof (*gcls->join_msg) <= remaining)
+  {
+    gcls->join_msg = GNUNET_copy_message ((struct GNUNET_MessageHeader *) p);
+    remaining -= ntohs (gcls->join_msg->size);
+  }
+
+  if (0 == offset || 0 != remaining)
+  {
+    if (NULL != gcls->join_msg)
+      GNUNET_free (gcls->join_msg);
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
+
+  uint16_t app_id_size = strlen (app_id) + 1;
+  gcls->app_id = GNUNET_malloc (app_id_size);
+  memcpy (gcls->app_id, app_id, app_id_size);
+
+  uint16_t password_size = strlen (password);
+  if (0 < password_size++)
+  {
+    gcls->password = GNUNET_malloc (password_size);
+    memcpy (gcls->password, password, password_size);
+  }
+
+  GNUNET_GNS_lookup (gns, gns_name, &greq->ego_pub_key,
+                     GNUNET_GNSRECORD_TYPE_PLACE, GNUNET_GNS_LO_DEFAULT,
+                     NULL, gns_result_guest_enter, gcls);
+}
+
+
 void
-place_notify (struct GNUNET_MessageHeader *msg,
-              struct GNUNET_SERVER_Client *client)
+app_notify_place (struct GNUNET_MessageHeader *msg,
+                  struct GNUNET_SERVER_Client *client)
 {
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "%p Sending place notification of type %u to client.\n",
               client, ntohs (msg->type));
 
- uint16_t msg_size = ntohs (msg->size);
-  struct GNUNET_CRYPTO_EcdsaPublicKey place_pub;
+  uint16_t msg_size = ntohs (msg->size);
+  struct AppPlaceMessage amsg;
+  amsg.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE);
+  amsg.header.size = htons (sizeof (amsg));
 
   switch (ntohs (msg->type))
   {
@@ -1051,7 +1449,9 @@
     if (msg_size < sizeof (struct HostEnterRequest))
       return;
     struct HostEnterRequest *hreq = (struct HostEnterRequest *) msg;
-    GNUNET_CRYPTO_ecdsa_key_get_public (&hreq->host_key, &place_pub);
+    amsg.is_host = GNUNET_YES;
+    amsg.ego_pub_key = hreq->ego_pub_key;
+    amsg.place_pub_key = hreq->place_pub_key;
     break;
 
   case GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER:
@@ -1058,7 +1458,9 @@
     if (msg_size < sizeof (struct GuestEnterRequest))
       return;
     struct GuestEnterRequest *greq = (struct GuestEnterRequest *) msg;
-    GNUNET_CRYPTO_ecdsa_key_get_public (&greq->guest_key, &place_pub);
+    amsg.is_host = GNUNET_NO;
+    amsg.ego_pub_key = greq->ego_pub_key;
+    amsg.place_pub_key = greq->place_pub_key;
     break;
 
   default:
@@ -1065,63 +1467,163 @@
     return;
   }
 
-  GNUNET_SERVER_notification_context_add (nc, client);
-  GNUNET_SERVER_notification_context_unicast (nc, client, msg,
-                                              GNUNET_NO);
+  client_send_msg (client, &amsg.header);
 }
 
 
+void
+app_notify_ego (struct Ego *ego, struct GNUNET_SERVER_Client *client)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "%p Sending ego notification to client: %s\n",
+              client, ego->name);
+
+  size_t name_size = strlen (ego->name) + 1;
+  struct AppEgoMessage *emsg = GNUNET_malloc (sizeof (*emsg) + name_size);
+  emsg->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_APP_EGO);
+  emsg->header.size = htons (sizeof (*emsg) + name_size);
+
+  GNUNET_CRYPTO_ecdsa_key_get_public (&ego->key, &emsg->ego_pub_key);
+  memcpy (&emsg[1], ego->name, name_size);
+
+  client_send_msg (client, &emsg->header);
+  GNUNET_free (emsg);
+}
+
+
 int
-map_entry_place (void *cls, const struct GNUNET_HashCode *key, void *value)
+app_place_entry (void *cls, const struct GNUNET_HashCode *key, void *value)
 {
-  place_notify (value, cls);
+  struct GNUNET_MessageHeader *
+    msg = GNUNET_CONTAINER_multihashmap_get (places, key);
+  if (NULL != msg)
+    app_notify_place (msg, cls);
   return GNUNET_YES;
 }
 
 
+int
+ego_entry (void *cls, const struct GNUNET_HashCode *key, void *value)
+{
+  app_notify_ego (value, cls);
+  return GNUNET_YES;
+}
+
+
 /**
- * Handle a connecting client listening for entered places.
+ * Handle application connection.
  */
 static void
-client_recv_place_listen (void *cls, struct GNUNET_SERVER_Client *client,
-                          const struct GNUNET_MessageHeader *msg)
+client_recv_app_connect (void *cls, struct GNUNET_SERVER_Client *client,
+                         const struct GNUNET_MessageHeader *msg)
 {
-  const struct PlaceListenRequest *req
-    = (const struct PlaceListenRequest *) msg;
+  const struct AppConnectRequest *creq
+    = (const struct AppConnectRequest *) msg;
 
-  struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub;
-  struct GNUNET_HashCode ego_pub_hash;
+  uint8_t app_id_size = ntohs (creq->header.size) - sizeof (*creq);
+  const char *app_id = NULL;
+  uint16_t offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &creq[1],
+                                                    app_id_size, 1, &app_id);
+  if (0 == offset || offset != app_id_size)
+  {
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
 
-  GNUNET_CRYPTO_ecdsa_key_get_public (&req->ego_key, &ego_pub);
-  GNUNET_CRYPTO_hash (&ego_pub, sizeof (ego_pub), &ego_pub_hash);
+  struct GNUNET_HashCode app_id_hash;
+  GNUNET_CRYPTO_hash (app_id, app_id_size, &app_id_hash);
 
+  GNUNET_CONTAINER_multihashmap_iterate (egos, ego_entry, client);
+
   struct GNUNET_CONTAINER_MultiHashMap *
-    ego_places = GNUNET_CONTAINER_multihashmap_get (places_entered, 
&ego_pub_hash);
-  if (NULL != ego_places)
-    GNUNET_CONTAINER_multihashmap_iterate (ego_places, map_entry_place, 
client);
+    app_places = GNUNET_CONTAINER_multihashmap_get (apps_places, &app_id_hash);
+  if (NULL != app_places)
+    GNUNET_CONTAINER_multihashmap_iterate (app_places, app_place_entry, 
client);
 
-  GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-              "%p Client connected to listen for entered places of ego %s.\n",
-              NULL, GNUNET_h2s (&ego_pub_hash));
-
   struct ClientListItem *cli = GNUNET_new (struct ClientListItem);
   cli->client = client;
-  struct PlaceListener *pl = GNUNET_CONTAINER_multihashmap_get 
(place_listeners,
-                                                                &ego_pub_hash);
-  if (NULL == pl) {
-    pl = GNUNET_malloc (sizeof (*pl));
-    (void) GNUNET_CONTAINER_multihashmap_put (place_listeners, &ego_pub_hash, 
pl,
+  struct Application *app = GNUNET_CONTAINER_multihashmap_get (apps,
+                                                               &app_id_hash);
+  if (NULL == app) {
+    app = GNUNET_malloc (sizeof (*app));
+    (void) GNUNET_CONTAINER_multihashmap_put (apps, &app_id_hash, app,
                                               
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
   }
-  GNUNET_CONTAINER_DLL_insert (pl->clients_head, pl->clients_tail, cli);
+  GNUNET_CONTAINER_DLL_insert (app->clients_head, app->clients_tail, cli);
 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "%p Application %s connected.\n", app, app_id);
+
   struct Client *ctx = GNUNET_new (struct Client);
-  ctx->ego_key = req->ego_key;
+  ctx->app_id = GNUNET_malloc (app_id_size);
+  memcpy (ctx->app_id, app_id, app_id_size);
+
   GNUNET_SERVER_client_set_user_context (client, ctx);
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
 
 
+/**
+ * Handle application detach request.
+ */
+static void
+client_recv_app_detach (void *cls, struct GNUNET_SERVER_Client *client,
+                         const struct GNUNET_MessageHeader *msg)
+{
+  struct Client *
+    ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
+  GNUNET_assert (NULL != ctx);
+
+  const struct AppDetachRequest *req
+    = (const struct AppDetachRequest *) msg;
+
+  int ret = app_place_remove (ctx->app_id, &req->place_pub_key);
+  client_send_result (client, req->op_id, ret, NULL, 0);
+
+  GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Handle application detach request.
+ */
+static void
+client_recv_place_leave (void *cls, struct GNUNET_SERVER_Client *client,
+                         const struct GNUNET_MessageHeader *msg)
+{
+  struct Client *
+    ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
+  GNUNET_assert (NULL != ctx);
+  struct Place *plc = ctx->plc;
+
+  /* Disconnect all clients connected to the place */
+  /* FIXME: disconnect from the network, but keep local connection for history 
access */
+  struct ClientListItem *cli = plc->clients_head, *next;
+  while (NULL != cli)
+  {
+    GNUNET_CONTAINER_DLL_remove (plc->clients_head, plc->clients_tail, cli);
+    GNUNET_SERVER_client_disconnect (cli->client);
+    next = cli->next;
+    GNUNET_free (cli);
+    cli = next;
+  }
+
+  if (GNUNET_YES != plc->is_disconnected)
+  {
+    plc->is_disconnected = GNUNET_YES;
+    if (NULL != plc->tmit_msgs_head)
+    { /* Send pending messages to PSYC before cleanup. */
+      psyc_transmit_message (plc);
+    }
+    else
+    {
+      cleanup_place (plc);
+    }
+  }
+}
+
+
 struct JoinDecisionClosure
 {
   int32_t is_admitted;
@@ -1198,9 +1700,7 @@
   struct GNUNET_MessageHeader res;
   res.size = htons (sizeof (res));
   res.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK);
-
-  GNUNET_SERVER_notification_context_add (nc, client);
-  GNUNET_SERVER_notification_context_unicast (nc, client, &res, GNUNET_NO);
+  client_send_msg (client, &res);
 }
 
 
@@ -1872,7 +2372,7 @@
   memcpy (&res[1], msg, size);
 
   /** @todo FIXME: send only to requesting client */
-  client_send_msg (plc, &res->header);
+  place_send_msg (plc, &res->header);
 }
 
 
@@ -1977,7 +2477,7 @@
   memcpy (&res[1], mod, size);
 
   /** @todo FIXME: send only to requesting client */
-  client_send_msg (plc, &res->header);
+  place_send_msg (plc, &res->header);
 }
 
 
@@ -2059,6 +2559,130 @@
 }
 
 
+static void
+namestore_recv_records_store_result (void *cls, int32_t result,
+                                     const char *err_msg)
+{
+  struct OperationClosure *ocls = cls;
+  client_send_result (ocls->client, ocls->op_id, result, err_msg,
+                      (NULL != err_msg) ? strlen (err_msg) : 0);
+  GNUNET_free (ocls);
+}
+
+
+/**
+ * Handle request to add PLACE record to GNS zone.
+ */
+static void
+client_recv_zone_add_place (void *cls, struct GNUNET_SERVER_Client *client,
+                             const struct GNUNET_MessageHeader *msg)
+{
+  const struct ZoneAddPlaceRequest *preq
+    = (const struct ZoneAddPlaceRequest *) msg;
+
+  uint16_t remaining = ntohs (preq->header.size) - sizeof (*preq);
+  const char *p = (const char *) &preq[1];
+  const char *name = NULL, *password = NULL;
+  uint16_t offset = GNUNET_STRINGS_buffer_tokenize (p, remaining, 2,
+                                                    &name, &password);
+  remaining -= offset;
+  p += offset;
+  const struct GNUNET_PeerIdentity *
+    relays = (const struct GNUNET_PeerIdentity *) p;
+  uint16_t relay_size = ntohl (preq->relay_count) * sizeof (*relays);
+
+  if (0 == offset || remaining != relay_size)
+  {
+    GNUNET_break (0);
+    client_send_result (client, preq->op_id, GNUNET_SYSERR, NULL, 0);
+    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    return;
+  }
+
+  struct GNUNET_GNSRECORD_Data rd = { };
+  rd.record_type = GNUNET_GNSRECORD_TYPE_PLACE;
+  rd.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
+  rd.expiration_time = GNUNET_ntohll (preq->expiration_time);
+
+  struct GNUNET_GNSRECORD_PlaceData *
+    rec = GNUNET_malloc (sizeof (*rec) + relay_size);
+  rec->place_pub_key = preq->place_pub_key;
+  rec->origin = this_peer;
+  rec->relay_count = preq->relay_count;
+  memcpy (&rec[1], relays, relay_size);
+
+  rd.data = rec;
+  rd.data_size = sizeof (*rec) + relay_size;
+
+  struct GNUNET_HashCode ego_pub_hash;
+  GNUNET_CRYPTO_hash (&preq->ego_pub_key, sizeof (preq->ego_pub_key), 
&ego_pub_hash);
+  struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash);
+  if (NULL == ego)
+  {
+    client_send_result (client, preq->op_id, GNUNET_SYSERR, NULL, 0);
+  }
+  else
+  {
+    struct OperationClosure *ocls = GNUNET_malloc (sizeof (*ocls));
+    ocls->client = client;
+    ocls->op_id = preq->op_id;
+    GNUNET_NAMESTORE_records_store (namestore, &ego->key,
+                                    name, 1, &rd,
+                                    namestore_recv_records_store_result, ocls);
+  }
+  GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Handle request to add PLACE record to GNS zone.
+ */
+static void
+client_recv_zone_add_nym (void *cls, struct GNUNET_SERVER_Client *client,
+                          const struct GNUNET_MessageHeader *msg)
+{
+  const struct ZoneAddNymRequest *nreq
+    = (const struct ZoneAddNymRequest *) msg;
+
+  uint16_t name_size = ntohs (nreq->header.size) - sizeof (*nreq);
+  const char *name = NULL;
+  uint16_t offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &nreq[1],
+                                                    name_size, 1, &name);
+  if (0 == offset || offset != name_size)
+  {
+    GNUNET_break (0);
+    client_send_result (client, nreq->op_id, GNUNET_SYSERR, NULL, 0);
+    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    return;
+  }
+
+  struct GNUNET_GNSRECORD_Data rd = { };
+  rd.record_type = GNUNET_GNSRECORD_TYPE_PKEY;
+  rd.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
+  rd.expiration_time = GNUNET_ntohll (nreq->expiration_time);
+  rd.data = &nreq->nym_pub_key;
+  rd.data_size = sizeof (nreq->nym_pub_key);
+
+  struct GNUNET_HashCode ego_pub_hash;
+  GNUNET_CRYPTO_hash (&nreq->ego_pub_key, sizeof (nreq->ego_pub_key), 
&ego_pub_hash);
+  struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash);
+  if (NULL == ego)
+  {
+    client_send_result (client, nreq->op_id, GNUNET_SYSERR, NULL, 0);
+  }
+  else
+  {
+    struct OperationClosure *ocls = GNUNET_malloc (sizeof (*ocls));
+    ocls->client = client;
+    ocls->op_id = nreq->op_id;
+    GNUNET_NAMESTORE_records_store (namestore, &ego->key,
+                                      name, 1, &rd,
+                                      namestore_recv_records_store_result, 
ocls);
+  }
+  GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
   { &client_recv_host_enter, NULL,
     GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER, 0 },
@@ -2066,6 +2690,9 @@
   { &client_recv_guest_enter, NULL,
     GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER, 0 },
 
+  { &client_recv_guest_enter_by_name, NULL,
+    GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_BY_NAME, 0 },
+
   { &client_recv_join_decision, NULL,
     GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION, 0 },
 
@@ -2081,50 +2708,79 @@
   { &client_recv_state_get, NULL,
     GNUNET_MESSAGE_TYPE_PSYC_STATE_GET_PREFIX, 0 },
 
-  { &client_recv_place_listen, NULL,
-    GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LISTEN, 0 },
+  { &client_recv_zone_add_place, NULL,
+    GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_PLACE, 0 },
 
+  { &client_recv_zone_add_nym, NULL,
+    GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_NYM, 0 },
+
+  { &client_recv_app_connect, NULL,
+    GNUNET_MESSAGE_TYPE_SOCIAL_APP_CONNECT, 0 },
+
+  { &client_recv_app_detach, NULL,
+    GNUNET_MESSAGE_TYPE_SOCIAL_APP_DETACH, 0 },
+
+  { &client_recv_place_leave, NULL,
+    GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE, 0 },
+
   { NULL, NULL, 0, 0 }
 };
 
 
+const char *
+path_basename (const char *path)
+{
+  const char *basename = strrchr (path, DIR_SEPARATOR);
+  if (NULL != basename)
+    basename++;
+
+  if (NULL == basename || '\0' == basename)
+    return NULL;
+
+  return basename;
+}
+
+
+struct PlaceLoadClosure
+{
+  const char *app_id;
+  const char *ego_pub_hash_str;
+};
+
+
+/** Load a place file */
 int
 file_place_load (void *cls, const char *filename)
 {
-  uint64_t fsize = 0;
+  char *app_id = cls;
+  uint64_t file_size = 0;
   if (GNUNET_OK !=
-      GNUNET_DISK_file_size (filename, &fsize, GNUNET_YES, GNUNET_YES)
-      || fsize < sizeof (struct HostEnterRequest))
+      GNUNET_DISK_file_size (filename, &file_size, GNUNET_YES, GNUNET_YES)
+      || file_size < sizeof (struct HostEnterRequest))
     return GNUNET_OK;
 
-  struct GNUNET_MessageHeader *msg = GNUNET_malloc (fsize);
-  ssize_t rsize = GNUNET_DISK_fn_read (filename, msg, fsize);
-  if (rsize < 0 || (size_t) rsize < sizeof (*msg))
+  struct PlaceEnterRequest *ereq = GNUNET_malloc (file_size);
+  ssize_t read_size = GNUNET_DISK_fn_read (filename, ereq, file_size);
+  if (read_size < 0 || read_size < sizeof (*ereq))
     return GNUNET_OK;
 
-  uint16_t msg_size = ntohs (msg->size);
-  struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub;
-  struct GNUNET_CRYPTO_EddsaPublicKey place_pub;
+  uint16_t ereq_size = ntohs (ereq->header.size);
+  if (read_size != ereq_size)
+    return GNUNET_OK;
 
-  switch (ntohs (msg->type))
+  switch (ntohs (ereq->header.type))
   {
   case GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER:
-    if (msg_size < sizeof (struct HostEnterRequest))
+    if (ereq_size < sizeof (struct HostEnterRequest))
       return GNUNET_OK;
-    struct HostEnterRequest *hreq = (struct HostEnterRequest *) msg;
-    GNUNET_CRYPTO_ecdsa_key_get_public (&hreq->host_key, &ego_pub);
-    GNUNET_CRYPTO_eddsa_key_get_public (&hreq->place_key, &place_pub);
-
+    struct HostEnterRequest *hreq = (struct HostEnterRequest *) ereq;
     host_enter (hreq, NULL);
     break;
 
   case GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER:
-    if (msg_size < sizeof (struct GuestEnterRequest))
+    if (ereq_size < sizeof (struct GuestEnterRequest))
       return GNUNET_OK;
-    struct GuestEnterRequest *greq = (struct GuestEnterRequest *) msg;
-    GNUNET_CRYPTO_ecdsa_key_get_public (&greq->guest_key, &ego_pub);
-    place_pub = greq->place_key;
-
+    struct GuestEnterRequest *greq = (struct GuestEnterRequest *) ereq;
     guest_enter (greq, NULL);
     break;
 
@@ -2132,44 +2788,139 @@
     return GNUNET_OK;
   }
 
-  struct GNUNET_HashCode ego_pub_hash, place_pub_hash;
-  GNUNET_CRYPTO_hash (&ego_pub, sizeof (ego_pub), &ego_pub_hash);
-  GNUNET_CRYPTO_hash (&place_pub, sizeof (place_pub), &place_pub_hash);
+  app_place_add (app_id, ereq);
+  return GNUNET_OK;
+}
 
-  place_add (&ego_pub_hash, &place_pub_hash, msg);
+
+/** Load an ego place file */
+int
+file_ego_place_load (void *cls, const char *place_filename)
+{
+  struct PlaceLoadClosure *plcls = cls;
+
+  const char *place_pub_hash_str = path_basename (place_filename);
+  if (NULL == place_pub_hash_str)
+  {
+    GNUNET_break (0);
+    return GNUNET_OK;
+  }
+
+  char *filename = NULL;
+  GNUNET_asprintf (&filename, "%s%c" "%s%c" "%s%c" "%s",
+                   dir_social, DIR_SEPARATOR,
+                   "places", DIR_SEPARATOR,
+                   plcls->ego_pub_hash_str, DIR_SEPARATOR,
+                   place_pub_hash_str);
+
+  struct PlaceEnterRequest ereq[GNUNET_SERVER_MAX_MESSAGE_SIZE];
+
+  int read_size = GNUNET_DISK_fn_read (filename, &ereq,
+                                       GNUNET_SERVER_MAX_MESSAGE_SIZE);
+  GNUNET_free (filename);
+
+  if (read_size < (ssize_t) sizeof (ereq))
+    return GNUNET_OK;
+
+  app_place_add (plcls->app_id, ereq);
   return GNUNET_OK;
 }
 
 
+/**
+ * Read @e place_pub_hash_str entries in @a dir_ego
+ *
+ * @param dir_ego
+ *        Data directory of an application ego.
+ *        e.g. ~/.local/share/gnunet/social/apps/$app_id/$ego_pub_hash_str/
+ */
 int
-load_places_of_ego (void *cls, const char *dir_ego)
+scan_app_ego_dir (void *cls, const char *dir_ego)
 {
-  if (GNUNET_YES != GNUNET_DISK_directory_test (dir_ego, GNUNET_YES))
+  struct PlaceLoadClosure *plcls = cls;
+  plcls->ego_pub_hash_str = path_basename (dir_ego);
+
+  if (NULL != plcls->ego_pub_hash_str)
+    GNUNET_DISK_directory_scan (dir_ego, file_ego_place_load, plcls);
+
+  return GNUNET_OK;
+}
+
+/**
+ * Read @e ego_pub_hash_str entries in @a dir_app
+ *
+ * @param dir_app
+ *        Data directory of an application.
+ *        e.g. ~/.local/share/gnunet/social/apps/$app_id/
+ */
+int
+scan_app_dir (void *cls, const char *dir_app)
+{
+  if (GNUNET_YES != GNUNET_DISK_directory_test (dir_app, GNUNET_YES))
     return GNUNET_OK;
 
-  GNUNET_DISK_directory_scan (dir_ego, file_place_load, NULL);
+  struct PlaceLoadClosure plcls;
+  plcls.app_id = path_basename (dir_app);
+
+  if (NULL != plcls.app_id)
+    GNUNET_DISK_directory_scan (dir_app, scan_app_ego_dir, &plcls);
+
   return GNUNET_OK;
 }
 
 
-void
-load_places ()
+static void
+identity_recv_ego (void *cls, struct GNUNET_IDENTITY_Ego *id_ego,
+                   void **ctx, const char *name)
 {
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_filename (cfg, "social", "PLACES_DIR",
-                                               &dir_places))
+  if (NULL == id_ego) // end of initial list of egos
+    return;
+
+  struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
+  GNUNET_IDENTITY_ego_get_public_key (id_ego, &ego_pub_key);
+
+  struct GNUNET_HashCode ego_pub_hash;
+  GNUNET_CRYPTO_hash (&ego_pub_key, sizeof (ego_pub_key), &ego_pub_hash);
+
+  struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash);
+  if (NULL != ego)
   {
-    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "social", 
"PLACES_DIR");
-    GNUNET_break (0);
-    return;
+    GNUNET_free (ego->name);
+    if (NULL == name) // deleted
+    {
+      GNUNET_CONTAINER_multihashmap_remove (egos, &ego_pub_hash, ego);
+      GNUNET_free (ego);
+      ego = NULL;
+    }
   }
+  else
+  {
+    ego = GNUNET_malloc (sizeof (*ego));
+  }
+  if (NULL != ego)
+  {
+    ego->key = *(GNUNET_IDENTITY_ego_get_private_key (id_ego));
+    size_t name_size = strlen (name) + 1;
+    ego->name = GNUNET_malloc (name_size);
+    memcpy (ego->name, name, name_size);
 
-  places_entered = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_NO);
-  GNUNET_DISK_directory_scan (dir_places, load_places_of_ego, NULL);
+    GNUNET_CONTAINER_multihashmap_put (egos, &ego_pub_hash, ego,
+                                       
GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
+  }
 }
 
 
 /**
+ * Connected to core service.
+ */
+static void
+core_connected (void *cls, const struct GNUNET_PeerIdentity *my_identity)
+{
+  this_peer = *my_identity;
+}
+
+
+/**
  * Initialize the PSYC service.
  *
  * @param cls Closure.
@@ -2181,13 +2932,39 @@
      const struct GNUNET_CONFIGURATION_Handle *c)
 {
   cfg = c;
-  stats = GNUNET_STATISTICS_create ("social", cfg);
+
   hosts = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
   guests = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
   place_guests = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
-  place_listeners = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
-  load_places ();
 
+  egos = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
+  apps = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
+  places = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_NO);
+  apps_places = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_NO);
+
+  core = GNUNET_CORE_connect (cfg, NULL, core_connected, NULL, NULL,
+                              NULL, GNUNET_NO, NULL, GNUNET_NO, NULL);
+  id = GNUNET_IDENTITY_connect (cfg, &identity_recv_ego, NULL);
+  gns = GNUNET_GNS_connect (cfg);
+  namestore = GNUNET_NAMESTORE_connect (cfg);
+  stats = GNUNET_STATISTICS_create ("social", cfg);
+
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_filename (cfg, "social", 
"SOCIAL_DATA_DIR",
+                                               &dir_social))
+  {
+    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+                               "social", "SOCIAL_DATA_DIR");
+    GNUNET_break (0);
+    return;
+  }
+  GNUNET_asprintf (&dir_places, "%s%c%s",
+                   dir_social, DIR_SEPARATOR, "places");
+  GNUNET_asprintf (&dir_apps, "%s%c%s",
+                   dir_social, DIR_SEPARATOR, "apps");
+
+  GNUNET_DISK_directory_scan (dir_apps, scan_app_dir, NULL);
+
   nc = GNUNET_SERVER_notification_context_create (server, 1);
   GNUNET_SERVER_add_handlers (server, handlers);
   GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);

Modified: gnunet/src/social/social.h
===================================================================
--- gnunet/src/social/social.h  2015-12-16 17:43:13 UTC (rev 36766)
+++ gnunet/src/social/social.h  2015-12-17 14:12:44 UTC (rev 36767)
@@ -49,6 +49,37 @@
 /**** library -> service ****/
 
 
+struct AppConnectRequest
+{
+  /**
+   * Type: GNUNET_MESSAGE_TYPE_SOCIAL_APP_CONNECT
+   */
+  struct GNUNET_MessageHeader header;
+
+  /* Followed by char *app_id */
+};
+
+
+struct AppDetachRequest
+{
+  /**
+   * Type: GNUNET_MESSAGE_TYPE_SOCIAL_APP_DETACH
+   */
+  struct GNUNET_MessageHeader header;
+
+  /**
+   * Public key of place.
+   */
+  struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key;
+
+  /**
+   * Operation ID.
+   */
+  uint64_t op_id GNUNET_PACKED;
+
+};
+
+
 struct HostEnterRequest
 {
   /**
@@ -58,9 +89,13 @@
 
   uint32_t policy GNUNET_PACKED;
 
-  struct GNUNET_CRYPTO_EcdsaPrivateKey host_key;
+  struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
 
+  struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key;
+
   struct GNUNET_CRYPTO_EddsaPrivateKey place_key;
+
+  /* Followed by char *app_id */
 };
 
 
@@ -67,37 +102,166 @@
 struct GuestEnterRequest
 {
   /**
-   * Type: GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ADDR
+   * Type: GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER
    */
   struct GNUNET_MessageHeader header;
 
   uint32_t relay_count GNUNET_PACKED;
 
-  struct GNUNET_CRYPTO_EcdsaPrivateKey guest_key;
+  struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
 
-  struct GNUNET_CRYPTO_EddsaPublicKey place_key;
+  struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key;
 
   struct GNUNET_PeerIdentity origin;
 
+  /* Followed by char *app_id */
   /* Followed by struct GNUNET_PeerIdentity relays[relay_count] */
+  /* Followed by struct GNUNET_MessageHeader *join_msg */
+};
 
-  /* Followed by struct GNUNET_MessageHeader join_msg */
+
+/** Compatible parts of HostEnterRequest and GuestEnterRequest */
+struct PlaceEnterRequest
+{
+  struct GNUNET_MessageHeader header;
+
+  uint32_t reserved GNUNET_PACKED;
+
+  struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
+
+  struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key;
 };
 
 
-struct PlaceListenRequest
+struct EgoPlacePublicKey
 {
+  struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
+  struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key;
+};
+
+
+struct GuestEnterByNameRequest
+{
   /**
-   * Type: GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LISTEN
+   * Type: GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_BY_NAME
    */
   struct GNUNET_MessageHeader header;
 
-  struct GNUNET_CRYPTO_EcdsaPrivateKey ego_key;
+  struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
+
+  /* Followed by char *app_id */
+  /* Followed by char *gns_name */
+  /* Followed by char *password */
+  /* Followed by struct GNUNET_MessageHeader *join_msg */
 };
 
 
+struct ZoneAddPlaceRequest
+{
+  struct GNUNET_MessageHeader header;
+
+  uint32_t relay_count GNUNET_PACKED;
+
+  /**
+   * Operation ID.
+   */
+  uint64_t op_id;
+
+  /**
+   * Expiration time: absolute value in us.
+   */
+  uint64_t expiration_time;
+
+  struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
+
+  struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key;
+
+  struct GNUNET_PeerIdentity origin;
+
+  /* Followed by const char *name */
+  /* Followed by const char *password */
+  /* Followed by  struct GNUNET_PeerIdentity *relays[relay_count] */
+};
+
+
+struct ZoneAddNymRequest
+{
+  struct GNUNET_MessageHeader header;
+
+  /**
+   * Operation ID.
+   */
+  uint64_t op_id;
+
+  /**
+   * Expiration time: absolute value in us.
+   */
+  uint64_t expiration_time;
+
+  struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
+
+  struct GNUNET_CRYPTO_EcdsaPublicKey nym_pub_key;
+
+  /* Followed by const char *name */
+};
+
 /**** service -> library ****/
 
+
+struct AppEgoMessage
+{
+  /**
+   * Type: GNUNET_MESSAGE_TYPE_SOCIAL_APP_EGO
+   */
+  struct GNUNET_MessageHeader header;
+
+  /**
+   * Public key of ego.
+   */
+  struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
+
+  /* Followed by char *name */
+};
+
+
+struct AppPlaceMessage
+{
+  /**
+   * Type: GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE
+   */
+  struct GNUNET_MessageHeader header;
+
+  struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
+
+  struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key;
+
+  uint8_t is_host;
+};
+
+
+struct HostEnterAck {
+  /**
+   * Type: GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK
+   */
+  struct GNUNET_MessageHeader header;
+
+  /**
+   * Status code for the operation.
+   */
+  uint32_t result_code GNUNET_PACKED;
+
+  /**
+   * Last message ID sent to the channel.
+   */
+  uint64_t max_message_id GNUNET_PACKED;
+
+  /**
+   * Public key of the place.
+   */
+  struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key;
+};
+
+
 #if REMOVE
 struct NymEnterRequest
 {
@@ -105,6 +269,7 @@
    * Type: GNUNET_MESSAGE_TYPE_SOCIAL_NYM_ENTER
    */
   struct GNUNET_MessageHeader header;
+
   /**
    * Public key of the joining slave.
    */

Modified: gnunet/src/social/social_api.c
===================================================================
--- gnunet/src/social/social_api.c      2015-12-16 17:43:13 UTC (rev 36766)
+++ gnunet/src/social/social_api.c      2015-12-17 14:12:44 UTC (rev 36767)
@@ -30,10 +30,6 @@
 #include "platform.h"
 #include "gnunet_util_lib.h"
 #include "gnunet_env_lib.h"
-#include "gnunet_core_service.h"
-#include "gnunet_identity_service.h"
-#include "gnunet_namestore_service.h"
-#include "gnunet_gns_service.h"
 #include "gnunet_psyc_service.h"
 #include "gnunet_psyc_util_lib.h"
 #include "gnunet_social_service.h"
@@ -41,13 +37,17 @@
 
 #define LOG(kind,...) GNUNET_log_from (kind, "social-api",__VA_ARGS__)
 
+/**
+ * Handle for an ego.
+ */
+struct GNUNET_SOCIAL_Ego
+{
+  struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
+  struct GNUNET_HashCode pub_key_hash;
+  char *name;
+};
 
-static struct GNUNET_CORE_Handle *core;
-static struct GNUNET_GNS_Handle *gns;
-static struct GNUNET_NAMESTORE_Handle *namestore;
-static struct GNUNET_PeerIdentity this_peer;
 
-
 /**
  * Handle for a pseudonym of another user in the network.
  */
@@ -59,6 +59,76 @@
 
 
 /**
+ * Handle for an application.
+ */
+struct GNUNET_SOCIAL_App
+{
+  /**
+   * Configuration to use.
+   */
+  const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+  /**
+   * Client connection to the service.
+   */
+  struct GNUNET_CLIENT_MANAGER_Connection *client;
+
+  /**
+   * Message to send on reconnect.
+   */
+  struct GNUNET_MessageHeader *connect_msg;
+
+  /**
+   * Function called after disconnected from the service.
+   */
+  GNUNET_ContinuationCallback disconnect_cb;
+
+  /**
+   * Closure for @a disconnect_cb.
+   */
+  void *disconnect_cls;
+
+  /**
+   * Application ID.
+   */
+  char *id;
+
+  /**
+   * Hash map of all egos.
+   * pub_key_hash -> struct GNUNET_SOCIAL_Ego *
+   */
+  struct GNUNET_CONTAINER_MultiHashMap *egos;
+
+  GNUNET_SOCIAL_AppEgoCallback ego_cb;
+  GNUNET_SOCIAL_AppHostPlaceCallback host_cb;
+  GNUNET_SOCIAL_AppGuestPlaceCallback guest_cb;
+  void *cb_cls;
+
+  /**
+   * Is this place in the process of disconnecting from the service?
+   * #GNUNET_YES or #GNUNET_NO
+   */
+  uint8_t is_disconnecting;
+};
+
+
+struct GNUNET_SOCIAL_HostConnection
+{
+  struct GNUNET_SOCIAL_App *app;
+
+  struct AppPlaceMessage plc_msg;
+};
+
+
+struct GNUNET_SOCIAL_GuestConnection
+{
+  struct GNUNET_SOCIAL_App *app;
+
+  struct AppPlaceMessage plc_msg;
+};
+
+
+/**
  * Handle for a place where social interactions happen.
  */
 struct GNUNET_SOCIAL_Place
@@ -109,9 +179,9 @@
   struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
 
   /**
-   * Private key of the ego.
+   * Public key of the ego.
    */
-  struct GNUNET_CRYPTO_EcdsaPrivateKey ego_key;
+  struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
 
   /**
    * Does this place belong to a host (#GNUNET_YES) or guest (#GNUNET_NO)?
@@ -133,8 +203,6 @@
 {
   struct GNUNET_SOCIAL_Place plc;
 
-  struct GNUNET_CRYPTO_EddsaPrivateKey place_key;
-
   /**
    * Receipt handle.
    */
@@ -190,19 +258,6 @@
 
 
 /**
- * Handle for place notifications.
- */
-struct GNUNET_SOCIAL_PlaceListenHandle
-{
-  struct GNUNET_SOCIAL_Place plc;
-
-  GNUNET_SOCIAL_PlaceNotifyHostCallback notify_host;
-  GNUNET_SOCIAL_PlaceNotifyGuestCallback notify_guest;
-  void *notify_cls;
-};
-
-
-/**
  * Hash map of all nyms.
  * pub_key_hash -> struct GNUNET_SOCIAL_Nym *
  */
@@ -417,6 +472,22 @@
 };
 
 
+struct ZoneAddPlaceHandle
+{
+  struct ZoneAddPlaceRequest *req;
+  GNUNET_ResultCallback result_cb;
+  void *result_cls;
+};
+
+
+struct ZoneAddNymHandle
+{
+  struct ZoneAddNymRequest *req;
+  GNUNET_ResultCallback result_cb;
+  void *result_cls;
+};
+
+
 /*** NYM ***/
 
 static struct GNUNET_SOCIAL_Nym *
@@ -1012,7 +1083,32 @@
   GNUNET_free (slicer);
 }
 
+/*** CLIENT ***/
 
+
+static void
+app_send_connect_msg (struct GNUNET_SOCIAL_App *app)
+{
+  uint16_t cmsg_size = ntohs (app->connect_msg->size);
+  struct GNUNET_MessageHeader * cmsg = GNUNET_malloc (cmsg_size);
+  memcpy (cmsg, app->connect_msg, cmsg_size);
+  GNUNET_CLIENT_MANAGER_transmit_now (app->client, cmsg);
+}
+
+
+static void
+app_recv_disconnect (void *cls,
+                     struct GNUNET_CLIENT_MANAGER_Connection *client,
+                     const struct GNUNET_MessageHeader *msg)
+{
+  struct GNUNET_SOCIAL_App *
+    app = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*app));
+
+  GNUNET_CLIENT_MANAGER_reconnect (client);
+  app_send_connect_msg (app);
+}
+
+
 /*** PLACE ***/
 
 
@@ -1066,6 +1162,32 @@
 
 
 static void
+app_recv_result (void *cls,
+                 struct GNUNET_CLIENT_MANAGER_Connection *client,
+                 const struct GNUNET_MessageHeader *msg)
+{
+  struct GNUNET_SOCIAL_App *
+    app = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*app));
+
+  const struct GNUNET_OperationResultMessage *
+    res = (const struct GNUNET_OperationResultMessage *) msg;
+
+  uint16_t size = ntohs (msg->size);
+  if (size < sizeof (*res))
+  { /* Error, message too small. */
+    GNUNET_break (0);
+    return;
+  }
+
+  uint16_t data_size = size - sizeof (*res);
+  const char *data = (0 < data_size) ? (const char *) &res[1] : NULL;
+  GNUNET_CLIENT_MANAGER_op_result (app->client, GNUNET_ntohll (res->op_id),
+                                   GNUNET_ntohll (res->result_code),
+                                   data, data_size);
+}
+
+
+static void
 op_recv_history_result (void *cls, int64_t result,
                         const void *err_msg, uint16_t err_msg_size)
 {
@@ -1261,11 +1383,13 @@
     hst = GNUNET_CLIENT_MANAGER_get_user_context_ (client,
                                                    sizeof (struct 
GNUNET_SOCIAL_Place));
 
-  struct GNUNET_PSYC_CountersResultMessage *
-    cres = (struct GNUNET_PSYC_CountersResultMessage *) msg;
-  int32_t result = ntohl (cres->result_code);
+  struct HostEnterAck *hack = (struct HostEnterAck *) msg;
+  hst->plc.pub_key = hack->place_pub_key;
+
+  int32_t result = ntohl (hack->result_code);
   if (NULL != hst->enter_cb)
-    hst->enter_cb (hst->cb_cls, result, GNUNET_ntohll (cres->max_message_id));
+    hst->enter_cb (hst->cb_cls, result, &hack->place_pub_key,
+                   GNUNET_ntohll (hack->max_message_id));
 }
 
 
@@ -1364,52 +1488,85 @@
 
 
 static void
-notify_recv_place_host (void *cls,
-                        struct GNUNET_CLIENT_MANAGER_Connection *client,
-                        const struct GNUNET_MessageHeader *msg)
+app_recv_ego (void *cls,
+              struct GNUNET_CLIENT_MANAGER_Connection *client,
+              const struct GNUNET_MessageHeader *msg)
 {
-  struct GNUNET_SOCIAL_PlaceListenHandle *
-    pl = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*pl));
-  if (NULL == pl->notify_host)
-    return;
+  struct GNUNET_SOCIAL_App *
+    app = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*app));
 
-  struct HostEnterRequest *
-    hreq = (struct HostEnterRequest *) msg;
+  struct AppEgoMessage *
+    emsg = (struct AppEgoMessage *) msg;
 
-  pl->notify_host (pl->notify_cls, &hreq->place_key, ntohl (hreq->policy));
+  uint16_t name_size = ntohs (emsg->header.size) - sizeof (*emsg);
+
+  struct GNUNET_HashCode ego_pub_hash;
+  GNUNET_CRYPTO_hash (&emsg->ego_pub_key, sizeof (emsg->ego_pub_key),
+                      &ego_pub_hash);
+
+  struct GNUNET_SOCIAL_Ego *
+    ego = GNUNET_CONTAINER_multihashmap_get (app->egos, &ego_pub_hash);
+  if (NULL == ego)
+  {
+    ego = GNUNET_malloc (sizeof (*ego));
+    ego->pub_key = emsg->ego_pub_key;
+    ego->name = GNUNET_malloc (name_size);
+    memcpy (ego->name, &emsg[1], name_size);
+  }
+  else
+  {
+    ego->name = GNUNET_realloc (ego->name, name_size);
+    memcpy (ego->name, &emsg[1], name_size);
+  }
+
+  GNUNET_CONTAINER_multihashmap_put (app->egos, &ego_pub_hash, ego,
+                                     
GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
+
+  if (NULL != app->ego_cb)
+    app->ego_cb (app->cb_cls, ego, &ego->pub_key, ego->name);
 }
 
 
 static void
-notify_recv_place_guest (void *cls,
-                         struct GNUNET_CLIENT_MANAGER_Connection *client,
-                         const struct GNUNET_MessageHeader *msg)
+app_recv_place (void *cls,
+                struct GNUNET_CLIENT_MANAGER_Connection *client,
+                const struct GNUNET_MessageHeader *msg)
 {
-  struct GNUNET_SOCIAL_PlaceListenHandle *
-    pl = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*pl));
-  if (NULL == pl->notify_guest)
-    return;
+  struct GNUNET_SOCIAL_App *
+    app = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*app));
 
-  struct GuestEnterRequest *
-    greq = (struct GuestEnterRequest *) msg;
-  uint16_t greq_size = ntohs (greq->header.size);
+  struct AppPlaceMessage *
+    pmsg = (struct AppPlaceMessage *) msg;
 
-  const struct GNUNET_PeerIdentity *relays = NULL;
-  uint16_t relay_count = ntohs (greq->relay_count);
-  uint16_t relay_size = relay_count * sizeof (*relays);
-  if (0 < relay_size)
-    relays = (const struct GNUNET_PeerIdentity *) &greq[1];
-  struct GNUNET_PSYC_Message *join_msg = NULL;
+  if ((GNUNET_YES == pmsg->is_host && NULL == app->host_cb)
+      || (GNUNET_NO == pmsg->is_host && NULL == app->guest_cb))
+    return;
 
-  if (sizeof (*greq) + relay_size + sizeof (struct GNUNET_MessageHeader)
-      <= greq_size)
+  struct GNUNET_HashCode ego_pub_hash;
+  GNUNET_CRYPTO_hash (&pmsg->ego_pub_key, sizeof (pmsg->ego_pub_key),
+                      &ego_pub_hash);
+  struct GNUNET_SOCIAL_Ego *
+    ego = GNUNET_CONTAINER_multihashmap_get (app->egos, &ego_pub_hash);
+  if (NULL == ego)
   {
-    join_msg = (struct GNUNET_PSYC_Message *)
-      (((char *) &greq[1]) + relay_size);
+    GNUNET_break (0);
+    return;
   }
 
-  pl->notify_guest (pl->notify_cls, &greq->place_key, &greq->origin,
-                    relay_count, relays, join_msg);
+  if (GNUNET_YES == pmsg->is_host)
+  {
+    struct GNUNET_SOCIAL_HostConnection *hconn = GNUNET_malloc (sizeof 
(*hconn));
+    hconn->app = app;
+    hconn->plc_msg = *pmsg;
+    app->host_cb (app->cb_cls, hconn, ego, &pmsg->place_pub_key);
+  }
+  else
+  {
+    struct GNUNET_SOCIAL_GuestConnection *gconn = GNUNET_malloc (sizeof 
(*gconn));
+    gconn->app = app;
+    gconn->plc_msg = *pmsg;
+    app->guest_cb (app->cb_cls, gconn, ego, &pmsg->place_pub_key);
+  }
 }
 
 
@@ -1417,7 +1574,7 @@
 {
   { host_recv_enter_ack, NULL,
     GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK,
-    sizeof (struct GNUNET_PSYC_CountersResultMessage), GNUNET_NO },
+    sizeof (struct HostEnterAck), GNUNET_NO },
 
   { host_recv_enter_request, NULL,
     GNUNET_MESSAGE_TYPE_PSYC_JOIN_REQUEST,
@@ -1490,16 +1647,22 @@
 
 
 
-static struct GNUNET_CLIENT_MANAGER_MessageHandler notify_handlers[] =
+static struct GNUNET_CLIENT_MANAGER_MessageHandler app_handlers[] =
 {
-  { notify_recv_place_host, NULL,
-    GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER,
-    sizeof (struct HostEnterRequest), GNUNET_NO },
+  { app_recv_ego, NULL,
+    GNUNET_MESSAGE_TYPE_SOCIAL_APP_EGO,
+    sizeof (struct AppEgoMessage), GNUNET_YES },
 
-  { notify_recv_place_guest, NULL,
-    GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER,
-    sizeof (struct GuestEnterRequest), GNUNET_YES },
+  { app_recv_place, NULL,
+    GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE,
+    sizeof (struct AppPlaceMessage), GNUNET_NO },
 
+  { app_recv_result, NULL,
+    GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE,
+    sizeof (struct GNUNET_OperationResultMessage), GNUNET_YES },
+
+  { app_recv_disconnect, NULL, 0, 0, GNUNET_NO },
+
   { NULL, NULL, 0, 0, GNUNET_NO }
 };
 
@@ -1515,22 +1678,6 @@
     GNUNET_free (plc->connect_msg);
   if (NULL != plc->disconnect_cb)
     plc->disconnect_cb (plc->disconnect_cls);
-
-  if (NULL != core)
-  {
-    GNUNET_CORE_disconnect (core);
-    core = NULL;
-  }
-  if (NULL != namestore)
-  {
-    GNUNET_NAMESTORE_disconnect (namestore);
-    namestore = NULL;
-  }
-  if (NULL != gns)
-  {
-    GNUNET_GNS_disconnect (gns);
-    gns = NULL;
-  }
 }
 
 
@@ -1539,8 +1686,16 @@
 {
   struct GNUNET_SOCIAL_Host *hst = cls;
   place_cleanup (&hst->plc);
-  GNUNET_PSYC_receive_destroy (hst->recv);
-  GNUNET_SOCIAL_slicer_destroy (hst->slicer);
+  if (NULL != hst->recv)
+  {
+    GNUNET_PSYC_receive_destroy (hst->recv);
+    hst->recv = NULL;
+  }
+  if (NULL != hst->slicer)
+  {
+    GNUNET_SOCIAL_slicer_destroy (hst->slicer);
+    hst->slicer = NULL;
+  }
   GNUNET_free (hst);
 }
 
@@ -1568,11 +1723,13 @@
  *        Identity of the host.
  * @param place_key
  *        Private-public key pair of the place.
- *        NULL for ephemeral places.
+ *        NULL to generate a key.
  * @param policy
  *        Policy specifying entry and history restrictions for the place.
  * @param slicer
  *        Slicer to handle incoming messages.
+ * @param enter_cb
+ *        Function called when the place is entered and ready to use.
  * @param answer_door_cb
  *        Function to handle new nyms that want to enter.
  * @param farewell_cb
@@ -1583,9 +1740,8 @@
  * @return Handle for the host.
  */
 struct GNUNET_SOCIAL_Host *
-GNUNET_SOCIAL_host_enter (const struct GNUNET_CONFIGURATION_Handle *cfg,
-                          const struct GNUNET_IDENTITY_Ego *ego,
-                          const struct GNUNET_CRYPTO_EddsaPrivateKey 
*place_key,
+GNUNET_SOCIAL_host_enter (const struct GNUNET_SOCIAL_App *app,
+                          const struct GNUNET_SOCIAL_Ego *ego,
                           enum GNUNET_PSYC_Policy policy,
                           struct GNUNET_SOCIAL_Slicer *slicer,
                           GNUNET_SOCIAL_HostEnterCallback enter_cb,
@@ -1595,35 +1751,17 @@
 {
   struct GNUNET_SOCIAL_Host *hst = GNUNET_malloc (sizeof (*hst));
   struct GNUNET_SOCIAL_Place *plc = &hst->plc;
-  struct HostEnterRequest *req = GNUNET_malloc (sizeof (*req));
 
-  if (NULL != place_key)
-  {
-    hst->place_key = *place_key;
-  }
-  else
-  {
-    struct GNUNET_CRYPTO_EddsaPrivateKey *
-      ephemeral_key = GNUNET_CRYPTO_eddsa_key_create ();
-    hst->place_key = *ephemeral_key;
-    GNUNET_CRYPTO_eddsa_key_get_public (&hst->place_key, &plc->pub_key);
-    GNUNET_CRYPTO_eddsa_key_clear (ephemeral_key);
-    GNUNET_free (ephemeral_key);
-  }
-
-  plc->cfg = cfg;
+  plc->cfg = app->cfg;
   plc->is_host = GNUNET_YES;
   plc->slicer = slicer;
 
-  plc->ego_key = *GNUNET_IDENTITY_ego_get_private_key (ego);
-  GNUNET_CRYPTO_eddsa_key_get_public (place_key, &plc->pub_key);
-
   hst->enter_cb = enter_cb;
   hst->answer_door_cb = answer_door_cb;
   hst->farewell_cb = farewell_cb;
   hst->cb_cls = cls;
 
-  plc->client = GNUNET_CLIENT_MANAGER_connect (cfg, "social", host_handlers);
+  plc->client = GNUNET_CLIENT_MANAGER_connect (plc->cfg, "social", 
host_handlers);
   GNUNET_CLIENT_MANAGER_set_user_context_ (plc->client, hst, sizeof (*plc));
 
   plc->tmit = GNUNET_PSYC_transmit_create (plc->client);
@@ -1636,13 +1774,15 @@
                                    NULL, host_recv_notice_place_leave_eom, 
hst);
   hst->recv = GNUNET_PSYC_receive_create (NULL, slicer_message, hst->slicer);
 
-  req->header.size = htons (sizeof (*req));
-  req->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER);
-  req->policy = policy;
-  req->place_key = hst->place_key;
-  req->host_key = plc->ego_key;
+  uint16_t app_id_size = strlen (app->id) + 1;
+  struct HostEnterRequest *hreq = GNUNET_malloc (sizeof (*hreq) + app_id_size);
+  hreq->header.size = htons (sizeof (*hreq) + app_id_size);
+  hreq->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER);
+  hreq->policy = policy;
+  hreq->ego_pub_key = ego->pub_key;
+  memcpy (&hreq[1], app->id, app_id_size);
 
-  plc->connect_msg = (struct GNUNET_MessageHeader *) req;
+  plc->connect_msg = &hreq->header;
   place_send_connect_msg (plc);
 
   return hst;
@@ -1650,22 +1790,15 @@
 
 
 /**
- * Enter a place as host.
+ * Reconnect to an already entered place as host.
  *
- * A place is created upon first entering, and it is active until permanently
- * left using GNUNET_SOCIAL_host_leave().
- *
- * @param cfg
- *        Configuration to contact the social service.
- * @param ego
- *        Identity of the host.
- * @param gns_name
- *        GNS name in the zone of the @a ego that contains the
- *        public key of the place in a PLACE record.
- * @param policy
- *        Policy specifying entry and history restrictions for the place.
+ * @param hconn
+ *        Host connection handle.
+ *        @see GNUNET_SOCIAL_app_connect() & 
GNUNET_SOCIAL_AppHostPlaceCallback()
  * @param slicer
  *        Slicer to handle incoming messages.
+ * @param enter_cb
+ *        Function called when the place is entered and ready to use.
  * @param answer_door_cb
  *        Function to handle new nyms that want to enter.
  * @param farewell_cb
@@ -1676,26 +1809,54 @@
  * @return Handle for the host.
  */
 struct GNUNET_SOCIAL_Host *
-GNUNET_SOCIAL_host_enter_by_name (const struct GNUNET_CONFIGURATION_Handle 
*cfg,
-                                  struct GNUNET_IDENTITY_Ego *ego,
-                                  const char *gns_name,
-                                  enum GNUNET_PSYC_Policy policy,
-                                  struct GNUNET_SOCIAL_Slicer *slicer,
-                                  GNUNET_SOCIAL_HostEnterCallback enter_cb,
-                                  GNUNET_SOCIAL_AnswerDoorCallback 
answer_door_cb,
-                                  GNUNET_SOCIAL_FarewellCallback farewell_cb,
-                                  void *cls)
+GNUNET_SOCIAL_host_enter_reconnect (struct GNUNET_SOCIAL_HostConnection *hconn,
+                                    struct GNUNET_SOCIAL_Slicer *slicer,
+                                    GNUNET_SOCIAL_HostEnterCallback enter_cb,
+                                    GNUNET_SOCIAL_AnswerDoorCallback 
answer_door_cb,
+                                    GNUNET_SOCIAL_FarewellCallback farewell_cb,
+                                    void *cls)
 {
-  struct GNUNET_CRYPTO_EddsaPrivateKey place_key = {};
+  struct GNUNET_SOCIAL_Host *hst = GNUNET_malloc (sizeof (*hst));
+  struct GNUNET_SOCIAL_Place *plc = &hst->plc;
 
-  /* FIXME:
-   * 1. get public key by looking up PLACE entry under gns_name
-   *    in the zone of the ego.
-   * 2. get private key from $GNUNET_DATA_HOME/social/places/PUB_KEY_HASH
-   */
+  size_t app_id_size = strlen (hconn->app->id) + 1;
+  struct HostEnterRequest *hreq = GNUNET_malloc (sizeof (*hreq) + app_id_size);
 
-  return GNUNET_SOCIAL_host_enter (cfg, ego, &place_key, policy, slicer,
-                                   enter_cb, answer_door_cb, farewell_cb, cls);
+  hst->enter_cb = enter_cb;
+  hst->answer_door_cb = answer_door_cb;
+  hst->farewell_cb = farewell_cb;
+  hst->cb_cls = cls;
+
+  plc->cfg = hconn->app->cfg;
+  plc->is_host = GNUNET_YES;
+  plc->slicer = slicer;
+  plc->pub_key = hconn->plc_msg.place_pub_key;
+  plc->ego_pub_key = hconn->plc_msg.ego_pub_key;
+
+  plc->client = GNUNET_CLIENT_MANAGER_connect (plc->cfg, "social", 
host_handlers);
+  GNUNET_CLIENT_MANAGER_set_user_context_ (plc->client, hst, sizeof (*plc));
+
+  plc->tmit = GNUNET_PSYC_transmit_create (plc->client);
+  plc->recv = GNUNET_PSYC_receive_create (NULL, slicer_message, plc->slicer);
+
+  hst->slicer = GNUNET_SOCIAL_slicer_create ();
+  GNUNET_SOCIAL_slicer_method_add (hst->slicer, "_notice_place_leave",
+                                   host_recv_notice_place_leave_method,
+                                   host_recv_notice_place_leave_modifier,
+                                   NULL, host_recv_notice_place_leave_eom, 
hst);
+  hst->recv = GNUNET_PSYC_receive_create (NULL, slicer_message, hst->slicer);
+
+  hreq->header.size = htons (sizeof (*hreq) + app_id_size);
+  hreq->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER);
+  hreq->place_pub_key = hconn->plc_msg.place_pub_key;
+  hreq->ego_pub_key = hconn->plc_msg.ego_pub_key;
+  memcpy (&hreq[1], hconn->app->id, app_id_size);
+
+  plc->connect_msg = &hreq->header;
+  place_send_connect_msg (plc);
+
+  GNUNET_free (hconn);
+  return hst;
 }
 
 
@@ -1759,12 +1920,16 @@
  *        Host of the place.
  * @param nym
  *        Handle for the entity to be ejected.
+ * @param env
+ *        Environment for the message or NULL.
  */
 void
 GNUNET_SOCIAL_host_eject (struct GNUNET_SOCIAL_Host *hst,
-                          const struct GNUNET_SOCIAL_Nym *nym)
+                          const struct GNUNET_SOCIAL_Nym *nym,
+                          struct GNUNET_ENV_Environment *env)
 {
-  struct GNUNET_ENV_Environment *env = GNUNET_ENV_environment_create ();
+  if (NULL == env)
+    env = GNUNET_ENV_environment_create ();
   GNUNET_ENV_environment_add (env, GNUNET_ENV_OP_SET,
                               "_nym", &nym->pub_key, sizeof (nym->pub_key));
   GNUNET_SOCIAL_host_announce (hst, "_notice_place_leave", env, NULL, NULL,
@@ -1773,121 +1938,79 @@
 
 
 /**
- * Get the public key of a @a nym.
+ * Get the public key of @a ego.
  *
- * Suitable, for example, to be used with GNUNET_NAMESTORE_zone_to_name().
+ * @param ego
+ *        Ego.
  *
- * @param nym
- *        Pseudonym to map to a cryptographic identifier.
- *
- * @return Public key of nym.
+ * @return Public key of ego.
  */
 const struct GNUNET_CRYPTO_EcdsaPublicKey *
-GNUNET_SOCIAL_nym_get_key (const struct GNUNET_SOCIAL_Nym *nym)
+GNUNET_SOCIAL_ego_get_pub_key (const struct GNUNET_SOCIAL_Ego *ego)
 {
-  return &nym->pub_key;
+  return &ego->pub_key;
 }
 
 
 /**
- * Get the hash of the public key of a @a nym.
+ * Get the hash of the public key of @a ego.
  *
- * @param nym
- *        Pseudonym to map to a cryptographic identifier.
+ * @param ego
+ *        Ego.
  *
- * @return Hash of the public key of nym.
+ * @return Hash of the public key of @a ego.
  */
 const struct GNUNET_HashCode *
-GNUNET_SOCIAL_nym_get_key_hash (const struct GNUNET_SOCIAL_Nym *nym)
+GNUNET_SOCIAL_ego_get_pub_key_hash (const struct GNUNET_SOCIAL_Ego *ego)
 {
-  return &nym->pub_key_hash;
+  return &ego->pub_key_hash;
 }
 
 
 /**
- * Obtain the private-public key pair of the hosted place.
+ * Get the name of @a ego.
  *
- * The public part is suitable for storing in GNS within a PLACE record,
- * along with peer IDs to join at.
+ * @param ego
+ *        Ego.
  *
- * @param host
- *        Host of the place.
- *
- * @return Private-public key pair of the hosted place.
+ * @return Public key of @a ego.
  */
-const struct GNUNET_CRYPTO_EddsaPrivateKey *
-GNUNET_SOCIAL_host_get_place_key (struct GNUNET_SOCIAL_Host *hst)
+const char *
+GNUNET_SOCIAL_ego_get_name (const struct GNUNET_SOCIAL_Ego *ego)
 {
-  return &hst->place_key;
+  return ego->name;
 }
 
 
 /**
- * Connected to core service.
+ * Get the public key of @a nym.
+ *
+ * Suitable, for example, to be used with GNUNET_SOCIAL_zone_add_nym().
+ *
+ * @param nym
+ *        Pseudonym.
+ *
+ * @return Public key of @a nym.
  */
-static void
-core_connected_cb  (void *cls, const struct GNUNET_PeerIdentity *my_identity)
+const struct GNUNET_CRYPTO_EcdsaPublicKey *
+GNUNET_SOCIAL_nym_get_pub_key (const struct GNUNET_SOCIAL_Nym *nym)
 {
-  this_peer = *my_identity;
-  // FIXME
+  return &nym->pub_key;
 }
 
 
 /**
- * Advertise the place in the GNS zone of the @e ego of the @a host.
+ * Get the hash of the public key of @a nym.
  *
- * @param hst
- *        Host of the place.
- * @param name
- *        The name for the PLACE record to put in the zone.
- * @param peer_count
- *        Number of elements in the @a peers array.
- * @param peers
- *        List of peers to put in the PLACE record to advertise
- *        as entry points to the place in addition to the origin.
- * @param expiration_time
- *        Expiration time of the record, use 0 to remove the record.
- * @param password
- *        Password used to encrypt the record or NULL to keep it cleartext.
- * @param result_cb
- *        Function called with the result of the operation.
- * @param result_cls
- *        Closure for @a result_cb
+ * @param nym
+ *        Pseudonym.
+ *
+ * @return Hash of the public key of @a nym.
  */
-void
-GNUNET_SOCIAL_host_advertise (struct GNUNET_SOCIAL_Host *hst,
-                              const char *name,
-                              uint32_t peer_count,
-                              const struct GNUNET_PeerIdentity *peers,
-                              struct GNUNET_TIME_Absolute expiration_time,
-                              const char *password,
-                              GNUNET_NAMESTORE_ContinuationWithStatus 
result_cb,
-                              void *result_cls)
+const struct GNUNET_HashCode *
+GNUNET_SOCIAL_nym_get_pub_key_hash (const struct GNUNET_SOCIAL_Nym *nym)
 {
-  struct GNUNET_SOCIAL_Place *plc = &hst->plc;
-  if (NULL == namestore)
-    namestore = GNUNET_NAMESTORE_connect (plc->cfg);
-  if (NULL == core)
-    core = GNUNET_CORE_connect (plc->cfg, NULL, core_connected_cb, NULL, NULL,
-                                NULL, GNUNET_NO, NULL, GNUNET_NO, NULL);
-
-  struct GNUNET_GNSRECORD_Data rd = { };
-  rd.record_type = GNUNET_GNSRECORD_TYPE_PLACE;
-  rd.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
-  rd.expiration_time = expiration_time.abs_value_us;
-
-  struct GNUNET_GNSRECORD_PlaceData *
-    rec = GNUNET_malloc (sizeof (*rec) + peer_count * sizeof (*peers));
-  rec->place_key = plc->pub_key;
-  rec->origin = this_peer;
-  rec->relay_count = htonl (peer_count);
-  memcpy (&rec[1], peers, peer_count * sizeof (*peers));
-
-  rd.data = rec;
-  rd.data_size = sizeof (*rec) + peer_count * sizeof (*peers);
-
-  GNUNET_NAMESTORE_records_store (namestore, &hst->plc.ego_key,
-                                  name, 1, &rd, result_cb, result_cls);
+  return &nym->pub_key_hash;
 }
 
 
@@ -1966,30 +2089,77 @@
 }
 
 
+
+void
+place_leave (struct GNUNET_SOCIAL_Place *plc)
+{
+  struct GNUNET_MessageHeader msg;
+  msg.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE);
+  msg.size = htons (sizeof (msg));
+  GNUNET_CLIENT_MANAGER_transmit (plc->client, &msg);
+}
+
+
+void
+place_disconnect (struct GNUNET_SOCIAL_Place *plc,
+                  GNUNET_ContinuationCallback disconnect_cb,
+                  void *disconnect_cls)
+{
+  plc->is_disconnecting = GNUNET_YES;
+  plc->disconnect_cb = disconnect_cb;
+  plc->disconnect_cls = disconnect_cls;
+
+  GNUNET_CLIENT_MANAGER_disconnect (plc->client, GNUNET_YES,
+                                    GNUNET_YES == plc->is_host
+                                    ? host_cleanup : guest_cleanup,
+                                    plc);
+}
+
+
 /**
- * Stop hosting a place.
+ * Disconnect from a home.
  *
  * Invalidates host handle.
  *
- * @param host  Host leaving the place.
- * @param keep_active  Keep the place active after last host disconnected.
+ * @param hst
+ *        The host to disconnect.
  */
 void
-GNUNET_SOCIAL_host_leave (struct GNUNET_SOCIAL_Host *hst,
-                          int keep_active,
-                          GNUNET_ContinuationCallback leave_cb,
-                          void *leave_cls)
+GNUNET_SOCIAL_host_disconnect (struct GNUNET_SOCIAL_Host *hst,
+                               GNUNET_ContinuationCallback disconnect_cb,
+                               void *cls)
 {
-  struct GNUNET_SOCIAL_Place *plc = &hst->plc;
+  place_disconnect (&hst->plc, disconnect_cb, cls);
+}
 
- /* FIXME: send msg to service */
 
-  plc->is_disconnecting = GNUNET_YES;
-  plc->disconnect_cb = leave_cb;
-  plc->disconnect_cls = leave_cls;
-
-  GNUNET_CLIENT_MANAGER_disconnect (plc->client, GNUNET_YES,
-                                    &host_cleanup, hst);
+/**
+ * Stop hosting the home.
+ *
+ * Sends a _notice_place_closed announcement to the home.
+ * Invalidates host handle.
+ *
+ * @param hst
+ *        The host leaving.
+ * @param env
+ *        Environment for the message or NULL.
+ *        _nym is set to @e nym regardless whether an @e env is provided.
+ * @param disconnect_cb
+ *        Function called after the host left the place
+ *        and disconnected from the social service.
+ * @param cls
+ *        Closure for @a disconnect_cb.
+ */
+void
+GNUNET_SOCIAL_host_leave (struct GNUNET_SOCIAL_Host *hst,
+                          const struct GNUNET_ENV_Environment *env,
+                          GNUNET_ContinuationCallback disconnect_cb,
+                          void *cls)
+{
+  GNUNET_SOCIAL_host_announce (hst, "_notice_place_closed", env, NULL, NULL,
+                               GNUNET_SOCIAL_ANNOUNCE_NONE);
+  place_leave (&hst->plc);
+  GNUNET_SOCIAL_host_disconnect (hst, disconnect_cb, cls);
 }
 
 
@@ -1996,35 +2166,40 @@
 /*** GUEST ***/
 
 static struct GuestEnterRequest *
-guest_enter_request_create (const struct GNUNET_CRYPTO_EcdsaPrivateKey 
*guest_key,
-                            const struct GNUNET_CRYPTO_EddsaPublicKey 
*place_key,
+guest_enter_request_create (const char *app_id,
+                            const struct GNUNET_CRYPTO_EcdsaPublicKey 
*ego_pub_key,
+                            const struct GNUNET_CRYPTO_EddsaPublicKey 
*place_pub_key,
                             const struct GNUNET_PeerIdentity *origin,
                             size_t relay_count,
                             const struct GNUNET_PeerIdentity *relays,
                             const struct GNUNET_PSYC_Message *join_msg)
 {
+  uint16_t app_id_size = strlen (app_id) + 1;
   uint16_t join_msg_size = ntohs (join_msg->header.size);
   uint16_t relay_size = relay_count * sizeof (*relays);
 
   struct GuestEnterRequest *
-    req = GNUNET_malloc (sizeof (*req) + relay_size + join_msg_size);
+    greq = GNUNET_malloc (sizeof (*greq) + app_id_size + relay_size + 
join_msg_size);
 
-  req->header.size = htons (sizeof (*req) + relay_size + join_msg_size);
-  req->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER);
-  req->place_key = *place_key;
-  req->guest_key = *guest_key;
-  req->origin = *origin;
-  req->relay_count = htonl (relay_count);
+  greq->header.size = htons (sizeof (*greq) + app_id_size + relay_size + 
join_msg_size);
+  greq->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER);
+  greq->place_pub_key = *place_pub_key;
+  greq->ego_pub_key = *ego_pub_key;
+  greq->origin = *origin;
+  greq->relay_count = htonl (relay_count);
 
-  uint16_t p = sizeof (*req);
+  char *p = (char *) &greq[1];
+  memcpy (p, app_id, app_id_size);
+  p += app_id_size;
+
   if (0 < relay_size)
   {
-    memcpy ((char *) req + p, relays, relay_size);
+    memcpy (p, relays, relay_size);
     p += relay_size;
   }
 
-  memcpy ((char *) req + p, join_msg, join_msg_size);
-  return req;
+  memcpy (p, join_msg, join_msg_size);
+  return greq;
 }
 
 /**
@@ -2045,13 +2220,13 @@
  * @return NULL on errors, otherwise handle for the guest.
  */
 struct GNUNET_SOCIAL_Guest *
-GNUNET_SOCIAL_guest_enter (const struct GNUNET_CONFIGURATION_Handle *cfg,
-                           const struct GNUNET_IDENTITY_Ego *ego,
-                           const struct GNUNET_CRYPTO_EddsaPublicKey 
*place_key,
+GNUNET_SOCIAL_guest_enter (const struct GNUNET_SOCIAL_App *app,
+                           const struct GNUNET_SOCIAL_Ego *ego,
+                           const struct GNUNET_CRYPTO_EddsaPublicKey 
*place_pub_key,
                            const struct GNUNET_PeerIdentity *origin,
                            uint32_t relay_count,
                            const struct GNUNET_PeerIdentity *relays,
-                           const struct GNUNET_PSYC_Message *join_msg,
+                           const struct GNUNET_PSYC_Message *entry_msg,
                            struct GNUNET_SOCIAL_Slicer *slicer,
                            GNUNET_SOCIAL_GuestEnterCallback local_enter_cb,
                            GNUNET_SOCIAL_EntryDecisionCallback entry_dcsn_cb,
@@ -2060,9 +2235,9 @@
   struct GNUNET_SOCIAL_Guest *gst = GNUNET_malloc (sizeof (*gst));
   struct GNUNET_SOCIAL_Place *plc = &gst->plc;
 
-  plc->ego_key = *GNUNET_IDENTITY_ego_get_private_key (ego);
-  plc->pub_key = *place_key;
-  plc->cfg = cfg;
+  plc->ego_pub_key = ego->pub_key;
+  plc->pub_key = *place_pub_key;
+  plc->cfg = app->cfg;
   plc->is_host = GNUNET_YES;
   plc->slicer = slicer;
 
@@ -2070,7 +2245,7 @@
   gst->entry_dcsn_cb = entry_dcsn_cb;
   gst->cb_cls = cls;
 
-  plc->client = GNUNET_CLIENT_MANAGER_connect (cfg, "social", guest_handlers);
+  plc->client = GNUNET_CLIENT_MANAGER_connect (plc->cfg, "social", 
guest_handlers);
   GNUNET_CLIENT_MANAGER_set_user_context_ (plc->client, gst, sizeof (*plc));
 
   plc->tmit = GNUNET_PSYC_transmit_create (plc->client);
@@ -2077,9 +2252,9 @@
   plc->recv = GNUNET_PSYC_receive_create (NULL, slicer_message, plc->slicer);
 
   struct GuestEnterRequest *
-    req = guest_enter_request_create (&plc->ego_key, place_key, origin,
-                                      relay_count, relays, join_msg);
-  plc->connect_msg = &req->header;
+    greq = guest_enter_request_create (app->id, &ego->pub_key, &plc->pub_key,
+                                       origin, relay_count, relays, entry_msg);
+  plc->connect_msg = &greq->header;
   place_send_connect_msg (plc);
   return gst;
 }
@@ -2086,70 +2261,6 @@
 
 
 /**
- * Result of a GNS name lookup for entering a place.
- *
- * @see GNUNET_SOCIAL_guest_enter_by_name
- */
-static void
-gns_result_guest_enter (void *cls, uint32_t rd_count,
-                        const struct GNUNET_GNSRECORD_Data *rd)
-{
-  struct GNUNET_SOCIAL_Guest *gst = cls;
-  struct GNUNET_SOCIAL_Place *plc = &gst->plc;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-              "%p GNS result: %u records.\n", gst, rd_count);
-
-  const struct GNUNET_GNSRECORD_PlaceData *
-    rec = (const struct GNUNET_GNSRECORD_PlaceData *) rd->data;
-
-  if (0 == rd_count)
-  {
-    if (NULL != gst->enter_cb)
-      gst->enter_cb (gst->cb_cls, GNUNET_SYSERR, 0);
-    return;
-  }
-
-  if (rd->data_size < sizeof (*rec))
-  {
-    GNUNET_break_op (0);
-    if (NULL != gst->enter_cb)
-      gst->enter_cb (gst->cb_cls, GNUNET_SYSERR, 0);
-    return;
-  }
-
-  uint16_t relay_count = ntohl (rec->relay_count);
-  struct GNUNET_PeerIdentity *relays = NULL;
-
-  if (0 < relay_count)
-  {
-    if (rd->data_size == sizeof (*rec) + relay_count * sizeof (struct 
GNUNET_PeerIdentity))
-    {
-      relays = (struct GNUNET_PeerIdentity *) &rec[1];
-    }
-    else
-    {
-      relay_count = 0;
-      GNUNET_break_op (0);
-    }
-  }
-
-  struct GuestEnterRequest *
-    req = guest_enter_request_create (&plc->ego_key, &rec->place_key,
-                                      &rec->origin, relay_count, relays,
-                                      (struct GNUNET_PSYC_Message *) 
plc->connect_msg);
-  GNUNET_free (plc->connect_msg);
-  plc->connect_msg = &req->header;
-  plc->pub_key = req->place_key;
-
-  plc->tmit = GNUNET_PSYC_transmit_create (plc->client);
-  plc->recv = GNUNET_PSYC_receive_create (NULL, slicer_message, plc->slicer);
-
-  place_send_connect_msg (plc);
-}
-
-
-/**
  * Request entry to a place by name as a guest.
  *
  * @param cfg
@@ -2165,7 +2276,7 @@
  * @param password
  *        Password to decrypt the record, or NULL for cleartext records.
  * @param join_msg
- *        Entry request message.
+ *        Entry request message or NULL.
  * @param slicer
  *        Slicer to use for processing incoming requests from guests.
  * @param local_enter_cb
@@ -2176,9 +2287,10 @@
  * @return NULL on errors, otherwise handle for the guest.
  */
 struct GNUNET_SOCIAL_Guest *
-GNUNET_SOCIAL_guest_enter_by_name (const struct GNUNET_CONFIGURATION_Handle 
*cfg,
-                                   const struct GNUNET_IDENTITY_Ego *ego,
-                                   const char *gns_name, const char *password,
+GNUNET_SOCIAL_guest_enter_by_name (const struct GNUNET_SOCIAL_App *app,
+                                   const struct GNUNET_SOCIAL_Ego *ego,
+                                   const char *gns_name,
+                                   const char *password,
                                    const struct GNUNET_PSYC_Message *join_msg,
                                    struct GNUNET_SOCIAL_Slicer *slicer,
                                    GNUNET_SOCIAL_GuestEnterCallback 
local_enter_cb,
@@ -2188,32 +2300,109 @@
   struct GNUNET_SOCIAL_Guest *gst = GNUNET_malloc (sizeof (*gst));
   struct GNUNET_SOCIAL_Place *plc = &gst->plc;
 
-  GNUNET_assert (NULL != join_msg);
+  if (NULL == password)
+    password = "";
 
+  uint16_t app_id_size = strlen (app->id) + 1;
+  uint16_t gns_name_size = strlen (gns_name) + 1;
+  uint16_t password_size = strlen (password) + 1;
+
+  uint16_t join_msg_size = 0;
+  if (NULL != join_msg);
+    join_msg_size = ntohs (join_msg->header.size);
+
+  uint16_t greq_size = sizeof (struct GuestEnterByNameRequest)
+    + app_id_size + gns_name_size + password_size + join_msg_size;
+  struct GuestEnterByNameRequest *greq = GNUNET_malloc (greq_size);
+  greq->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_BY_NAME);
+  greq->header.size = htons (greq_size);
+  greq->ego_pub_key = ego->pub_key;
+
+  char *p = (char *) &greq[1];
+  memcpy (p, app->id, app_id_size);
+  p += app_id_size;
+  memcpy (p, gns_name, gns_name_size);
+  p += gns_name_size;
+  memcpy (p, password, password_size);
+  p += password_size;
+  if (NULL != join_msg)
+    memcpy (p, join_msg, join_msg_size);
+
   gst->enter_cb = local_enter_cb;
   gst->entry_dcsn_cb = entry_decision_cb;
   gst->cb_cls = cls;
 
-  plc->ego_key = *GNUNET_IDENTITY_ego_get_private_key (ego);
-  plc->cfg = cfg;
+  plc->ego_pub_key = ego->pub_key;
+  plc->cfg = app->cfg;
   plc->is_host = GNUNET_NO;
   plc->slicer = slicer;
 
-  uint16_t join_msg_size = ntohs (join_msg->header.size);
-  plc->connect_msg = GNUNET_malloc (join_msg_size);
-  memcpy (plc->connect_msg, join_msg, join_msg_size);
+  plc->client = GNUNET_CLIENT_MANAGER_connect (app->cfg, "social", 
guest_handlers);
+  GNUNET_CLIENT_MANAGER_set_user_context_ (plc->client, gst, sizeof (*plc));
 
-  if (NULL == gns)
-    gns = GNUNET_GNS_connect (cfg);
+  plc->tmit = GNUNET_PSYC_transmit_create (plc->client);
+  plc->recv = GNUNET_PSYC_receive_create (NULL, slicer_message, plc->slicer);
 
-  plc->client = GNUNET_CLIENT_MANAGER_connect (cfg, "social", guest_handlers);
+  plc->connect_msg = &greq->header;
+  place_send_connect_msg (plc);
+
+  return gst;
+}
+
+
+/**
+ * Reconnect to an already entered place as guest.
+ *
+ * @param gconn
+ *        Guest connection handle.
+ *        @see GNUNET_SOCIAL_app_connect() & 
GNUNET_SOCIAL_AppGuestPlaceCallback()
+ * @param slicer
+ *        Slicer to use for processing incoming requests from guests.
+ * @param local_enter_cb
+ *        Called upon connection established to the social service.
+ * @param entry_decision_cb
+ *        Called upon receiving entry decision.
+ *
+ * @return NULL on errors, otherwise handle for the guest.
+ */
+struct GNUNET_SOCIAL_Guest *
+GNUNET_SOCIAL_guest_enter_reconnect (struct GNUNET_SOCIAL_GuestConnection 
*gconn,
+                                     struct GNUNET_SOCIAL_Slicer *slicer,
+                                     GNUNET_SOCIAL_GuestEnterCallback 
local_enter_cb,
+                                     void *cls)
+{
+  struct GNUNET_SOCIAL_Guest *gst = GNUNET_malloc (sizeof (*gst));
+  struct GNUNET_SOCIAL_Place *plc = &gst->plc;
+
+  uint16_t app_id_size = strlen (gconn->app->id) + 1;
+  uint16_t greq_size = sizeof (struct GuestEnterRequest) + app_id_size;
+  struct GuestEnterRequest *greq = GNUNET_malloc (greq_size);
+  greq->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER);
+  greq->header.size = htons (greq_size);
+  greq->ego_pub_key = gconn->plc_msg.ego_pub_key;
+  greq->place_pub_key = gconn->plc_msg.place_pub_key;
+
+  memcpy (&greq[1], gconn->app->id, app_id_size);
+
+  gst->enter_cb = local_enter_cb;
+  gst->cb_cls = cls;
+
+  plc->cfg = gconn->app->cfg;
+  plc->is_host = GNUNET_NO;
+  plc->slicer = slicer;
+  plc->pub_key = gconn->plc_msg.place_pub_key;
+  plc->ego_pub_key = gconn->plc_msg.ego_pub_key;
+
+  plc->client = GNUNET_CLIENT_MANAGER_connect (plc->cfg, "social", 
guest_handlers);
   GNUNET_CLIENT_MANAGER_set_user_context_ (plc->client, gst, sizeof (*plc));
 
-  struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
-  GNUNET_IDENTITY_ego_get_public_key (ego, &ego_pub_key);
-  GNUNET_GNS_lookup (gns, gns_name, &ego_pub_key,
-                     GNUNET_GNSRECORD_TYPE_PLACE, GNUNET_GNS_LO_DEFAULT,
-                     NULL, gns_result_guest_enter, gst);
+  plc->tmit = GNUNET_PSYC_transmit_create (plc->client);
+  plc->recv = GNUNET_PSYC_receive_create (NULL, slicer_message, plc->slicer);
+
+  plc->connect_msg = &greq->header;
+  place_send_connect_msg (plc);
+
+  GNUNET_free (gconn);
   return gst;
 }
 
@@ -2284,6 +2473,23 @@
 
 
 /**
+ * Disconnect from a place.
+ *
+ * Invalidates guest handle.
+ *
+ * @param gst
+ *        The guest to disconnect.
+ */
+void
+GNUNET_SOCIAL_guest_disconnect (struct GNUNET_SOCIAL_Guest *gst,
+                                GNUNET_ContinuationCallback disconnect_cb,
+                                void *cls)
+{
+  place_disconnect (&gst->plc, disconnect_cb, cls);
+}
+
+
+/**
  * Leave a place temporarily or permanently.
  *
  * Notifies the owner of the place about leaving, and destroys the place 
handle.
@@ -2301,28 +2507,14 @@
  */
 void
 GNUNET_SOCIAL_guest_leave (struct GNUNET_SOCIAL_Guest *gst,
-                           int keep_active,
                            struct GNUNET_ENV_Environment *env,
-                           GNUNET_ContinuationCallback leave_cb,
-                           void *leave_cls)
+                           GNUNET_ContinuationCallback disconnect_cb,
+                           void *cls)
 {
-  struct GNUNET_SOCIAL_Place *plc = &gst->plc;
-
-  plc->is_disconnecting = GNUNET_YES;
-  plc->disconnect_cb = leave_cb;
-  plc->disconnect_cls = leave_cls;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-              "Guest: leaving place.\n");
-
-  if (GNUNET_NO == keep_active && NULL != plc->tmit)
-  {
-    GNUNET_SOCIAL_guest_talk (gst, "_notice_place_leave", env, NULL, NULL,
-                              GNUNET_SOCIAL_TALK_NONE);
-  }
-
-  GNUNET_CLIENT_MANAGER_disconnect (plc->client, GNUNET_YES,
-                                    &guest_cleanup, gst);
+  GNUNET_SOCIAL_guest_talk (gst, "_notice_place_leave", env, NULL, NULL,
+                            GNUNET_SOCIAL_TALK_NONE);
+  place_leave (&gst->plc);
+  GNUNET_SOCIAL_guest_disconnect (gst, disconnect_cb, cls);
 }
 
 
@@ -2342,6 +2534,21 @@
 }
 
 
+/**
+ * Obtain the public key of a place.
+ *
+ * @param plc
+ *        Place.
+ *
+ * @return Public key of the place.
+ */
+const struct GNUNET_CRYPTO_EddsaPublicKey *
+GNUNET_SOCIAL_place_get_key (struct GNUNET_SOCIAL_Place *plc)
+{
+  return &plc->pub_key;
+}
+
+
 static struct GNUNET_SOCIAL_HistoryRequest *
 place_history_replay (struct GNUNET_SOCIAL_Place *plc,
                       uint64_t start_message_id,
@@ -2571,9 +2778,120 @@
 }
 
 
+static void
+op_recv_zone_add_place_result (void *cls, int64_t result,
+                               const void *err_msg, uint16_t err_msg_size)
+{
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received zone add place result: %" PRId64 ".\n", result);
+
+  struct ZoneAddPlaceHandle *add_plc = cls;
+  if (NULL != add_plc->result_cb)
+    add_plc->result_cb (add_plc->result_cls, result, err_msg, err_msg_size);
+
+  GNUNET_free (add_plc->req);
+  GNUNET_free (add_plc);
+}
+
+
 /**
- * Add public key to the GNS zone of the @e ego.
+ * Advertise @e place in the GNS zone of @e ego.
  *
+ * @param app
+ *        Application handle.
+ * @param ego
+ *        Ego.
+ * @param place_pub_key
+ *        Public key of place to add.
+ * @param name
+ *        The name for the PLACE record to put in the zone.
+ * @param password
+ *        Password used to encrypt the record or NULL to keep it cleartext.
+ * @param relay_count
+ *        Number of elements in the @a relays array.
+ * @param relays
+ *        List of relays to put in the PLACE record to advertise
+ *        as entry points to the place in addition to the origin.
+ * @param expiration_time
+ *        Expiration time of the record, use 0 to remove the record.
+ * @param result_cb
+ *        Function called with the result of the operation.
+ * @param result_cls
+ *        Closure for @a result_cb
+ *
+ * @return #GNUNET_OK if the request was sent,
+ *         #GNUNET_SYSERR on error, e.g. the name/password is too long.
+ */
+int
+GNUNET_SOCIAL_zone_add_place (const struct GNUNET_SOCIAL_App *app,
+                              const struct GNUNET_SOCIAL_Ego *ego,
+                              const char *name,
+                              const char *password,
+                              const struct GNUNET_CRYPTO_EddsaPublicKey 
*place_pub_key,
+                              const struct GNUNET_PeerIdentity *origin,
+                              uint32_t relay_count,
+                              const struct GNUNET_PeerIdentity *relays,
+                              struct GNUNET_TIME_Absolute expiration_time,
+                              GNUNET_ResultCallback result_cb,
+                              void *result_cls)
+{
+  struct ZoneAddPlaceRequest *preq;
+  size_t name_size = strlen (name) + 1;
+  size_t password_size = strlen (password) + 1;
+  size_t relay_size = relay_count * sizeof (*relays);
+  size_t preq_size = sizeof (*preq) + name_size + password_size + relay_size;
+
+  if (GNUNET_SERVER_MAX_MESSAGE_SIZE < preq_size)
+    return GNUNET_SYSERR;
+
+  preq = GNUNET_malloc (preq_size);
+  preq->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_PLACE);
+  preq->header.size = htons (preq_size);
+  preq->expiration_time = GNUNET_htonll (expiration_time.abs_value_us);
+  preq->ego_pub_key = ego->pub_key;
+  preq->place_pub_key = *place_pub_key;
+  preq->origin = *origin;
+  preq->relay_count = htonl (relay_count);
+
+  char *p = (char *) &preq[1];
+  memcpy (p, name, name_size);
+  p += name_size;
+  memcpy (p, password, password_size);
+  p += password_size;
+  memcpy (p, relays, relay_size);
+
+  struct ZoneAddPlaceHandle * add_plc = GNUNET_malloc (sizeof (*add_plc));
+  add_plc->req = preq;
+  add_plc->result_cb = result_cb;
+  add_plc->result_cls = result_cls;
+
+  preq->op_id = GNUNET_htonll (GNUNET_CLIENT_MANAGER_op_add (app->client,
+                                                             
op_recv_zone_add_place_result,
+                                                             add_plc));
+  GNUNET_CLIENT_MANAGER_transmit_now (app->client, &preq->header);
+  return GNUNET_OK;
+}
+
+
+static void
+op_recv_zone_add_nym_result (void *cls, int64_t result,
+                             const void *err_msg, uint16_t err_msg_size)
+{
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received zone add nym result: %" PRId64 ".\n", result);
+
+  struct ZoneAddNymHandle *add_nym = cls;
+  if (NULL != add_nym->result_cb)
+    add_nym->result_cb (add_nym->result_cls, result, err_msg, err_msg_size);
+
+  GNUNET_free (add_nym->req);
+  GNUNET_free (add_nym);
+}
+
+
+/**
+ * Add nym to the GNS zone of @e ego.
+ *
  * @param cfg
  *        Configuration.
  * @param ego
@@ -2588,43 +2906,57 @@
  *        Function called with the result of the operation.
  * @param result_cls
  *        Closure for @a result_cb
+ *
+ * @return #GNUNET_OK if the request was sent,
+ *         #GNUNET_SYSERR on error, e.g. the name is too long.
  */
-void
-GNUNET_SOCIAL_zone_add_pkey (const struct GNUNET_CONFIGURATION_Handle *cfg,
-                             const struct GNUNET_IDENTITY_Ego *ego,
-                             const char *name,
-                             const struct GNUNET_CRYPTO_EcdsaPublicKey 
*nym_pub_key,
-                             struct GNUNET_TIME_Absolute expiration_time,
-                             GNUNET_NAMESTORE_ContinuationWithStatus result_cb,
-                             void *result_cls)
+int
+GNUNET_SOCIAL_zone_add_nym (const struct GNUNET_SOCIAL_App *app,
+                            const struct GNUNET_SOCIAL_Ego *ego,
+                            const char *name,
+                            const struct GNUNET_CRYPTO_EcdsaPublicKey 
*nym_pub_key,
+                            struct GNUNET_TIME_Absolute expiration_time,
+                            GNUNET_ResultCallback result_cb,
+                            void *result_cls)
 {
-  if (NULL == namestore)
-    namestore = GNUNET_NAMESTORE_connect (cfg);
+  struct ZoneAddNymRequest *nreq;
 
-  struct GNUNET_GNSRECORD_Data rd = { };
-  rd.record_type = GNUNET_GNSRECORD_TYPE_PKEY;
-  rd.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
-  rd.expiration_time = expiration_time.abs_value_us;
-  rd.data = nym_pub_key;
-  rd.data_size = sizeof (*nym_pub_key);
+  size_t name_size = strlen (name) + 1;
+  if (GNUNET_SERVER_MAX_MESSAGE_SIZE < sizeof (*nreq) + name_size)
+    return GNUNET_SYSERR;
 
-  GNUNET_NAMESTORE_records_store (namestore,
-                                  GNUNET_IDENTITY_ego_get_private_key (ego),
-                                  name, 1, &rd, result_cb, result_cls);
+  nreq = GNUNET_malloc (sizeof (*nreq) + name_size);
+  nreq->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_NYM);
+  nreq->header.size = htons (sizeof (*nreq) + name_size);
+  nreq->expiration_time = GNUNET_htonll (expiration_time.abs_value_us);
+  nreq->ego_pub_key = ego->pub_key;
+  nreq->nym_pub_key = *nym_pub_key;
+  memcpy (&nreq[1], name, name_size);
+
+  struct ZoneAddNymHandle * add_nym = GNUNET_malloc (sizeof (*add_nym));
+  add_nym->req = nreq;
+  add_nym->result_cb = result_cb;
+  add_nym->result_cls = result_cls;
+
+  nreq->op_id = GNUNET_htonll (GNUNET_CLIENT_MANAGER_op_add (app->client,
+                                                             
op_recv_zone_add_nym_result,
+                                                             add_nym));
+  GNUNET_CLIENT_MANAGER_transmit_now (app->client, &nreq->header);
+  return GNUNET_OK;
 }
 
 
 /**
- * Start listening for entered places as host or guest.
+ * Connect application to the social service.
  *
- * The @notify_host and @notify_guest functions are
- * initially called with the full list of entered places,
- * then later each time a new place is entered.
+ * The @host_place_cb and @guest_place_cb functions are
+ * initially called for each entered places,
+ * then later each time a new place is entered with the current application ID.
  *
  * @param cfg
  *        Configuration.
- * @param ego
- *        Listen for places of this ego.
+ * @param id
+ *        Application ID.
  * @param notify_host
  *        Function to notify about a place entered as host.
  * @param notify_guest
@@ -2634,48 +2966,81 @@
  *
  * @return Handle that can be used to stop listening.
  */
-struct GNUNET_SOCIAL_PlaceListenHandle *
-GNUNET_SOCIAL_place_listen_start (const struct GNUNET_CONFIGURATION_Handle 
*cfg,
-                                  const struct GNUNET_IDENTITY_Ego *ego,
-                                  GNUNET_SOCIAL_PlaceNotifyHostCallback 
notify_host,
-                                  GNUNET_SOCIAL_PlaceNotifyGuestCallback 
notify_guest,
-                                  void *notify_cls)
+struct GNUNET_SOCIAL_App *
+GNUNET_SOCIAL_app_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
+                           const char *id,
+                           GNUNET_SOCIAL_AppEgoCallback ego_cb,
+                           GNUNET_SOCIAL_AppHostPlaceCallback host_cb,
+                           GNUNET_SOCIAL_AppGuestPlaceCallback guest_cb,
+                           void *cls)
 {
-  struct GNUNET_SOCIAL_PlaceListenHandle *pl = GNUNET_malloc (sizeof *pl);
-  pl->notify_host = notify_host;
-  pl->notify_guest = notify_guest;
-  pl->notify_cls = notify_cls;
+  uint16_t app_id_size = strnlen (id, GNUNET_SOCIAL_APP_MAX_ID_SIZE);
+  if (GNUNET_SOCIAL_APP_MAX_ID_SIZE == app_id_size)
+    return NULL;
+  app_id_size++;
 
-  struct GNUNET_SOCIAL_Place *plc = &pl->plc;
+  struct GNUNET_SOCIAL_App *app = GNUNET_malloc (sizeof *app);
+  app->cfg = cfg;
+  app->ego_cb = ego_cb;
+  app->host_cb = host_cb;
+  app->guest_cb = guest_cb;
+  app->cb_cls = cls;
+  app->egos = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
+  app->client = GNUNET_CLIENT_MANAGER_connect (cfg, "social",
+                                               app_handlers);
+  GNUNET_CLIENT_MANAGER_set_user_context_ (app->client, app, sizeof (*app));
 
-  plc->ego_key = *GNUNET_IDENTITY_ego_get_private_key (ego);
-  plc->cfg = cfg;
-  plc->client = GNUNET_CLIENT_MANAGER_connect (cfg, "social",
-                                               notify_handlers);
-  GNUNET_CLIENT_MANAGER_set_user_context_ (plc->client, pl, sizeof (*pl));
+  app->id = GNUNET_malloc (app_id_size);
+  memcpy (app->id, id, app_id_size);
 
-  struct PlaceListenRequest *req = GNUNET_malloc (sizeof (*req));
-  req->ego_key = plc->ego_key;
-  req->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LISTEN);
-  req->header.size = htons (sizeof (*req));
+  struct AppConnectRequest *creq = GNUNET_malloc (sizeof (*creq) + 
app_id_size);
+  creq->header.size = htons (sizeof (*creq) + app_id_size);
+  creq->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_APP_CONNECT);
+  memcpy (&creq[1], app->id, app_id_size);
 
-  plc->connect_msg = (struct GNUNET_MessageHeader *) req;
-  place_send_connect_msg (plc);
+  app->connect_msg = &creq->header;
+  app_send_connect_msg (app);
 
-  return pl;
+  return app;
 }
 
 
 /**
- * Stop listening for entered places.
+ * Disconnect application.
  *
- * @param pl
- *        Place listen handle.
+ * @param app
+ *        Application handle.
  */
 void
-GNUNET_SOCIAL_place_listen_stop (struct GNUNET_SOCIAL_PlaceListenHandle *pl)
+GNUNET_SOCIAL_app_disconnect (struct GNUNET_SOCIAL_App *app)
 {
-  GNUNET_CLIENT_MANAGER_disconnect (pl->plc.client, GNUNET_NO, NULL, NULL);
+  GNUNET_CLIENT_MANAGER_disconnect (app->client, GNUNET_NO, NULL, NULL);
 }
 
+
+/**
+ * Detach application from a place.
+ *
+ * Removes the place from the entered places list for this application.
+ * Note: this does not disconnect from the place.
+ *
+ * @see GNUNET_SOCIAL_host_disconnect() and GNUNET_SOCIAL_guest_disconnect()
+ *
+ * @param app
+ *        Application.
+ * @param plc
+ *        Place.
+ */
+void
+GNUNET_SOCIAL_app_detach (struct GNUNET_SOCIAL_App *app,
+                          struct GNUNET_SOCIAL_Place *plc)
+{
+  struct AppDetachRequest dreq;
+  dreq.header.size = htons (sizeof (dreq));
+  dreq.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_APP_DETACH);
+  dreq.place_pub_key = plc->pub_key;
+  GNUNET_CLIENT_MANAGER_transmit_now (plc->client, &dreq.header);
+}
+
+
 /* end of social_api.c */

Modified: gnunet/src/social/test_social.c
===================================================================
--- gnunet/src/social/test_social.c     2015-12-16 17:43:13 UTC (rev 36766)
+++ gnunet/src/social/test_social.c     2015-12-17 14:12:44 UTC (rev 36767)
@@ -45,6 +45,9 @@
  */
 int res;
 
+struct GNUNET_SOCIAL_App *app;
+const char *app_id = "test";
+
 /**
  * Handle for task for timeout termination.
  */
@@ -57,8 +60,8 @@
 
 struct GNUNET_IDENTITY_Handle *id;
 
-const struct GNUNET_IDENTITY_Ego *host_ego;
-const struct GNUNET_IDENTITY_Ego *guest_ego;
+const struct GNUNET_SOCIAL_Ego *host_ego;
+const struct GNUNET_SOCIAL_Ego *guest_ego;
 
 const char *host_name = "Host One";
 const char *guest_name = "Guest One";
@@ -67,6 +70,8 @@
 struct GNUNET_CRYPTO_EcdsaPrivateKey *guest_key;
 
 struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key;
+struct GNUNET_HashCode place_pub_hash;
+
 struct GNUNET_CRYPTO_EcdsaPublicKey guest_pub_key;
 struct GNUNET_CRYPTO_EcdsaPublicKey host_pub_key;
 
@@ -111,32 +116,57 @@
 
 uint32_t counter;
 
-uint8_t guest_pkey_added = GNUNET_NO;
+uint8_t is_guest_nym_added = GNUNET_NO;
+uint8_t is_host_reconnected = GNUNET_NO;
+uint8_t is_guest_reconnected = GNUNET_NO;
 
 enum
 {
-  TEST_NONE = 0,
-  TEST_HOST_ANSWER_DOOR_REFUSE      =  1,
-  TEST_GUEST_RECV_ENTRY_DCSN_REFUSE =  2,
-  TEST_HOST_ANSWER_DOOR_ADMIT       =  3,
-  TEST_GUEST_RECV_ENTRY_DCSN_ADMIT  =  4,
-  TEST_HOST_ANNOUNCE                       =  5,
-  TEST_HOST_ANNOUNCE_END            =  6,
-  TEST_HOST_ANNOUNCE2                      =  7,
-  TEST_HOST_ANNOUNCE2_END           =  8,
-  TEST_GUEST_TALK                   =  9,
-  TEST_GUEST_HISTORY_REPLAY         = 10,
-  TEST_GUEST_HISTORY_REPLAY_LATEST  = 11,
-  TEST_GUEST_LOOK_AT                = 12,
-  TEST_GUEST_LOOK_FOR               = 13,
-  TEST_GUEST_LEAVE                  = 14,
-  TEST_HOST_ADVERTISE               = 15,
-  TEST_GUEST_ENTER_BY_NAME          = 16,
-  TEST_HOST_LEAVE                   = 17,
+  TEST_NONE                         =  0,
+  TEST_HOST_CREATE                  =  1,
+  TEST_HOST_ENTER                   =  2,
+  TEST_GUEST_CREATE                 =  3,
+  TEST_GUEST_ENTER                  =  4,
+  TEST_HOST_ANSWER_DOOR_REFUSE      =  5,
+  TEST_GUEST_RECV_ENTRY_DCSN_REFUSE =  6,
+  TEST_HOST_ANSWER_DOOR_ADMIT       =  7,
+  TEST_GUEST_RECV_ENTRY_DCSN_ADMIT  =  8,
+  TEST_HOST_ANNOUNCE                       =  9,
+  TEST_HOST_ANNOUNCE_END            = 10,
+  TEST_HOST_ANNOUNCE2                      = 11,
+  TEST_HOST_ANNOUNCE2_END           = 12,
+  TEST_GUEST_TALK                   = 13,
+  TEST_GUEST_HISTORY_REPLAY         = 14,
+  TEST_GUEST_HISTORY_REPLAY_LATEST  = 15,
+  TEST_GUEST_LOOK_AT                = 16,
+  TEST_GUEST_LOOK_FOR               = 17,
+  TEST_GUEST_LEAVE                  = 18,
+  TEST_ZONE_ADD_PLACE               = 19,
+  TEST_GUEST_ENTER_BY_NAME          = 20,
+  TEST_RECONNECT                    = 21,
+  TEST_GUEST_LEAVE2                 = 22,
+  TEST_HOST_LEAVE                   = 23,
 } test;
 
 
 static void
+schedule_guest_leave (void *cls, const struct GNUNET_SCHEDULER_TaskContext 
*tc);
+
+static void
+host_answer_door (void *cls,
+                  struct GNUNET_SOCIAL_Nym *nym,
+                  const char *method_name,
+                  struct GNUNET_ENV_Environment *env,
+                  size_t data_size,
+                  const void *data);
+
+static void
+host_enter ();
+
+static void
+guest_init ();
+
+static void
 guest_enter ();
 
 static void
@@ -167,18 +197,31 @@
     id = NULL;
   }
 
+  if (NULL != guest_slicer)
+  {
+    GNUNET_SOCIAL_slicer_destroy (guest_slicer);
+    guest_slicer = NULL;
+  }
+
+  if (NULL != host_slicer)
+  {
+    GNUNET_SOCIAL_slicer_destroy (host_slicer);
+    host_slicer = NULL;
+  }
+
   if (NULL != gst)
   {
-    GNUNET_SOCIAL_guest_leave (gst, GNUNET_NO, NULL, NULL, NULL);
+    GNUNET_SOCIAL_guest_leave (gst, NULL, NULL, NULL);
     gst = NULL;
     gst_plc = NULL;
   }
   if (NULL != hst)
   {
-    GNUNET_SOCIAL_host_leave (hst, GNUNET_NO, NULL, NULL);
+    GNUNET_SOCIAL_host_leave (hst, NULL, NULL, NULL);
     hst = NULL;
     hst_plc = NULL;
   }
+  GNUNET_SOCIAL_app_disconnect (app);
   GNUNET_SCHEDULER_shutdown ();
 }
 
@@ -295,58 +338,186 @@
 {
   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
               "The host has left the place.\n");
-  GNUNET_SOCIAL_slicer_destroy (host_slicer);
-  host_slicer = NULL;
+  end ();
+}
+
+
+static void
+schedule_host_leave (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  test = TEST_HOST_LEAVE;
+  GNUNET_SOCIAL_host_leave (hst, NULL, &host_left, NULL);
   hst = NULL;
   hst_plc = NULL;
+}
 
-  // TODO: GNUNET_SOCIAL_place_listen_start ()
 
-  end ();
+static void
+host_farewell2 (void *cls,
+               const struct GNUNET_SOCIAL_Nym *nym,
+               struct GNUNET_ENV_Environment *env)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+              "Nym left the place again.\n");
+  GNUNET_SCHEDULER_add_now (schedule_host_leave, NULL);
 }
 
 
 static void
-schedule_host_leave (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+host_reconnected (void *cls, int result,
+              const struct GNUNET_CRYPTO_EddsaPublicKey *home_pub_key,
+              uint64_t max_message_id)
 {
-  test = TEST_HOST_LEAVE;
-  GNUNET_SOCIAL_host_leave (hst, GNUNET_NO, &host_left, NULL);
+  place_pub_key = *home_pub_key;
+  GNUNET_CRYPTO_hash (&place_pub_key, sizeof (place_pub_key), &place_pub_hash);
+  GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+              "Test #%u: Host reconnected to place %s\n",
+              test, GNUNET_h2s (&place_pub_hash));
+
+  is_host_reconnected = GNUNET_YES;
+  if (GNUNET_YES == is_guest_reconnected)
+  {
+    GNUNET_SCHEDULER_add_now (schedule_guest_leave, NULL);
+  }
 }
 
 
 static void
-id_guest_ego_cb2 (void *cls, const struct GNUNET_IDENTITY_Ego *ego)
+guest_reconnected (void *cls, int result, uint64_t max_message_id)
 {
-  GNUNET_assert (NULL != ego);
-  guest_ego = ego;
+  GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+              "Test #%u: Guest reconnected to place: %d\n",
+              test, result);
+  GNUNET_assert (0 <= result);
 
-  guest_enter_by_name ();
+  is_guest_reconnected = GNUNET_YES;
+  if (GNUNET_YES == is_host_reconnected)
+  {
+    GNUNET_SCHEDULER_add_now (schedule_guest_leave, NULL);
+  }
 }
 
 
 static void
-host_recv_advertise_result (void *cls, int32_t success, const char *emsg)
+app_recv_host (void *cls,
+               struct GNUNET_SOCIAL_HostConnection *hconn,
+               struct GNUNET_SOCIAL_Ego *ego,
+               const struct GNUNET_CRYPTO_EddsaPublicKey *host_pub_key)
 {
+  struct GNUNET_HashCode host_pub_hash;
+  GNUNET_CRYPTO_hash (host_pub_key, sizeof (*host_pub_key), &host_pub_hash);
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Got app host place notification: %s\n",
+              GNUNET_h2s (&host_pub_hash));
+
+  if (test == TEST_RECONNECT)
+  {
+    if (0 == memcmp (&place_pub_key, host_pub_key, sizeof (*host_pub_key)))
+    {
+      hst = GNUNET_SOCIAL_host_enter_reconnect (hconn, host_slicer, 
host_reconnected,
+                                                host_answer_door, 
host_farewell2, NULL);
+    }
+  }
+}
+
+
+static void
+app_recv_guest (void *cls,
+               struct GNUNET_SOCIAL_GuestConnection *gconn,
+               struct GNUNET_SOCIAL_Ego *ego,
+               const struct GNUNET_CRYPTO_EddsaPublicKey *guest_pub_key)
+{
+  struct GNUNET_HashCode guest_pub_hash;
+  GNUNET_CRYPTO_hash (guest_pub_key, sizeof (*guest_pub_key), &guest_pub_hash);
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Got app guest place notification: %s\n",
+              GNUNET_h2s (&guest_pub_hash));
+
+  if (test == TEST_RECONNECT)
+  {
+    if (0 == memcmp (&place_pub_key, guest_pub_key, sizeof (*guest_pub_key)))
+    {
+      gst = GNUNET_SOCIAL_guest_enter_reconnect (gconn, guest_slicer,
+                                                 guest_reconnected, NULL);
+    }
+  }
+}
+
+
+static void
+app_recv_ego (void *cls,
+              struct GNUNET_SOCIAL_Ego *ego,
+              const struct GNUNET_CRYPTO_EcdsaPublicKey *ego_pub_key,
+              const char *name)
+{
   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-              "Test #%u: Advertise result: %d (%s).\n",
-              test, success, emsg);
-  GNUNET_assert (GNUNET_YES == success);
+              "Got app ego notification: %p %s %s\n",
+              ego, name,
+              GNUNET_CRYPTO_ecdsa_public_key_to_string (ego_pub_key));
 
-  GNUNET_assert (GNUNET_YES == guest_pkey_added);
-  GNUNET_IDENTITY_ego_lookup (cfg, guest_name, id_guest_ego_cb2, NULL);
+  if (NULL != strstr (name, host_name) && TEST_HOST_CREATE == test)
+  {
+    host_ego = ego;
+    host_pub_key = *(GNUNET_SOCIAL_ego_get_pub_key (host_ego));
+    GNUNET_assert (TEST_HOST_CREATE == test);
+    host_enter ();
+  }
+  else if (NULL != strstr (name, guest_name))
+  {
+    guest_ego = ego;
+
+    if (TEST_GUEST_CREATE == test)
+      guest_init ();
+  }
 }
 
 
 static void
-host_advertise ()
+schedule_reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
-  test = TEST_HOST_ADVERTISE;
+  test = TEST_RECONNECT;
+
+  GNUNET_SOCIAL_host_disconnect (hst, NULL, NULL);
+  GNUNET_SOCIAL_guest_disconnect (gst, NULL, NULL);
+  hst = NULL;
+  gst = NULL;
+
+  GNUNET_SOCIAL_app_disconnect (app);
+  app = GNUNET_SOCIAL_app_connect (cfg, app_id,
+                                   app_recv_ego,
+                                   app_recv_host,
+                                   app_recv_guest,
+                                   NULL);
+}
+
+
+static void
+host_recv_zone_add_place_result (void *cls, int64_t result,
+                                 const void *data, uint16_t data_size)
+{
   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-              "Test #%u: Advertising place.\n", test);
+              "Test #%u: Zone add place result: %d (%.*s).\n",
+              test, result, data_size, data);
+  GNUNET_assert (GNUNET_YES == result);
 
-  GNUNET_SOCIAL_host_advertise (hst, "home", 1, &this_peer,
+  GNUNET_assert (GNUNET_YES == is_guest_nym_added);
+  guest_enter_by_name ();
+}
+
+
+static void
+zone_add_place ()
+{
+  test = TEST_ZONE_ADD_PLACE;
+  GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+              "Test #%u: Adding place to zone.\n", test);
+
+  GNUNET_SOCIAL_zone_add_place (app, host_ego, "home", "let.me*in!",
+                                &place_pub_key, &this_peer, 1, &this_peer,
                                 GNUNET_TIME_relative_to_absolute 
(GNUNET_TIME_UNIT_MINUTES),
-                                "let.me*in!", host_recv_advertise_result, hst);
+                                host_recv_zone_add_place_result, app);
 }
 
 
@@ -356,12 +527,12 @@
                struct GNUNET_ENV_Environment *env)
 {
   const struct GNUNET_CRYPTO_EcdsaPublicKey *
-    nym_key = GNUNET_SOCIAL_nym_get_key (nym);
+    nym_key = GNUNET_SOCIAL_nym_get_pub_key (nym);
 
   char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (nym_key);
   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
               "Farewell: nym %s (%s) has left the place.\n",
-              GNUNET_h2s (GNUNET_SOCIAL_nym_get_key_hash (nym)), str);
+              GNUNET_h2s (GNUNET_SOCIAL_nym_get_pub_key_hash (nym)), str);
   GNUNET_free (str);
   GNUNET_assert (1 == GNUNET_ENV_environment_get_count (env));
   if (0 != memcmp (&guest_pub_key, nym_key, sizeof (*nym_key)))
@@ -372,7 +543,7 @@
     GNUNET_free (str);
     GNUNET_assert (0);
   }
-  host_advertise ();
+  zone_add_place ();
 }
 
 
@@ -381,10 +552,6 @@
 {
   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
               "The guest has left the place.\n");
-  GNUNET_SOCIAL_slicer_destroy (guest_slicer);
-  guest_slicer = NULL;
-  gst = NULL;
-  gst_plc = NULL;
 }
 
 
@@ -391,15 +558,18 @@
 static void
 guest_leave()
 {
-  test = TEST_GUEST_LEAVE;
+  if (test < TEST_RECONNECT)
+    test = TEST_GUEST_LEAVE;
+  else
+    test = TEST_GUEST_LEAVE2;
 
   struct GNUNET_ENV_Environment *env = GNUNET_ENV_environment_create ();
   GNUNET_ENV_environment_add (env, GNUNET_ENV_OP_SET,
                               "_message", DATA2ARG ("Leaving."));
-  GNUNET_SOCIAL_guest_leave (gst, GNUNET_NO, env, &guest_left, NULL);
+  GNUNET_SOCIAL_guest_leave (gst, env, &guest_left, NULL);
   GNUNET_ENV_environment_destroy (env);
-
-  /* @todo test keep_active */
+  gst = NULL;
+  gst_plc = NULL;
 }
 
 
@@ -871,7 +1041,7 @@
     break;
 
   case TEST_GUEST_ENTER_BY_NAME:
-    GNUNET_SCHEDULER_add_now (schedule_host_leave, NULL);
+    GNUNET_SCHEDULER_add_now (schedule_reconnect, NULL);
     break;
 
   default:
@@ -951,7 +1121,7 @@
   emsg->msg = GNUNET_PSYC_message_create (emsg->method_name, emsg->env,
                                           emsg->data, emsg->data_size);
 
-  gst = GNUNET_SOCIAL_guest_enter (cfg, guest_ego, &place_pub_key,
+  gst = GNUNET_SOCIAL_guest_enter (app, guest_ego, &place_pub_key,
                                    &this_peer, 0, NULL, emsg->msg, 
guest_slicer,
                                    guest_recv_local_enter,
                                    guest_recv_entry_decision, NULL);
@@ -979,7 +1149,7 @@
   emsg->msg = GNUNET_PSYC_message_create (emsg->method_name, emsg->env,
                                           emsg->data, emsg->data_size);
 
-  gst = GNUNET_SOCIAL_guest_enter_by_name (cfg, guest_ego,
+  gst = GNUNET_SOCIAL_guest_enter_by_name (app, guest_ego,
                                            "home.host.gnu", "let.me*in!",
                                            emsg->msg, guest_slicer,
                                            guest_recv_local_enter,
@@ -989,19 +1159,18 @@
 
 
 static void
-guest_recv_add_pkey_result (void *cls, int32_t success, const char *emsg)
+app_recv_zone_add_nym_result (void *cls, int64_t result,
+                              const void *data, uint16_t data_size)
 {
-  GNUNET_assert (GNUNET_YES == success);
-  guest_pkey_added = GNUNET_YES;
+  GNUNET_assert (GNUNET_YES == result);
+  is_guest_nym_added = GNUNET_YES;
 }
 
 
 static void
-id_guest_ego_cb (void *cls, const struct GNUNET_IDENTITY_Ego *ego)
+guest_init ()
 {
-  GNUNET_assert (NULL != ego);
-  guest_ego = ego;
-  GNUNET_IDENTITY_ego_get_public_key (ego, &guest_pub_key);
+  guest_pub_key = *(GNUNET_SOCIAL_ego_get_pub_key (guest_ego));
 
   guest_slicer = GNUNET_SOCIAL_slicer_create ();
   GNUNET_SOCIAL_slicer_method_add (guest_slicer, "",
@@ -1011,10 +1180,9 @@
                                      guest_recv_mod_foo_bar, 
&mod_foo_bar_rcls);
   test = TEST_HOST_ANSWER_DOOR_ADMIT;
 
-  GNUNET_SOCIAL_zone_add_pkey (cfg, guest_ego, "host", &host_pub_key,
-                               GNUNET_TIME_relative_to_absolute 
(GNUNET_TIME_UNIT_MINUTES),
-                               guest_recv_add_pkey_result, NULL);
-
+  GNUNET_SOCIAL_zone_add_nym (app, guest_ego, "host", &host_pub_key,
+                              GNUNET_TIME_relative_to_absolute 
(GNUNET_TIME_UNIT_MINUTES),
+                              app_recv_zone_add_nym_result, NULL);
   guest_enter ();
 }
 
@@ -1030,27 +1198,29 @@
     GNUNET_assert (0);
 #endif
   }
-
- GNUNET_IDENTITY_ego_lookup (cfg, guest_name, &id_guest_ego_cb, NULL);
+  if (NULL != guest_ego)
+    guest_init ();
 }
 
 
 static void
-host_entered (void *cls, int result, uint64_t max_message_id)
+host_entered (void *cls, int result,
+              const struct GNUNET_CRYPTO_EddsaPublicKey *home_pub_key,
+              uint64_t max_message_id)
 {
-  GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Host entered to place.\n");
+  place_pub_key = *home_pub_key;
+  GNUNET_CRYPTO_hash (&place_pub_key, sizeof (place_pub_key), &place_pub_hash);
+  GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+              "Host entered to place %s\n", GNUNET_h2s (&place_pub_hash));
 
+  test = TEST_GUEST_CREATE;
   GNUNET_IDENTITY_create (id, guest_name, &id_guest_created, NULL);
 }
 
 
 static void
-id_host_ego_cb (void *cls, const struct GNUNET_IDENTITY_Ego *ego)
+host_enter ()
 {
-  GNUNET_assert (NULL != ego);
-  host_ego = ego;
-  GNUNET_IDENTITY_ego_get_public_key (ego, &host_pub_key);
-
   host_slicer = GNUNET_SOCIAL_slicer_create ();
   GNUNET_SOCIAL_slicer_method_add (host_slicer, "",
                                    &host_recv_method, &host_recv_modifier,
@@ -1057,10 +1227,11 @@
                                    &host_recv_data, &host_recv_eom, NULL);
 
   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Entering to place as host.\n");
-  hst = GNUNET_SOCIAL_host_enter (cfg, host_ego, place_key,
-                                  GNUNET_PSYC_CHANNEL_PRIVATE, host_slicer,
-                                  host_entered, host_answer_door,
-                                  host_farewell, NULL);
+  test = TEST_HOST_ENTER;
+  hst = GNUNET_SOCIAL_host_enter (app, host_ego,
+                                  GNUNET_PSYC_CHANNEL_PRIVATE,
+                                  host_slicer, host_entered,
+                                  host_answer_door, host_farewell, NULL);
   hst_plc = GNUNET_SOCIAL_host_get_place (hst);
 }
 
@@ -1068,6 +1239,12 @@
 static void
 id_host_created (void *cls, const char *emsg)
 {
+  if (NULL != core)
+  {
+    GNUNET_CORE_disconnect (core);
+    core = NULL;
+  }
+
   if (NULL != emsg)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@@ -1077,7 +1254,11 @@
 #endif
   }
 
-  GNUNET_IDENTITY_ego_lookup (cfg, host_name, &id_host_ego_cb, NULL);
+  app = GNUNET_SOCIAL_app_connect (cfg, app_id,
+                                   app_recv_ego,
+                                   app_recv_host,
+                                   app_recv_guest,
+                                   NULL);
 }
 
 
@@ -1085,7 +1266,6 @@
 identity_ego_cb (void *cls, struct GNUNET_IDENTITY_Ego *ego,
                  void **ctx, const char *name)
 {
-
 }
 
 
@@ -1093,8 +1273,9 @@
 core_connected (void *cls, const struct GNUNET_PeerIdentity *my_identity)
 {
   this_peer = *my_identity;
+  id = GNUNET_IDENTITY_connect (cfg, &identity_ego_cb, NULL);
 
-  id = GNUNET_IDENTITY_connect (cfg, &identity_ego_cb, NULL);
+  test = TEST_HOST_CREATE;
   GNUNET_IDENTITY_create (id, host_name, &id_host_created, NULL);
 }
 
@@ -1119,9 +1300,6 @@
   cfg = c;
   end_badly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
 
-  place_key = GNUNET_CRYPTO_eddsa_key_create ();
-  GNUNET_CRYPTO_eddsa_key_get_public (place_key, &place_pub_key);
-
   core = GNUNET_CORE_connect (cfg, NULL, &core_connected, NULL, NULL,
                               NULL, GNUNET_NO, NULL, GNUNET_NO, NULL);
 }




reply via email to

[Prev in Thread] Current Thread [Next in Thread]