+}
+
+
+/**
+ * Relay a message part received from a guest to the the place.
+ *
+ * @param hst
+ * Host.
+ * @param pmsg
+ * Message part.
+ * @param nym_pub_key
+ * Nym the message is received from.
+ */
+static void
+host_relay_message_part (struct Host *hst,
+ const struct GNUNET_MessageHeader *pmsg,
+ const struct GNUNET_CRYPTO_EcdsaPublicKey *nym_pub_key)
+{
+ /* separate queue per nym */
+ struct GNUNET_HashCode nym_pub_hash;
+ GNUNET_CRYPTO_hash (nym_pub_key, sizeof (*nym_pub_key), &nym_pub_hash);
+
+ struct MessageTransmitQueue *
+ tmit_msg = GNUNET_CONTAINER_multihashmap_get (hst->relay_msgs, &nym_pub_hash);
+
+ uint16_t ptype = ntohs (pmsg->type);
+
+ if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == ptype)
+ {
+ /* FIXME: last message was unfinished, cancel & remove from queue */
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "FIXME: last message was unfinished.\n");
+ }
+
+ tmit_msg = psyc_transmit_queue_message (&hst->place, NULL, ntohs (pmsg->size),
+ pmsg, ptype, ptype, tmit_msg);
+
+ switch (ptype)
+ {
+ case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD:
+ GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_put
+ (hst->relay_msgs, &nym_pub_hash, tmit_msg,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+ break;
+ case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
+ case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
+ GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove
+ (hst->relay_msgs, &nym_pub_hash, tmit_msg));
+ break;
+ }
+}
+
+
+/**
+ * Received a method to be relayed from a guest.
+ */
+static void
+place_recv_relay_method (void *cls,
+ const struct GNUNET_PSYC_MessageHeader *msg,
+ const struct GNUNET_PSYC_MessageMethod *meth,
+ uint64_t message_id,
+ const char *method_name)
+{
+ struct Place *plc = cls;
+
+ if (GNUNET_PSYC_MESSAGE_REQUEST & ntohs (msg->flags)
+ && GNUNET_YES == plc->is_host)
+ {
+ struct Host *hst = cls;
+ host_relay_message_part (hst, &meth->header, &msg->slave_pub_key);
+ }
+}
+
+
+/**
+ * Received a modifier to be relayed from a guest.
+ */
+static void
+place_recv_relay_modifier (void *cls,
+ const struct GNUNET_PSYC_MessageHeader *msg,
+ const struct GNUNET_MessageHeader *pmsg,
+ uint64_t message_id,
+ enum GNUNET_PSYC_Operator oper,
+ const char *name,
+ const void *value,
+ uint16_t value_size,
+ uint16_t full_value_size)
+{
+ struct Place *plc = cls;
+
+ if (GNUNET_PSYC_MESSAGE_REQUEST & ntohs (msg->flags)
+ && GNUNET_YES == plc->is_host)
+ {
+ struct Host *hst = cls;
+ host_relay_message_part (hst, pmsg, &msg->slave_pub_key);
+ }
+}
+
+/**
+ * Received a data fragment to be relayed from a guest.
+ */
+static void
+place_recv_relay_data (void *cls,
+ const struct GNUNET_PSYC_MessageHeader *msg,
+ const struct GNUNET_MessageHeader *pmsg,
+ uint64_t message_id,
+ const void *data,
+ uint16_t data_size)
+{
+ struct Place *plc = cls;
+
+ if (GNUNET_PSYC_MESSAGE_REQUEST & ntohs (msg->flags)
+ && GNUNET_YES == plc->is_host)
+ {
+ struct Host *hst = cls;
+ host_relay_message_part (hst, pmsg, &msg->slave_pub_key);
+ }
+}
+
+
+/**
+ * Received end of message to be relayed from a guest.
+ */
+static void
+place_recv_relay_eom (void *cls,
+ const struct GNUNET_PSYC_MessageHeader *msg,
+ const struct GNUNET_MessageHeader *pmsg,
+ uint64_t message_id,
+ uint8_t is_cancelled)
+{
+ struct Place *plc = cls;
+
+ if (GNUNET_PSYC_MESSAGE_REQUEST & ntohs (msg->flags)
+ && GNUNET_YES == plc->is_host)
+ {
+ struct Host *hst = cls;
+ host_relay_message_part (hst, pmsg, &msg->slave_pub_key);
+ }
+}
+
+
+/**
+ * Received a method to be saved to disk.
+ *
+ * Create a new file for writing the data part of the message into,
+ * if the file does not yet exist.
+ */
+static void
+place_recv_save_method (void *cls,
+ const struct GNUNET_PSYC_MessageHeader *msg,
+ const struct GNUNET_PSYC_MessageMethod *meth,
+ uint64_t message_id,
+ const char *method_name)
+{
+ struct Place *plc = cls;
+ plc->file_offset = 0;
+ plc->file_save = GNUNET_NO;
+
+ char *place_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (&plc->pub_key);
+ char *filename = NULL;
+ GNUNET_asprintf (&filename, "%s%c" "%s%c" "%s%c" "%" PRIu64 ".part",
+ dir_social, DIR_SEPARATOR,
+ "files", DIR_SEPARATOR,
+ place_pub_str, DIR_SEPARATOR,
+ GNUNET_ntohll (msg->message_id));
+ GNUNET_free (place_pub_str);
+
+ /* save if does not already exist */
+ if (GNUNET_YES != GNUNET_DISK_file_test (filename))
+ {
+ if (0 == GNUNET_DISK_fn_write (filename, NULL, 0,
+ GNUNET_DISK_PERM_USER_READ
+ | GNUNET_DISK_PERM_USER_WRITE))
+ {
+ plc->file_save = GNUNET_YES;
+ }
+ else
+ {
+ GNUNET_break (0);
+ }
+ }
+ GNUNET_free (filename);
+}
+
+
+/**
+ * Received a data fragment to be saved to disk.
+ *
+ * Append data fragment to the file.
+ */
+static void
+place_recv_save_data (void *cls,
+ const struct GNUNET_PSYC_MessageHeader *msg,
+ const struct GNUNET_MessageHeader *pmsg,
+ uint64_t message_id,
+ const void *data,
+ uint16_t data_size)
+{
+ struct Place *plc = cls;
+ if (GNUNET_YES != plc->file_save)
+ return;
+
+ char *place_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (&plc->pub_key);
+ char *filename = NULL;
+ GNUNET_asprintf (&filename, "%s%c" "%s%c" "%s%c" "%" PRIu64 ".part",
+ dir_social, DIR_SEPARATOR,
+ "files", DIR_SEPARATOR,
+ place_pub_str, DIR_SEPARATOR,
+ GNUNET_ntohll (msg->message_id));
+ GNUNET_free (place_pub_str);
+ if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (filename))
+ {
+ GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "create", filename);
+ GNUNET_free (filename);
+ return;
+ }
+
+ struct GNUNET_DISK_FileHandle *
+ fh = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_WRITE,
+ GNUNET_DISK_PERM_NONE);
+ if (NULL != fh)
+ {
+ if (plc->file_offset != GNUNET_DISK_file_seek
+ (fh, plc->file_offset, GNUNET_DISK_SEEK_SET)) {
+ GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "seek", filename);
+ GNUNET_DISK_file_close (fh);
+ GNUNET_free (filename);
+ return;
+ }
+ GNUNET_DISK_file_write (fh, data, data_size);
+ GNUNET_DISK_file_close (fh);
+ GNUNET_free (filename);
+ }
+ else
+ {
+ GNUNET_free (filename);
+ GNUNET_break (0);
+ }
+ plc->file_offset += data_size;
+}
+
+
+/**
+ * Received end of message to be saved to disk.
+ *
+ * Remove .part ending from the filename.
+ */
+static void
+place_recv_save_eom (void *cls,
+ const struct GNUNET_PSYC_MessageHeader *msg,
+ const struct GNUNET_MessageHeader *pmsg,
+ uint64_t message_id,
+ uint8_t is_cancelled)
+{
+ struct Place *plc = cls;
+ if (GNUNET_YES != plc->file_save)
+ return;