static InfAdoptedUser*
inf_adopted_session_user_from_request_xml(InfAdoptedSession* session,
                                          xmlNodePtr xml,
                                          GError** error)
{
  InfUserTable* user_table;
  InfUser* user;
  guint user_id;

  user_table = inf_session_get_user_table(INF_SESSION(session));

  if(!inf_xml_util_get_attribute_uint_required(xml, "user", &user_id, error))
    return FALSE;

  /* User ID 0 means no user */
  if(user_id == 0) return NULL;

  user = inf_user_table_lookup_user_by_id(user_table, user_id);

  if(user == NULL)
  {
    g_set_error(
      error,
      inf_adopted_session_error_quark,
      INF_ADOPTED_SESSION_ERROR_NO_SUCH_USER,
      _("No such user with user ID '%u'"),
      user_id
    );

    return NULL;
  }

  g_assert(INF_ADOPTED_IS_USER(user));
  return INF_ADOPTED_USER(user);
}
static void
inf_adopted_session_create_algorithm(InfAdoptedSession* session)
{
  InfAdoptedSessionPrivate* priv;
  priv = INF_ADOPTED_SESSION_PRIVATE(session);

  g_assert(priv->algorithm == NULL);

  g_assert(
    inf_session_get_status(INF_SESSION(session)) == INF_SESSION_RUNNING
  );

  priv->algorithm = inf_adopted_algorithm_new_full(
    inf_session_get_user_table(INF_SESSION(session)),
    inf_session_get_buffer(INF_SESSION(session)),
    priv->max_total_log_size
  );

  g_signal_connect(
    G_OBJECT(priv->algorithm),
    "execute-request",
    G_CALLBACK(inf_adopted_session_execute_request_cb),
    session
  );

  g_object_notify(G_OBJECT(session), "algorithm");
}
static void
inf_adopted_session_synchronization_complete(InfSession* session,
                                             InfXmlConnection* connection)
{
  InfAdoptedSessionPrivate* priv;
  InfSessionStatus status;

  priv = INF_ADOPTED_SESSION_PRIVATE(session);
  g_object_get(G_OBJECT(session), "status", &status, NULL);

  INF_SESSION_CLASS(parent_class)->synchronization_complete(
    session,
    connection
  );

  if(status == INF_SESSION_SYNCHRONIZING)
  {
    inf_user_table_foreach_user(
      inf_session_get_user_table(session),
      inf_adopted_session_synchronization_complete_foreach_user_func,
      NULL
    );

    /* Create adOPTed algorithm upon successful synchronization */
    g_assert(priv->algorithm == NULL);
    inf_adopted_session_create_algorithm(INF_ADOPTED_SESSION(session));
  }
}
static void
inf_adopted_session_dispose(GObject* object)
{
  InfAdoptedSession* session;
  InfAdoptedSessionPrivate* priv;
  InfUserTable* user_table;

  session = INF_ADOPTED_SESSION(object);
  priv = INF_ADOPTED_SESSION_PRIVATE(session);

  user_table = inf_session_get_user_table(INF_SESSION(session));

  inf_signal_handlers_disconnect_by_func(
    G_OBJECT(user_table),
    G_CALLBACK(inf_adopted_session_add_local_user_cb),
    session
  );

  inf_signal_handlers_disconnect_by_func(
    G_OBJECT(user_table),
    G_CALLBACK(inf_adopted_session_remove_local_user_cb),
    session
  );

  if(priv->noop_timeout != NULL)
  {
    inf_io_remove_timeout(priv->io, priv->noop_timeout);
    priv->noop_timeout = NULL;
  }

  /* This calls the close vfunc if the session is running, in which we
   * free the local users. */
  G_OBJECT_CLASS(parent_class)->dispose(object);

  g_assert(priv->local_users == NULL);

  if(priv->algorithm != NULL)
  {
    inf_signal_handlers_disconnect_by_func(
      G_OBJECT(priv->algorithm),
      G_CALLBACK(inf_adopted_session_execute_request_cb),
      session
    );

    g_object_unref(G_OBJECT(priv->algorithm));
    priv->algorithm = NULL;
  }

  if(priv->io != NULL)
  {
    g_object_unref(G_OBJECT(priv->io));
    priv->io = NULL;
  }
}
static gboolean
inf_adopted_session_process_xml_sync(InfSession* session,
                                     InfXmlConnection* connection,
                                     const xmlNodePtr xml,
                                     GError** error)
{
  InfAdoptedSessionClass* session_class;
  InfAdoptedRequest* request;
  InfAdoptedUser* user;
  InfAdoptedRequestLog* log;

  if(strcmp((const char*)xml->name, "sync-request") == 0)
  {
    session_class = INF_ADOPTED_SESSION_GET_CLASS(session);
    g_assert(session_class->xml_to_request != NULL);

    request = session_class->xml_to_request(
      INF_ADOPTED_SESSION(session),
      xml,
      NULL, /* TODO: Diff to previous request, if any. */
      TRUE,
      error
    );

    if(request == NULL) return FALSE;

    user = INF_ADOPTED_USER(
      inf_user_table_lookup_user_by_id(
        inf_session_get_user_table(session),
        inf_adopted_request_get_user_id(request)
      )
    );

    log = inf_adopted_user_get_request_log(user);
    if(inf_adopted_session_validate_request(log, request, error) == FALSE)
    {
      g_object_unref(request);
      return FALSE;
    }

    inf_adopted_request_log_add_request(log, request);
    g_object_unref(request);

    return TRUE;
  }

  return INF_SESSION_CLASS(parent_class)->process_xml_sync(
    session,
    connection, 
    xml,
    error
  );
}
/* Breadcasts a request N times - makes only sense for undo and redo requests,
 * so that's the only thing we offer API for. */
static void
inf_adopted_session_broadcast_n_requests(InfAdoptedSession* session,
                                         InfAdoptedRequest* request,
                                         guint n)
{
  InfAdoptedSessionPrivate* priv;
  InfAdoptedSessionClass* session_class;
  InfUserTable* user_table;
  guint user_id;
  InfUser* user;
  InfAdoptedSessionLocalUser* local;
  xmlNodePtr xml;

  priv = INF_ADOPTED_SESSION_PRIVATE(session);
  session_class = INF_ADOPTED_SESSION_GET_CLASS(session);
  g_assert(session_class->request_to_xml != NULL);

  user_table = inf_session_get_user_table(INF_SESSION(session));
  user_id = inf_adopted_request_get_user_id(request);
  user = inf_user_table_lookup_user_by_id(user_table, user_id);
  g_assert(user != NULL);

  local = inf_adopted_session_lookup_local_user(
    session,
    INF_ADOPTED_USER(user)
  );
  g_assert(local != NULL);

  xml = xmlNewNode(NULL, (const xmlChar*)"request");

  session_class->request_to_xml(
    session,
    xml,
    request,
    local->last_send_vector,
    FALSE
  );

  if(n > 1) inf_xml_util_set_attribute_uint(xml, "num", n);
  inf_session_send_to_subscriptions(INF_SESSION(session), xml);

  inf_adopted_state_vector_free(local->last_send_vector);
  local->last_send_vector = inf_adopted_state_vector_copy(
    inf_adopted_request_get_vector(request)
  );

  /* Add this request to last send vector if it increases vector time
   * (-> affects buffer). */
  if(inf_adopted_request_affects_buffer(request) == TRUE)
    inf_adopted_state_vector_add(local->last_send_vector, user_id, n);

  inf_adopted_session_stop_noop_timer(session, local);
}
Esempio n. 7
0
void Gobby::ChatSessionView::set_active_user(InfUser* user)
{
	g_assert(
		user == NULL ||
		inf_user_table_lookup_user_by_id(
			inf_session_get_user_table(INF_SESSION(m_session)),
			inf_user_get_id(INF_USER(user)))
		== INF_USER(user));

	inf_gtk_chat_set_active_user(m_chat, user);
	active_user_changed(user);
}
static gboolean
infinoted_plugin_note_text_session_write(InfdStorage* storage,
                                         InfSession* session,
                                         const gchar* path,
                                         gpointer user_data,
                                         GError** error)
{
  return inf_text_filesystem_format_write(
    INFD_FILESYSTEM_STORAGE(storage),
    path,
    inf_session_get_user_table(session),
    INF_TEXT_BUFFER(inf_session_get_buffer(session)),
    error
  );
}
static void
infinoted_plugin_linekeeper_session_added(const InfBrowserIter* iter,
                                          InfSessionProxy* proxy,
                                          gpointer plugin_info,
                                          gpointer session_info)
{
  InfinotedPluginLinekeeperSessionInfo* info;
  InfSession* session;
  InfUserTable* user_table;

  info = (InfinotedPluginLinekeeperSessionInfo*)session_info;

  info->plugin = (InfinotedPluginLinekeeper*)plugin_info;
  info->proxy = proxy;
  info->request = NULL;
  info->user = NULL;
  info->dispatch = NULL;
  g_object_ref(proxy);

  g_object_get(G_OBJECT(proxy), "session", &session, NULL);
  g_assert(inf_session_get_status(session) == INF_SESSION_RUNNING);
  info->buffer = INF_TEXT_BUFFER(inf_session_get_buffer(session));
  g_object_ref(info->buffer);

  user_table = inf_session_get_user_table(session);

  g_signal_connect(
    G_OBJECT(user_table),
    "add-available-user",
    G_CALLBACK(infinoted_plugin_linekeeper_add_available_user_cb),
    info
  );

  g_signal_connect(
    G_OBJECT(user_table),
    "remove-available-user",
    G_CALLBACK(infinoted_plugin_linekeeper_remove_available_user_cb),
    info
  );

  /* Only join a user when there are other nonlocal users available, so that
   * we don't keep the session from going idle. */
  if(infinoted_plugin_linekeeper_has_available_users(info) == TRUE)
    infinoted_plugin_linekeeper_join_user(info);

  g_object_unref(session);
}
Esempio n. 10
0
static void
inf_adopted_session_to_xml_sync(InfSession* session,
                                xmlNodePtr parent)
{
  InfAdoptedSessionPrivate* priv;
  InfAdoptedSessionToXmlSyncForeachData foreach_data;

  priv = INF_ADOPTED_SESSION_PRIVATE(session);
  g_assert(priv->algorithm != NULL);

  INF_SESSION_CLASS(parent_class)->to_xml_sync(session, parent);

  foreach_data.session = INF_ADOPTED_SESSION(session);
  foreach_data.parent_xml = parent;

  inf_user_table_foreach_user(
    inf_session_get_user_table(session),
    inf_adopted_session_to_xml_sync_foreach_user_func,
    &foreach_data
  );
}
static void
infinoted_plugin_linekeeper_join_user(
  InfinotedPluginLinekeeperSessionInfo* info)
{
  InfSession* session;
  InfUserTable* user_table;

  g_assert(info->user == NULL);
  g_assert(info->request == NULL);

  g_object_get(G_OBJECT(info->proxy), "session", &session, NULL);
  user_table = inf_session_get_user_table(session);

  /* Prevent double user join attempt by blocking the callback for
   * joining our local user. */
  g_signal_handlers_block_by_func(
    user_table,
    G_CALLBACK(infinoted_plugin_linekeeper_add_available_user_cb),
    info
  );

  info->request = inf_text_session_join_user(
    info->proxy,
    "LineKeeper",
    INF_USER_ACTIVE,
    0.0,
    inf_text_buffer_get_length(info->buffer),
    0,
    infinoted_plugin_linekeeper_user_join_cb,
    info
  );

  g_signal_handlers_unblock_by_func(
    user_table,
    G_CALLBACK(infinoted_plugin_linekeeper_add_available_user_cb),
    info
  );

  g_object_unref(session);
}
static gboolean
infinoted_plugin_linekeeper_has_available_users(
  InfinotedPluginLinekeeperSessionInfo* info)
{
  InfinotedPluginLinekeeperHasAvailableUsersData data;
  InfSession* session;
  InfUserTable* user_table;

  g_object_get(G_OBJECT(info->proxy), "session", &session, NULL); 
  user_table = inf_session_get_user_table(session);

  data.has_available_user = FALSE;
  data.own_user = info->user;

  inf_user_table_foreach_user(
    user_table,
    infinoted_plugin_linekeeper_has_available_users_foreach_func,
    &data
  );

  g_object_unref(session);
  return data.has_available_user;
}
Esempio n. 13
0
static void
infc_session_proxy_release_connection(InfcSessionProxy* proxy)
{
  InfcSessionProxyPrivate* priv;
  priv = INFC_SESSION_PROXY_PRIVATE(proxy);

  g_assert(priv->connection != NULL);
  g_assert(priv->subscription_group != NULL);

  /* TODO: Emit failed signal with some "cancelled" error? */
  infc_request_manager_clear(priv->request_manager);

  /* Set status of all users to unavailable */
  /* TODO: Keep local users available */
  inf_user_table_foreach_user(
    inf_session_get_user_table(priv->session),
    infc_session_proxy_release_connection_foreach_user_func,
    NULL
  );

  g_signal_handlers_disconnect_by_func(
    G_OBJECT(priv->connection),
    G_CALLBACK(infc_session_proxy_connection_notify_status_cb),
    proxy
  );

  inf_session_set_subscription_group(priv->session, NULL);

  inf_connection_manager_group_unref(priv->subscription_group);
  priv->subscription_group = NULL;

  g_object_unref(G_OBJECT(priv->connection));
  priv->connection = NULL;

  g_object_notify(G_OBJECT(proxy), "connection");
  g_object_notify(G_OBJECT(proxy), "subscription-group");
}
static void
infinoted_plugin_linekeeper_session_removed(const InfBrowserIter* iter,
                                            InfSessionProxy* proxy,
                                            gpointer plugin_info,
                                            gpointer session_info)
{
  InfinotedPluginLinekeeperSessionInfo* info;
  InfdDirectory* directory;
  InfSession* session;
  InfUserTable* user_table;

  info = (InfinotedPluginLinekeeperSessionInfo*)session_info;

  g_object_get(G_OBJECT(info->proxy), "session", &session, NULL);
  user_table = inf_session_get_user_table(session);

  g_signal_handlers_disconnect_by_func(
    G_OBJECT(user_table),
    G_CALLBACK(infinoted_plugin_linekeeper_add_available_user_cb),
    info
  );

  g_signal_handlers_disconnect_by_func(
    G_OBJECT(user_table),
    G_CALLBACK(infinoted_plugin_linekeeper_remove_available_user_cb),
    info
  );

  if(info->dispatch != NULL)
  {
    directory = infinoted_plugin_manager_get_directory(info->plugin->manager);
    inf_io_remove_dispatch(infd_directory_get_io(directory), info->dispatch);
    info->dispatch = NULL;
  }

  if(info->user != NULL)
  {
    infinoted_plugin_linekeeper_remove_user(info);
  }

  if(info->buffer != NULL)
  {
    g_object_unref(info->buffer);
    info->buffer = NULL;
  }

  if(info->request != NULL)
  {
    inf_signal_handlers_disconnect_by_func(
      info->request,
      G_CALLBACK(infinoted_plugin_linekeeper_user_join_cb),
      info
    );

    info->request = NULL;
  }

  g_assert(info->proxy != NULL);
  g_object_unref(info->proxy);

  g_object_unref(session);
}
Esempio n. 15
0
static GObject*
inf_adopted_session_constructor(GType type,
                                guint n_construct_properties,
                                GObjectConstructParam* construct_properties)
{
  GObject* object;
  InfAdoptedSession* session;
  InfAdoptedSessionPrivate* priv;
  InfSessionStatus status;
  InfUserTable* user_table;

  object = G_OBJECT_CLASS(parent_class)->constructor(
    type,
    n_construct_properties,
    construct_properties
  );

  session = INF_ADOPTED_SESSION(object);
  priv = INF_ADOPTED_SESSION_PRIVATE(session);

  g_assert(priv->io != NULL);
  g_object_get(G_OBJECT(session), "status", &status, NULL);

  user_table = inf_session_get_user_table(INF_SESSION(session));

  g_signal_connect(
    G_OBJECT(user_table),
    "add-local-user",
    G_CALLBACK(inf_adopted_session_add_local_user_cb),
    session
  );

  g_signal_connect(
    G_OBJECT(user_table),
    "remove-local-user",
    G_CALLBACK(inf_adopted_session_remove_local_user_cb),
    session
  );

  switch(status)
  {
  case INF_SESSION_PRESYNC:
  case INF_SESSION_SYNCHRONIZING:
    /* algorithm is created during initial synchronization when parameters
     * like initial vector time, max total log size etc. are known. */
    break;
  case INF_SESSION_RUNNING:
    g_assert(inf_session_get_buffer(INF_SESSION(session)) != NULL);
    inf_adopted_session_create_algorithm(session);

    break;
  case INF_SESSION_CLOSED:
    /* Session should not be initially closed */
  default:
    g_assert_not_reached();
    break;
  }

  /* Add initial local users. Note that this requires the algorithm to exist, 
   * though in synchronizing state no local users can exist. */
  inf_user_table_foreach_local_user(
    user_table,
    inf_adopted_session_constructor_foreach_local_user_func,
    session
  );

  return object;
}
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;
}
Esempio n. 17
0
void Gobby::UserJoinCommands::UserJoinInfo::attempt_user_join()
{
	const Preferences& preferences = m_commands.m_preferences;

	// Check if there is already a local user, for example for a
	// synced-in document.
	InfSession* session;
	g_object_get(G_OBJECT(m_proxy), "session", &session, NULL);

	InfUserTable* user_table = inf_session_get_user_table(session);
	InfUser* user = NULL;
	inf_user_table_foreach_local_user(user_table,
	                                  retr_local_user_func, &user);
	g_object_unref(session);

	if(user != NULL)
	{
		user_join_complete(user);
		return;
	}

	// Next, check whether we are allowed to join a user
	if(m_node.get_browser() && m_node.get_browser_iter())
	{
		InfBrowser* browser = m_node.get_browser();
		const InfBrowserIter* iter = m_node.get_browser_iter();
		const InfAclAccount* account =
			inf_browser_get_acl_local_account(browser);
		InfAclMask msk;
		inf_acl_mask_set1(&msk, INF_ACL_CAN_JOIN_USER);
		if(!inf_browser_check_acl(browser, iter, account, &msk, NULL))
		{
			set_permission_denied_text(m_view);
			finish();
			return;
		}
	}

	// We are allowed, so attempt to join the user now.
	std::vector<GParameter> params;
	const GParameter name_param = { "name", { 0 } };
	params.push_back(name_param);
	const GParameter status_param = { "status", { 0 } };
	params.push_back(status_param);

	g_value_init(&params[0].value, G_TYPE_STRING);
	g_value_init(&params[1].value, INF_TYPE_USER_STATUS);

	const Glib::ustring& pref_name = preferences.user.name;
	if(m_retry_index > 1)
	{
		gchar* name = g_strdup_printf(
			"%s %u", pref_name.c_str(), m_retry_index);
		g_value_take_string(&params[0].value, name);
	}
	else
	{
		g_value_set_static_string(
			&params[0].value, pref_name.c_str());
	}

	if(m_folder.get_current_document() == &m_view)
		g_value_set_enum(&params[1].value, INF_USER_ACTIVE);
	else
		g_value_set_enum(&params[1].value, INF_USER_INACTIVE);

	// Extra properties for text session:
	TextSessionView* text_view =
		dynamic_cast<TextSessionView*>(&m_view);
	if(text_view) add_text_user_properties(params, *text_view);

	GError* error = NULL;
	InfRequest* request = inf_session_proxy_join_user(
		m_proxy, params.size(), &params[0],
		on_user_join_finished_static, this);

	for(unsigned int i = 0; i < params.size(); ++i)
		g_value_unset(&params[i].value);

	if(request != NULL)
	{
		m_request = request;
		g_object_ref(m_request);
		m_view.set_info(_("User Join in progress..."), false);
	}
}
static void
sync_completed (InfSession       *session,
                InfXmlConnection *connection,
                gpointer          data)
{
	ChatData *cdata = (ChatData *)data;
	GeditPanel *panel;
	GeditCollaborationBookmark *bookmark;
	GeditCollaborationUser *user;
	GtkWidget *image;
	GtkWidget *hpaned;
	GtkWidget *sw;
	GtkWidget *tree_view;
	GeditCollaborationUserStore *store;
	InfUserTable *user_table;
	gchar *chat_name;

	g_signal_handlers_disconnect_by_func (session,
	                                      G_CALLBACK (sync_failed),
	                                      data);

	g_signal_handlers_disconnect_by_func (session,
	                                      G_CALLBACK (sync_completed),
	                                      data);

	bookmark = g_object_get_data (G_OBJECT (connection),
	                              BOOKMARK_DATA_KEY);

	if (bookmark)
	{
		user = gedit_collaboration_bookmark_get_user (bookmark);
	}
	else
	{
		user = gedit_collaboration_user_get_default ();
	}

	chat_name = get_chat_name (cdata->helper, connection);

	hpaned = gtk_hpaned_new ();
	gtk_widget_show (hpaned);

	gtk_paned_pack1 (GTK_PANED (hpaned), cdata->chat, TRUE, TRUE);
	gtk_widget_show (cdata->chat);

	build_user_view (cdata->helper, &tree_view, &sw, FALSE);
	gtk_widget_show (sw);
	user_table = inf_session_get_user_table (session);

	store = gedit_collaboration_user_store_new (user_table, FALSE);

	gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view),
				 GTK_TREE_MODEL (store));

	gtk_paned_pack2 (GTK_PANED (hpaned), sw, TRUE, TRUE);

	panel = gedit_window_get_bottom_panel (cdata->helper->priv->window);

	image = create_collaboration_image (cdata->helper);
	gedit_panel_add_item (panel,
	                      hpaned,
			      "GeditCollaborationChat",
			      chat_name ? chat_name : _("Chat"),
			      image);
	g_object_set_data (G_OBJECT (connection), CHAT_DATA_KEY, hpaned);

	cdata->user = gedit_collaboration_user_get_name (user);

	g_free (chat_name);
	request_join (cdata, cdata->user);
}
Esempio n. 19
0
void Gobby::UserJoin::attempt_user_join()
{
	// Check if there is already a local user, for example for a
	// synced-in document.
	InfSession* session;
	g_object_get(G_OBJECT(m_proxy), "session", &session, NULL);

	InfUserTable* user_table = inf_session_get_user_table(session);
	InfUser* user = NULL;
	inf_user_table_foreach_local_user(user_table,
	                                  retr_local_user_func, &user);
	g_object_unref(session);

	if(user != NULL)
	{
		user_join_complete(user, NULL);
		return;
	}

	// Next, check whether we are allowed to join a user
	if(m_node.get_browser() && m_node.get_browser_iter())
	{
		InfBrowser* browser = m_node.get_browser();
		const InfBrowserIter* iter = m_node.get_browser_iter();
		const InfAclAccount* account =
			inf_browser_get_acl_local_account(browser);
		const InfAclAccountId acc_id =
			(account != NULL) ? account->id : 0;
		InfAclMask msk;
		inf_acl_mask_set1(&msk, INF_ACL_CAN_JOIN_USER);
		if(!inf_browser_check_acl(browser, iter, acc_id, &msk, NULL))
		{
			GError* error = NULL;
			g_set_error(
				&error, inf_request_error_quark(),
				INF_REQUEST_ERROR_NOT_AUTHORIZED,
				"%s", inf_request_strerror(
					INF_REQUEST_ERROR_NOT_AUTHORIZED));
			user_join_complete(NULL, error);
			g_error_free(error);
			return;
		}
	}

	// We are allowed, so attempt to join the user now.
	std::vector<GParameter> params =
		m_param_provider->get_user_join_parameters();
	std::vector<GParameter>::iterator name_index =
		find_name_param(params);
	const gchar* name = g_value_get_string(&name_index->value);

	if(m_retry_index > 1)
	{
		gchar* new_name = g_strdup_printf(
			"%s %u", name, m_retry_index);
		g_value_take_string(&name_index->value, new_name);
	}

	GError* error = NULL;
	InfRequest* request = inf_session_proxy_join_user(
		m_proxy, params.size(), &params[0],
		on_user_join_finished_static, this);

	for(unsigned int i = 0; i < params.size(); ++i)
		g_value_unset(&params[i].value);

	if(request != NULL)
	{
		m_request = request;
		g_object_ref(m_request);
	}
}
Esempio n. 20
0
static gboolean
infc_session_proxy_handle_user_rejoin(InfcSessionProxy* proxy,
                                      InfXmlConnection* connection,
                                      xmlNodePtr xml,
                                      GError** error)
{
  InfcSessionProxyPrivate* priv;
  InfSessionClass* session_class;
  GArray* array;
  InfUser* user;
  const GParameter* idparam;
  GParameter* param;
  guint id;
  gboolean result;
  guint i;

  priv = INFC_SESSION_PROXY_PRIVATE(proxy);
  session_class = INF_SESSION_GET_CLASS(priv->session);

  array = session_class->get_xml_user_props(priv->session, connection, xml);

  /* Find rejoining user first */
  idparam = inf_session_lookup_user_property(
    (const GParameter*)array->data,
    array->len,
    "id"
  );

  if(idparam == NULL)
  {
    g_set_error(
      error,
      inf_request_error_quark(),
      INF_REQUEST_ERROR_NO_SUCH_ATTRIBUTE,
      _("Request does not contain required attribute 'id'")
    );

    goto error;
  }

  id = g_value_get_uint(&idparam->value);
  user = inf_user_table_lookup_user_by_id(
    inf_session_get_user_table(priv->session),
    id
  );

  if(user == NULL)
  {
    g_set_error(
      error,
      inf_user_error_quark(),
      INF_USER_ERROR_NO_SUCH_USER,
      _("No such user with ID %u"),
      id
    );

    goto error;
  }

  /* Set local flag if the join was requested by us (seq is present in
   * server response). */
  param = inf_session_get_user_property(array, "flags");
  g_assert(!G_IS_VALUE(&param->value)); /* must not have been set already */

  g_value_init(&param->value, INF_TYPE_USER_FLAGS);
  if(xmlHasProp(xml, (const xmlChar*)"seq") != NULL)
    g_value_set_flags(&param->value, INF_USER_LOCAL);
  else
    g_value_set_flags(&param->value, 0);

  /* Set connection. If none was given, use publisher connection */
  param = inf_session_get_user_property(array, "connection");
  if(!G_IS_VALUE(&param->value))
  {
    g_value_init(&param->value, INF_TYPE_XML_CONNECTION);
    g_value_set_object(&param->value, G_OBJECT(connection));
  }

  result = session_class->validate_user_props(
    priv->session,
    (const GParameter*)array->data,
    array->len,
    user,
    error
  );

  if(result == FALSE)
    goto error;

  /* Set properties on the found user object, performing the rejoin */
  g_object_freeze_notify(G_OBJECT(user));

  for(i = 0; i < array->len; ++ i)
  {
    param = &g_array_index(array, GParameter, i);

    /* Don't set ID because the ID is the same anyway (we did the user lookup
     * by it). The "id" property is construct only anyway. */
    if(strcmp(param->name, "id") != 0)
      g_object_set_property(G_OBJECT(user), param->name, &param->value);
  }

  /* TODO: Set user status to available, if the server did not send the
   * status property? Require the status property being set on a rejoin?
   * Make sure it is not unavailable? */

  g_object_thaw_notify(G_OBJECT(user));
  for(i = 0; i < array->len; ++ i)
    g_value_unset(&g_array_index(array, GParameter, i).value);
  g_array_free(array, TRUE);

  infc_session_proxy_succeed_user_request(proxy, xml, user);

  return TRUE;

error:
  for(i = 0; i < array->len; ++ i)
    g_value_unset(&g_array_index(array, GParameter, i).value);
  g_array_free(array, TRUE);
  return FALSE;
}