/**
 * infd_chat_filesystem_format_write:
 * @storage: A #InfdFilesystemStorage.
 * @path: Storage path where to write the session to.
 * @buffer: The #InfChatBuffer to write.
 * @error: Location to store error information, if any, or %NULL.
 *
 * Writes the given buffer into the filesystem storage at @path. If
 * successful, the session can then be read back with
 * infd_chat_filesystem_format_read(). If the function fails, %FALSE is
 * returned and @error is set.
 *
 * Returns: %TRUE on success or %FALSE on error.
 */
gboolean
infd_chat_filesystem_format_write(InfdFilesystemStorage* storage,
                                  const gchar* path,
                                  InfChatBuffer* buffer,
                                  GError** error)
{
  FILE* stream;
  xmlDocPtr doc;
  xmlNodePtr root;
  xmlErrorPtr xmlerror;

  g_return_val_if_fail(INFD_IS_FILESYSTEM_STORAGE(storage), FALSE);
  g_return_val_if_fail(path != NULL, FALSE);
  g_return_val_if_fail(INF_IS_CHAT_BUFFER(buffer), FALSE);
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);

  /* Open stream before exporting buffer to XML so possible errors are
   * catched earlier. */
  stream = infd_filesystem_storage_open(
    INFD_FILESYSTEM_STORAGE(storage),
    "InfChat",
    path,
    "w",
    NULL,
    error
  );

  if(stream == NULL)
    return FALSE;

  root = xmlNewNode(NULL, (const xmlChar*)"inf-chat-session");

  doc = xmlNewDoc((const xmlChar*)"1.0");
  xmlDocSetRootElement(doc, root);

  /* TODO: At this point, we should tell libxml2 to use
   * infd_filesystem_storage_stream_write() instead of fwrite(),
   * to prevent C runtime mixups. */
  if(xmlDocFormatDump(stream, doc, 1) == -1)
  {
    xmlerror = xmlGetLastError();
    infd_filesystem_storage_stream_close(stream);
    xmlFreeDoc(doc);

    g_set_error_literal(
      error,
      g_quark_from_static_string("LIBXML2_OUTPUT_ERROR"),
      xmlerror->code,
      xmlerror->message
    );

    return FALSE;
  }

  infd_filesystem_storage_stream_close(stream);
  xmlFreeDoc(doc);
  return TRUE;
}
static gboolean
infinoted_plugin_note_chat_session_write(InfdStorage* storage,
                                         InfSession* session,
                                         const gchar* path,
                                         gpointer user_data,
                                         GError** error)
{
  return infd_chat_filesystem_format_write(
    INFD_FILESYSTEM_STORAGE(storage),
    path,
    INF_CHAT_BUFFER(inf_session_get_buffer(session)),
    error
  );
}
예제 #3
0
static InfSession*
infinoted_plugin_note_text_session_read(InfdStorage* storage,
                                        InfIo* io,
                                        InfCommunicationManager* manager,
                                        const gchar* path,
                                        gpointer user_data,
                                        GError** error)
{
  InfUserTable* user_table;
  InfTextBuffer* buffer;
  gboolean result;
  InfTextSession* session;

  g_assert(INFD_IS_FILESYSTEM_STORAGE(storage));

  user_table = inf_user_table_new();
  buffer = INF_TEXT_BUFFER(inf_text_default_buffer_new("UTF-8"));

  result = inf_text_filesystem_format_read(
    INFD_FILESYSTEM_STORAGE(storage),
    path,
    user_table,
    buffer,
    error
  );

  if(result == FALSE)
  {
    g_object_unref(user_table);
    g_object_unref(buffer);
    return NULL;
  }

  session = inf_text_session_new_with_user_table(
    manager,
    buffer,
    io,
    user_table,
    INF_SESSION_RUNNING,
    NULL,
    NULL
  );

  g_object_unref(user_table);
  g_object_unref(buffer);

  return INF_SESSION(session);
}
static InfSession*
infinoted_plugin_note_chat_session_read(InfdStorage* storage,
                                        InfIo* io,
                                        InfCommunicationManager* manager,
                                        const gchar* path,
                                        gpointer user_data,
                                        GError** error)
{
  InfChatBuffer* buffer;
  gboolean result;
  InfChatSession* session;

  g_assert(INFD_IS_FILESYSTEM_STORAGE(storage));

  buffer = inf_chat_buffer_new(256);

  result = infd_chat_filesystem_format_read(
    INFD_FILESYSTEM_STORAGE(storage),
    path,
    buffer,
    error
  );

  if(result == FALSE)
  {
    g_object_unref(buffer);
    return NULL;
  }

  session = inf_chat_session_new(
    manager,
    buffer,
    INF_SESSION_RUNNING,
    NULL,
    NULL
  );

  g_object_unref(buffer);
  return INF_SESSION(session);
}
예제 #5
0
void Gobby::SelfHoster::apply_preferences()
{
	// Update directory storage
	if(m_preferences.user.keep_local_documents)
	{
		InfdStorage* storage =
			infd_directory_get_storage(m_directory);
		g_assert(storage == NULL ||
		         INFD_IS_FILESYSTEM_STORAGE(storage));
		InfdFilesystemStorage* fs_storage =
			INFD_FILESYSTEM_STORAGE(storage);

		const std::string new_directory =
			m_preferences.user.host_directory;

		bool set_new_storage = true;
		if(fs_storage != NULL)
		{
			gchar* root_directory;
			g_object_get(
				G_OBJECT(fs_storage),
				"root-directory", &root_directory, NULL);

			if(strcmp(root_directory, new_directory.c_str()) == 0)
				set_new_storage = false;

			g_free(root_directory);
		}

		if(set_new_storage)
		{
			fs_storage = infd_filesystem_storage_new(
				new_directory.c_str());
			g_object_set(
				G_OBJECT(m_directory),
				"storage", fs_storage, NULL);
			g_object_unref(fs_storage);
		}
	}
	else
	{
		if(infd_directory_get_storage(m_directory) != NULL)
		{
			g_object_set(
				G_OBJECT(m_directory), "storage", NULL, NULL);
		}
	}

	// Remove old statusbar message, if any
	if(m_info_handle != m_status_bar.invalid_handle())
	{
		m_status_bar.remove_message(m_info_handle);
		m_info_handle = m_status_bar.invalid_handle();
	}

	// Close server and all connections if no access is required
	if(!m_preferences.user.allow_remote_access)
	{
		infd_directory_foreach_connection(
			m_directory, directory_foreach_func_close_static,
			this);
		if(m_server.is_open())
			m_server.close();
		return;
	}

	// Okay, we want to share our documents, so let's try to start a
	// server for it.

	// Make sure TLS credentials are available.
	if(m_preferences.security.policy !=
	   INF_XMPP_CONNECTION_SECURITY_ONLY_UNSECURED &&
	   (m_preferences.security.authentication_enabled != true ||
            m_cert_manager.get_private_key() == NULL ||
	    m_cert_manager.get_certificates() == NULL))
	{
		m_info_handle = m_status_bar.add_info_message(
			_("In order to start sharing your documents, "
			  "choose a private key and certificate or "
			  "create a new pair in the preferences"));
		return;
	}

	// Make sure we have DH parameters
	if(!ensure_dh_params()) return;

	// Okay, go and open a server. If the server is already open the
	// command below will only change the port and/or security policy.
	try
	{
		const InfKeepalive& keepalive =
			m_preferences.network.keepalive;
		m_server.open(m_preferences.user.port, &keepalive,
		              m_preferences.security.policy,
		              m_cert_manager.get_credentials(),
		              m_sasl_context, get_sasl_mechanisms());
	}
	catch(const std::exception& ex)
	{
		m_status_bar.add_error_message(_("Failed to share documents"),
		                               ex.what());

		return;
	}
}
static gboolean
infd_note_plugin_text_session_write(InfdStorage* storage,
                                    InfSession* session,
                                    const gchar* path,
                                    gpointer user_data,
                                    GError** error)
{
  InfUserTable* table;
  InfTextBuffer* buffer;
  InfTextBufferIter* iter;
  xmlNodePtr root;
  xmlNodePtr buffer_node;
  xmlNodePtr segment_node;

  guint author;
  gchar* content;
  gsize bytes;

  FILE* stream;
  xmlDocPtr doc;
  xmlErrorPtr xmlerror;

  g_assert(INFD_IS_FILESYSTEM_STORAGE(storage));
  g_assert(INF_TEXT_IS_SESSION(session));

  /* Open stream before exporting buffer to XML so possible errors are
   * catched earlier. */
  stream = infd_filesystem_storage_open(
    INFD_FILESYSTEM_STORAGE(storage),
    "InfText",
    path,
    "w",
    error
  );

  if(stream == NULL)
    return FALSE;

  root = xmlNewNode(NULL, (const xmlChar*)"inf-text-session");
  buffer = INF_TEXT_BUFFER(inf_session_get_buffer(session));
  table = inf_session_get_user_table(session);

  inf_user_table_foreach_user(
    table,
    infd_note_plugin_text_session_write_foreach_user_func,
    root
  );

  buffer_node = xmlNewChild(root, NULL, (const xmlChar*)"buffer", NULL);
  iter = inf_text_buffer_create_iter(buffer);
  if(iter != NULL)
  {
    do
    {
      author = inf_text_buffer_iter_get_author(buffer, iter);
      content = inf_text_buffer_iter_get_text(buffer, iter);
      bytes = inf_text_buffer_iter_get_bytes(buffer, iter);

      segment_node = xmlNewChild(
        buffer_node,
        NULL,
        (const xmlChar*)"segment",
        NULL
      );

      inf_xml_util_set_attribute_uint(segment_node, "author", author);
      inf_xml_util_add_child_text(segment_node, content, bytes);
      g_free(content);
    } while(inf_text_buffer_iter_next(buffer, iter));

    inf_text_buffer_destroy_iter(buffer, iter);
  }

  doc = xmlNewDoc((const xmlChar*)"1.0");
  xmlDocSetRootElement(doc, root);

  if(xmlDocFormatDump(stream, doc, 1) == -1)
  {
    xmlerror = xmlGetLastError();
    fclose(stream);
    xmlFreeDoc(doc);

    g_set_error(
      error,
      g_quark_from_static_string("LIBXML2_OUTPUT_ERROR"),
      xmlerror->code,
      "%s",
      xmlerror->message
    );

    return FALSE;
  }

  fclose(stream);
  xmlFreeDoc(doc);
  return TRUE;
}
static InfSession*
infd_note_plugin_text_session_read(InfdStorage* storage,
                                   InfIo* io,
                                   InfCommunicationManager* manager,
                                   const gchar* path,
                                   gpointer user_data,
                                   GError** error)
{
  InfUserTable* user_table;
  InfTextBuffer* buffer;
  InfTextSession* session;

  FILE* stream;
  xmlDocPtr doc;
  xmlErrorPtr xmlerror;
  xmlNodePtr root;
  xmlNodePtr child;
  gboolean result;

  g_assert(INFD_IS_FILESYSTEM_STORAGE(storage));

  user_table = inf_user_table_new();
  buffer = INF_TEXT_BUFFER(inf_text_default_buffer_new("UTF-8"));

  /* TODO: Use a SAX parser for better performance */
  stream = infd_filesystem_storage_open(
    INFD_FILESYSTEM_STORAGE(storage),
    "InfText",
    path,
    "r",
    error
  );

  if(stream == NULL) return FALSE;

  doc = xmlReadIO(
    infd_note_plugin_text_session_read_read_func,
    infd_note_plugin_text_sesison_read_close_func,
    stream,
    path, /* TODO: Get some "infinote-filesystem-storage://" URL? */
    "UTF-8",
    XML_PARSE_NOWARNING | XML_PARSE_NOERROR
  );

  if(doc == NULL)
  {
    xmlerror = xmlGetLastError();

    g_set_error(
      error,
      g_quark_from_static_string("LIBXML2_PARSER_ERROR"),
      xmlerror->code,
      "Error parsing XML in file '%s': [%d]: %s",
      path,
      xmlerror->line,
      xmlerror->message
    );

    result = FALSE;
  }
  else
  {
    root = xmlDocGetRootElement(doc);
    if(strcmp((const char*)root->name, "inf-text-session") != 0)
    {
      g_set_error(
        error,
        g_quark_from_static_string("INF_NOTE_PLUGIN_TEXT_ERROR"),
        INFD_NOTE_PLUGIN_TEXT_ERROR_NOT_A_TEXT_SESSION,
        "Error processing file '%s': %s",
        path,
        "The document is not a text session"
      );

      result = FALSE;
    }
    else
    {
      for(child = root->children; child != NULL; child = child->next)
      {
        if(child->type != XML_ELEMENT_NODE)
          continue;

        if(strcmp((const char*)child->name, "user") == 0)
        {
          if(!infd_note_plugin_text_read_user(user_table, child, error))
          {
            g_prefix_error(error, "Error processing file '%s': ", path);
            result = FALSE;
            break;
          }
        }
        else if(strcmp((const char*)child->name, "buffer") == 0)
        {
          if(!infd_note_plugin_text_read_buffer(buffer, user_table,
                                                child, error))
          {
            g_prefix_error(error, "Error processing file '%s': ", path);
            result = FALSE;
            break;
          }
        }
        else
        {
          infd_note_plugin_text_session_unexpected_node(child, error);
          g_prefix_error(error, "Error processing file '%s': ", path);
          result = FALSE;
          break;
        }
      }

      if(child == NULL)
        result = TRUE;
    }

    xmlFreeDoc(doc);
  }

  if(result == FALSE)
    return NULL;

  session = inf_text_session_new_with_user_table(
    manager,
    buffer,
    io,
    user_table,
    INF_SESSION_RUNNING,
    NULL,
    NULL
  );

  return INF_SESSION(session);
}
/**
 * infd_chat_filesystem_format_read:
 * @storage: A #InfdFilesystemStorage.
 * @path: Storage path to retrieve the session from.
 * @buffer: An empty #InfTextBuffer to use as the new session's buffer.
 * @error: Location to store error information, if any, or %NULL.
 *
 * Reads a chat session from @path in @storage. The file is expected to have
 * been saved with infd_chat_filesystem_format_write() before. The @buffer
 * parameter should be an empty #InfChatBuffer, and the document will be
 * written into this buffer. If the function succeeds, the buffer can be used
 * to create an #InfChatSession with inf_chat_session_new(). If the function 
 * fails, %FALSE is returned and @error is set.
 *
 * Returns: %TRUE on success or %FALSE on error.
 */
gboolean
infd_chat_filesystem_format_read(InfdFilesystemStorage* storage,
                                 const gchar* path,
                                 InfChatBuffer* buffer,
                                 GError** error)
{
  FILE* stream;
  gchar* full_path;
  gchar* uri;

  xmlDocPtr doc;
  xmlErrorPtr xmlerror;
  xmlNodePtr root;
  xmlNodePtr child;
  gboolean result;

  g_return_val_if_fail(INFD_IS_FILESYSTEM_STORAGE(storage), FALSE);
  g_return_val_if_fail(path != NULL, FALSE);
  g_return_val_if_fail(INF_IS_CHAT_BUFFER(buffer), FALSE);
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);

  /* TODO: Use a SAX parser for better performance */
  full_path = NULL;
  stream = infd_filesystem_storage_open(
    INFD_FILESYSTEM_STORAGE(storage),
    "InfChat",
    path,
    "r",
    &full_path,
    error
  );

  if(stream == NULL)
  {
    g_free(full_path);
    return FALSE;
  }

  uri = g_filename_to_uri(full_path, NULL, error);
  g_free(full_path);

  if(uri == NULL)
    return FALSE;

  doc = xmlReadIO(
    infd_chat_filesystem_format_read_read_func,
    infd_chat_filesystem_format_read_close_func,
    stream,
    uri,
    "UTF-8",
    XML_PARSE_NOWARNING | XML_PARSE_NOERROR
  );

  g_free(uri);

  if(doc == NULL)
  {
    xmlerror = xmlGetLastError();

    g_set_error(
      error,
      g_quark_from_static_string("LIBXML2_PARSER_ERROR"),
      xmlerror->code,
      _("Error parsing XML in file \"%s\": [%d]: %s"),
      path,
      xmlerror->line,
      xmlerror->message
    );

    result = FALSE;
  }
  else
  {
    root = xmlDocGetRootElement(doc);
    if(strcmp((const char*)root->name, "inf-chat-session") != 0)
    {
      g_set_error(
        error,
        infd_chat_filesystem_format_error_quark(),
        INFD_CHAT_FILESYSTEM_FORMAT_ERROR_NOT_A_CHAT_SESSION,
        _("Error processing file \"%s\": %s"),
        path,
        _("The document is not a chat session")
      );

      result = FALSE;
    }
    else
    {
      result = TRUE;
    }

    xmlFreeDoc(doc);
  }

  if(result == FALSE)
    return FALSE;

  return TRUE;
}