[folks/648811-dummy-backend-attempt3: 1/2] Another attempt at a dummy backend
- From: Philip Withnall <pwithnall src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [folks/648811-dummy-backend-attempt3: 1/2] Another attempt at a dummy backend
- Date: Wed, 22 May 2013 22:52:07 +0000 (UTC)
commit 479f6b18265eb53eea65da0d3ee77e943db3abe1
Author: Philip Withnall <philip tecnocode co uk>
Date: Sun Jul 22 21:26:11 2012 +0100
Another attempt at a dummy backend
This one has folks as a D-Bus client, and the tests as a D-Bus server.
Stalled because Vala doesn't natively support GDBusObjectManager, so
I'd be fighting Vala's D-Bus stuff all the way.
backends/Makefile.am | 2 +
backends/dummy/Makefile.am | 64 ++++
backends/dummy/dummy-backend-factory.vala | 60 ++++
backends/dummy/dummy-backend.vala | 210 +++++++++++++
backends/dummy/dummy-persona-store.vala | 250 +++++++++++++++
backends/dummy/dummy-persona.vala | 471 +++++++++++++++++++++++++++++
configure.ac | 8 +-
tests/lib/Makefile.am | 2 +
tests/lib/dummy/Makefile.am | 59 ++++
tests/lib/dummy/backend.vala | 51 +++
tests/lib/dummy/persona-store.vala | 91 ++++++
11 files changed, 1267 insertions(+), 1 deletions(-)
---
diff --git a/backends/Makefile.am b/backends/Makefile.am
index ec9659a..03628e2 100644
--- a/backends/Makefile.am
+++ b/backends/Makefile.am
@@ -1,4 +1,5 @@
SUBDIRS = \
+ dummy \
key-file \
$(NULL)
@@ -23,6 +24,7 @@ SUBDIRS += ofono
endif
DIST_SUBDIRS = \
+ dummy \
telepathy \
key-file \
tracker \
diff --git a/backends/dummy/Makefile.am b/backends/dummy/Makefile.am
new file mode 100644
index 0000000..428b06d
--- /dev/null
+++ b/backends/dummy/Makefile.am
@@ -0,0 +1,64 @@
+BACKEND_NAME = "dummy"
+
+backenddir = $(BACKEND_DIR)/dummy
+backend_LTLIBRARIES = dummy.la
+
+dummy_la_SOURCES = \
+ dummy-backend.vala \
+ dummy-backend-factory.vala \
+ dummy-persona-store.vala \
+ $(NULL)
+
+dummy_la_VALAFLAGS = \
+ $(AM_VALAFLAGS) \
+ $(ERROR_VALAFLAGS) \
+ --vapidir=. \
+ --vapidir=$(top_srcdir)/folks \
+ --pkg folks \
+ --pkg folks-internal \
+ --pkg gee-0.8 \
+ --pkg gio-2.0 \
+ --pkg gobject-2.0 \
+ $(NULL)
+
+dummy_la_CPPFLAGS = \
+ -I$(top_srcdir)/folks \
+ -include $(CONFIG_HEADER) \
+ -DPACKAGE_DATADIR=\"$(pkgdatadir)\" \
+ -DBACKEND_NAME=\"$(BACKEND_NAME)\" \
+ -DG_LOG_DOMAIN=\"$(BACKEND_NAME)\" \
+ $(NULL)
+
+dummy_la_CFLAGS = \
+ $(AM_CFLAGS) \
+ $(CODE_COVERAGE_CFLAGS) \
+ $(GIO_CFLAGS) \
+ $(GLIB_CFLAGS) \
+ $(GEE_CFLAGS) \
+ $(NULL)
+
+dummy_la_LIBADD = \
+ $(AM_LIBADD) \
+ $(GIO_LIBS) \
+ $(GLIB_LIBS) \
+ $(GEE_LIBS) \
+ $(top_builddir)/folks/libfolks.la \
+ $(top_builddir)/folks/libfolks-internal.la \
+ $(NULL)
+
+dummy_la_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ $(CODE_COVERAGE_LDFLAGS) \
+ -shared \
+ -fPIC \
+ -module \
+ -avoid-version \
+ $(NULL)
+
+GITIGNOREFILES = \
+ folks-backend-dummy.vapi \
+ $(dummy_la_SOURCES:.vala=.c) \
+ dummy_la_vala.stamp \
+ $(NULL)
+
+-include $(top_srcdir)/git.mk
diff --git a/backends/dummy/dummy-backend-factory.vala b/backends/dummy/dummy-backend-factory.vala
new file mode 100644
index 0000000..98c46c6
--- /dev/null
+++ b/backends/dummy/dummy-backend-factory.vala
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2009 Zeeshan Ali (Khattak) <zeeshanak gnome org>.
+ * Copyright (C) 2009 Nokia Corporation.
+ * Copyright (C) 2010 Collabora Ltd.
+ * Copyright (C) 2012 Philip Withnall
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Zeeshan Ali (Khattak) <zeeshanak gnome org>
+ * Travis Reitter <travis reitter collabora co uk>
+ * Philip Withnall <philip tecnocode co uk>
+ *
+ * This file was originally part of Rygel.
+ */
+
+using Folks;
+using Folks.Backends.Dummy;
+
+private BackendFactory _backend_factory = null;
+
+/**
+ * The backend module entry point.
+ */
+public void module_init (BackendStore backend_store)
+{
+ _backend_factory = new BackendFactory (backend_store);
+}
+
+/**
+ * The backend module exit point.
+ */
+public void module_finalize (BackendStore backend_store)
+{
+ _backend_factory = null;
+}
+
+/**
+ * A backend factory to create a single { link Backend}.
+ */
+public class Folks.Backends.Dummy.BackendFactory : Object
+{
+ /**
+ * { inheritDoc}
+ */
+ public BackendFactory (BackendStore backend_store)
+ {
+ backend_store.add_backend (new Backend ());
+ }
+}
diff --git a/backends/dummy/dummy-backend.vala b/backends/dummy/dummy-backend.vala
new file mode 100644
index 0000000..25c42a0
--- /dev/null
+++ b/backends/dummy/dummy-backend.vala
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2012 Philip Withnall
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Philip Withnall <philip tecnocode co uk>
+ */
+
+using GLib;
+using Gee;
+using Folks;
+using Folks.Backends.Dummy;
+
+extern const string BACKEND_NAME;
+
+/* TODO: Had to fix DBusObjectManagerClient constructor in gio-2.0.vapi. */
+
+/**
+ * TODO A backend which loads { link Persona}s from a simple key file in
+ * (XDG_DATA_HOME/folks/) and presents them through a single
+ * { link PersonaStore}.
+ *
+ * @since UNRELEASED
+ */
+public class Folks.Backends.Dummy.Backend : Folks.Backend
+{
+ private bool _is_prepared = false;
+ private bool _prepare_pending = false; /* used for unprepare() too */
+ private bool _is_quiescent = false;
+ private HashMap<string, PersonaStore> _persona_stores;
+ private Map<string, PersonaStore> _persona_stores_ro;
+
+ /**
+ * Whether this Backend has been prepared.
+ *
+ * See { link Folks.Backend.is_prepared}.
+ *
+ * @since UNRELEASED
+ */
+ public override bool is_prepared
+ {
+ get { return this._is_prepared; }
+ }
+
+ /**
+ * Whether this Backend has reached a quiescent state.
+ *
+ * See { link Folks.Backend.is_quiescent}.
+ *
+ * @since UNRELEASED
+ */
+ public override bool is_quiescent
+ {
+ get { return this._is_quiescent; }
+ }
+
+ /**
+ * { inheritDoc}
+ *
+ * @since UNRELEASED
+ */
+ public override string name { get { return BACKEND_NAME; } }
+
+ /**
+ * { inheritDoc}
+ *
+ * @since UNRELEASED
+ */
+ public override Map<string, PersonaStore> persona_stores
+ {
+ get { return this._persona_stores_ro; }
+ }
+
+ construct
+ {
+ this._persona_stores = new HashMap<string, PersonaStore> ();
+ this._persona_stores_ro = this._persona_stores.read_only_view;
+ }
+
+ /**
+ * { inheritDoc}
+ *
+ * @since UNRELEASED
+ */
+ public override async void prepare () throws GLib.Error
+ {
+ Internal.profiling_start ("preparing Dummy.Backend");
+
+ if (this._is_prepared || this._prepare_pending)
+ {
+ return;
+ }
+
+ try
+ {
+ this._prepare_pending = true;
+
+ DBusProxyTypeFunc f = null; /* TODO */
+
+ var connection = yield Bus get (BusType.SESSION);
+ var client = yield DBusObjectManagerClient new (connection,
DBusObjectManagerClientFlags.DO_NOT_AUTO_START,
+ "org.freedesktop.Folks.DummyBackend", "/org/freedesktop/Folks/DummyBackend", (owned) f);
+
+ if (client.name_owner == null)
+ {
+ /* TODO: Manager doesn't exist. */
+ return;
+ }
+
+ /* Connect to signals and create the persona stores. */
+ client.object_added.connect (this._dbus_persona_store_added_cb);
+ client.object_removed.connect (this._dbus_persona_store_removed_cb);
+
+ this.freeze_notify ();
+
+ foreach (var persona_store in client.get_objects ())
+ {
+ this._dbus_persona_store_added_cb (persona_store);
+ }
+
+ this.thaw_notify ();
+
+ this._is_prepared = true;
+ this.notify_property ("is-prepared");
+
+ this._is_quiescent = true;
+ this.notify_property ("is-quiescent");
+ }
+ finally
+ {
+ this._prepare_pending = false;
+ }
+
+ Internal.profiling_end ("preparing Dummy.Backend");
+ }
+
+ /**
+ * { inheritDoc}
+ *
+ * @since UNRELEASED
+ */
+ public override async void unprepare () throws GLib.Error
+ {
+ if (!this._is_prepared || this._prepare_pending == true)
+ {
+ return;
+ }
+
+ try
+ {
+ this._prepare_pending = true;
+
+ foreach (var persona_store in this._persona_stores.values)
+ {
+ this.persona_store_removed (persona_store);
+ }
+
+ this._persona_stores.clear ();
+ this.notify_property ("persona-stores");
+
+ this._is_quiescent = false;
+ this.notify_property ("is-quiescent");
+
+ this._is_prepared = false;
+ this.notify_property ("is-prepared");
+ }
+ finally
+ {
+ this._prepare_pending = false;
+ }
+ }
+
+ private void _dbus_persona_store_added_cb (DBusObject _dbus_store)
+ {
+ var dbus_store = _dbus_store as DummyPersonaStore;
+ assert (dbus_store != null);
+
+ var store = new Dummy.PersonaStore (dbus_store);
+
+ this._persona_stores.set (dbus_store.id, store);
+ this.notify_property ("persona-stores");
+ this.persona_store_added (store);
+ }
+
+ private void _dbus_persona_store_removed_cb (DBusObject _dbus_store)
+ {
+ var dbus_store = _dbus_store as DummyPersonaStore;
+ assert (dbus_store != null);
+
+ PersonaStore store;
+
+ if (this._persona_stores.unset (dbus_store.id, out store) == true)
+ {
+ this.notify_property ("persona-stores");
+ this.persona_store_removed (store);
+ }
+ }
+}
diff --git a/backends/dummy/dummy-persona-store.vala b/backends/dummy/dummy-persona-store.vala
new file mode 100644
index 0000000..1ceaf68
--- /dev/null
+++ b/backends/dummy/dummy-persona-store.vala
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2012 Philip Withnall
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Philip Withnall <philip tecnocode co uk>
+ */
+
+using GLib;
+using Gee;
+using Folks;
+using Folks.Backends.Dummy;
+
+/* TODO: Share this between dummy-persona-store.vala and persona-store.vala? */
+[DBus (name = "org.freedesktop.Folks.DummyBackend.PersonaStore")]
+public interface DummyPersonaStore : Object
+{
+ public abstract string id { owned get; }
+ public abstract string display_name { owned get; }
+ public abstract PersonaStoreTrust trust_level { get; set; }
+
+ /* These are bool rather than MaybeBool because we never actually use MAYBE */
+ public abstract bool can_add_personas { get; }
+ public abstract bool can_alias_personas { get; }
+ public abstract bool can_group_personas { get; }
+ public abstract bool can_remove_personas { get; }
+
+ public abstract bool is_prepared { get; }
+ public abstract bool is_quiescent { get; }
+
+ public abstract string[] always_writeable_properties { owned get; }
+
+ public abstract async void prepare () throws GLib.Error;
+}
+
+/**
+ * TODO A persona store which is associated with a single simple key file. It will
+ * create a { link Persona} for each of the groups in the key file.
+ *
+ * @since UNRELEASED
+ */
+public class Folks.Backends.Dummy.PersonaStore : Folks.PersonaStore
+{
+ private DummyPersonaStore _dbus_store;
+
+ private HashMap<string, Persona> _personas;
+ private Map<string, Persona> _personas_ro;
+
+ /**
+ * { inheritDoc}
+ *
+ * @since UNRELEASED
+ */
+ public override string type_id { get { return BACKEND_NAME; } }
+
+ /**
+ * Whether this PersonaStore can add { link Folks.Persona}s.
+ *
+ * See { link Folks.PersonaStore.can_add_personas}.
+ *
+ * @since UNRELEASED
+ */
+ public override MaybeBool can_add_personas
+ {
+ get
+ {
+ return this._dbus_store.can_add_personas
+ ? MaybeBool.TRUE : MaybeBool.FALSE;
+ }
+ }
+
+ /**
+ * Whether this PersonaStore can set the alias of { link Folks.Persona}s.
+ *
+ * See { link Folks.PersonaStore.can_alias_personas}.
+ *
+ * @since UNRELEASED
+ */
+ public override MaybeBool can_alias_personas
+ {
+ get
+ {
+ return this._dbus_store.can_alias_personas
+ ? MaybeBool.TRUE : MaybeBool.FALSE;
+ }
+ }
+
+ /**
+ * Whether this PersonaStore can set the groups of { link Folks.Persona}s.
+ *
+ * See { link Folks.PersonaStore.can_group_personas}.
+ *
+ * @since UNRELEASED
+ */
+ public override MaybeBool can_group_personas
+ {
+ get
+ {
+ return this._dbus_store.can_group_personas
+ ? MaybeBool.TRUE : MaybeBool.FALSE;
+ }
+ }
+
+ /**
+ * Whether this PersonaStore can remove { link Folks.Persona}s.
+ *
+ * See { link Folks.PersonaStore.can_remove_personas}.
+ *
+ * @since UNRELEASED
+ */
+ public override MaybeBool can_remove_personas
+ {
+ get
+ {
+ return this._dbus_store.can_remove_personas
+ ? MaybeBool.TRUE : MaybeBool.FALSE;
+ }
+ }
+
+ /**
+ * Whether this PersonaStore has been prepared.
+ *
+ * See { link Folks.PersonaStore.is_prepared}.
+ *
+ * @since UNRELEASED
+ */
+ public override bool is_prepared
+ {
+ get { return this._dbus_store.is_prepared; }
+ }
+
+ /**
+ * Whether this PersonaStore has reached a quiescent state.
+ *
+ * See { link Folks.PersonaStore.is_quiescent}.
+ *
+ * @since UNRELEASED
+ */
+ public override bool is_quiescent
+ {
+ get { return this._dbus_store.is_quiescent; }
+ }
+
+ private string[] _always_writeable_properties;
+
+ /**
+ * { inheritDoc}
+ *
+ * @since UNRELEASED
+ */
+ public override string[] always_writeable_properties
+ {
+ get
+ {
+ this._always_writeable_properties =
+ this._dbus_store.always_writeable_properties;
+ return this._always_writeable_properties;
+ }
+ }
+
+ /**
+ * { inheritDoc}
+ *
+ * @since UNRELEASED
+ */
+ public override Map<string, Persona> personas
+ {
+ get { return this._personas_ro; }
+ }
+
+ construct
+ {
+ this._personas = new HashMap<string, Persona> ();
+ this._personas_ro = this._personas.read_only_view;
+ }
+
+ /**
+ * TODO
+ *
+ * @since UNRELEASED
+ */
+ public PersonaStore (DummyPersonaStore dbus_store)
+ {
+ this._dbus_store = dbus_store;
+
+ Object (id: dbus_store.id,
+ display_name: dbus_store.display_name,
+ trust_level: dbus_store.trust_level);
+ }
+
+ /**
+ * { inheritDoc}
+ *
+ * @since UNRELEASED
+ */
+ public override async void prepare () throws GLib.Error
+ {
+ Internal.profiling_start ("preparing Dummy.PersonaStore (ID: %s)",
+ this.id);
+
+ yield this._dbus_store.prepare ();
+
+ Internal.profiling_end ("preparing Dummy.PersonaStore (ID: %s)", this.id);
+ }
+
+ /**
+ * { inheritDoc}
+ *
+ * @since UNRELEASED
+ */
+ public override async void remove_persona (Folks.Persona persona)
+ {
+ debug ("Removing Persona '%s' (IID '%s', group '%s')", persona.uid,
+ persona.iid, persona.display_id);
+
+ /* TODO */
+ }
+
+ /**
+ * Add a new { link Persona} to the PersonaStore.
+ *
+ * Accepted keys for `details` are:
+ * - PersonaStore.detail_key (PersonaDetail.IM_ADDRESSES)
+ * - PersonaStore.detail_key (PersonaDetail.WEB_SERVICE_ADDRESSES)
+ *
+ * See { link Folks.PersonaStore.add_persona_from_details}.
+ *
+ * @throws Folks.PersonaStoreError.CREATE_FAILED if setting the persona’s
+ * properties failed
+ * @since UNRELEASED
+ */
+ public override async Folks.Persona? add_persona_from_details (
+ HashTable<string, Value?> details) throws Folks.PersonaStoreError
+ {
+ /* TODO */
+ return null;
+ }
+}
diff --git a/backends/dummy/dummy-persona.vala b/backends/dummy/dummy-persona.vala
new file mode 100644
index 0000000..05b471d
--- /dev/null
+++ b/backends/dummy/dummy-persona.vala
@@ -0,0 +1,471 @@
+/*
+ * Copyright (C) 2010 Collabora Ltd.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Philip Withnall <philip withnall collabora co uk>
+ */
+
+using GLib;
+using Gee;
+using Folks;
+using Folks.Backends.Kf;
+
+/**
+ * A persona subclass which represents a single persona from a simple key file.
+ *
+ * @since 0.1.13
+ */
+public class Folks.Backends.Kf.Persona : Folks.Persona,
+ AliasDetails,
+ AntiLinkable,
+ ImDetails,
+ WebServiceDetails
+{
+ private HashMultiMap<string, ImFieldDetails> _im_addresses;
+ private HashMultiMap<string, WebServiceFieldDetails> _web_service_addresses;
+ private string _alias = ""; /* must not be null */
+ private const string[] _linkable_properties =
+ {
+ "im-addresses",
+ "web-service-addresses"
+ };
+ private const string[] _writeable_properties =
+ {
+ "alias",
+ "im-addresses",
+ "web-service-addresses",
+ "anti-links"
+ };
+
+ /**
+ * { inheritDoc}
+ */
+ public override string[] linkable_properties
+ {
+ get { return this._linkable_properties; }
+ }
+
+ /**
+ * { inheritDoc}
+ *
+ * @since 0.6.0
+ */
+ public override string[] writeable_properties
+ {
+ get { return this._writeable_properties; }
+ }
+
+ /**
+ * { inheritDoc}
+ *
+ * @since 0.1.15
+ */
+ [CCode (notify = false)]
+ public string alias
+ {
+ get { return this._alias; }
+ set { this.change_alias.begin (value); }
+ }
+
+ /**
+ * { inheritDoc}
+ *
+ * @since 0.6.2
+ */
+ public async void change_alias (string alias) throws PropertyError
+ {
+ /* Deal with badly-behaved callers. */
+ if (alias == null)
+ {
+ alias = "";
+ }
+
+ if (this._alias == alias)
+ {
+ return;
+ }
+
+ debug ("Setting alias of Kf.Persona '%s' to '%s'.", this.uid, alias);
+
+ unowned KeyFile key_file = ((Kf.PersonaStore) this.store).get_key_file ();
+ key_file.set_string (this.display_id, "__alias", alias);
+ yield ((Kf.PersonaStore) this.store).save_key_file ();
+
+ this._alias = alias;
+ this.notify_property ("alias");
+ }
+
+ /**
+ * { inheritDoc}
+ */
+ [CCode (notify = false)]
+ public MultiMap<string, ImFieldDetails> im_addresses
+ {
+ get { return this._im_addresses; }
+ set { this.change_im_addresses.begin (value); }
+ }
+
+ /**
+ * { inheritDoc}
+ *
+ * @since 0.6.2
+ */
+ public async void change_im_addresses (
+ MultiMap<string, ImFieldDetails> im_addresses) throws PropertyError
+ {
+ unowned KeyFile key_file = ((Kf.PersonaStore) this.store).get_key_file ();
+
+ /* Remove the current IM addresses from the key file */
+ foreach (var protocol1 in this._im_addresses.get_keys ())
+ {
+ try
+ {
+ key_file.remove_key (this.display_id, protocol1);
+ }
+ catch (KeyFileError e1)
+ {
+ /* Ignore the error, since it's just a group or key not found
+ * error. */
+ }
+ }
+
+ /* Add the new IM addresses to the key file and build a normalised
+ * table of them to set as the new property value */
+ var new_im_addresses = new HashMultiMap<string, ImFieldDetails> (
+ null, null,
+ AbstractFieldDetails<string>.hash_static,
+ AbstractFieldDetails<string>.equal_static);
+
+ foreach (var protocol2 in im_addresses.get_keys ())
+ {
+ var addresses = im_addresses.get (protocol2);
+ var normalised_addresses = new HashSet<string> ();
+
+ foreach (var im_fd in addresses)
+ {
+ string normalised_address;
+ try
+ {
+ normalised_address = ImDetails.normalise_im_address (
+ im_fd.value, protocol2);
+ }
+ catch (ImDetailsError e2)
+ {
+ throw new PropertyError.INVALID_VALUE (
+ /* Translators: this is an error message for if the user
+ * provides an invalid IM address. The first parameter is
+ * an IM address (e.g. “foo jabber org”), the second is
+ * the name of a protocol (e.g. “jabber”) and the third is
+ * an error message. */
+ _("Invalid IM address ‘%s’ for protocol ‘%s’: %s"),
+ im_fd.value, protocol2, e2.message);
+ }
+
+ normalised_addresses.add (normalised_address);
+ var new_im_fd = new ImFieldDetails (normalised_address);
+ new_im_addresses.set (protocol2, new_im_fd);
+ }
+
+ string[] addrs = (string[]) normalised_addresses.to_array ();
+ addrs.length = normalised_addresses.size;
+
+ key_file.set_string_list (this.display_id, protocol2, addrs);
+ }
+
+ /* Get the PersonaStore to save the key file */
+ yield ((Kf.PersonaStore) this.store).save_key_file ();
+
+ this._im_addresses = new_im_addresses;
+ this.notify_property ("im-addresses");
+ }
+
+ /**
+ * { inheritDoc}
+ */
+ [CCode (notify = false)]
+ public MultiMap<string, WebServiceFieldDetails> web_service_addresses
+ {
+ get { return this._web_service_addresses; }
+ set { this.change_web_service_addresses.begin (value); }
+ }
+
+ /**
+ * { inheritDoc}
+ *
+ * @since 0.6.2
+ */
+ public async void change_web_service_addresses (
+ MultiMap<string, WebServiceFieldDetails> web_service_addresses)
+ throws PropertyError
+ {
+ unowned KeyFile key_file = ((Kf.PersonaStore) this.store).get_key_file ();
+
+ /* Remove the current web service addresses from the key file */
+ foreach (var web_service1 in this._web_service_addresses.get_keys ())
+ {
+ try
+ {
+ key_file.remove_key (this.display_id,
+ "web-service." + web_service1);
+ }
+ catch (KeyFileError e)
+ {
+ /* Ignore the error, since it's just a group or key not found
+ * error. */
+ }
+ }
+
+ /* Add the new web service addresses to the key file and build a
+ * table of them to set as the new property value */
+ var new_web_service_addresses =
+ new HashMultiMap<string, WebServiceFieldDetails> (
+ null, null,
+ AbstractFieldDetails<string>.hash_static,
+ AbstractFieldDetails<string>.equal_static);
+
+ foreach (var web_service2 in web_service_addresses.get_keys ())
+ {
+ var ws_fds = web_service_addresses.get (web_service2);
+
+ string[] addrs = new string[0];
+ foreach (var ws_fd1 in ws_fds)
+ addrs += ws_fd1.value;
+
+ key_file.set_string_list (this.display_id,
+ "web-service." + web_service2, addrs);
+
+ foreach (var ws_fd2 in ws_fds)
+ new_web_service_addresses.set (web_service2, ws_fd2);
+ }
+
+ /* Get the PersonaStore to save the key file */
+ yield ((Kf.PersonaStore) this.store).save_key_file ();
+
+ this._web_service_addresses = new_web_service_addresses;
+ this.notify_property ("web-service-addresses");
+ }
+
+ private HashSet<string> _anti_links;
+ private Set<string> _anti_links_ro;
+
+ /**
+ * { inheritDoc}
+ *
+ * @since UNRELEASED
+ */
+ [CCode (notify = false)]
+ public Set<string> anti_links
+ {
+ get { return this._anti_links_ro; }
+ set { this.change_anti_links.begin (value); }
+ }
+
+ /**
+ * { inheritDoc}
+ *
+ * @since UNRELEASED
+ */
+ public async void change_anti_links (Set<string> anti_links)
+ throws PropertyError
+ {
+ if (Folks.Internal.equal_sets<string> (anti_links, this.anti_links))
+ {
+ return;
+ }
+
+ unowned KeyFile key_file = ((Kf.PersonaStore) this.store).get_key_file ();
+
+ /* Skip the persona's UID; don't allow reflexive anti-links. */
+ anti_links.remove (this.uid);
+
+ key_file.set_string_list (this.display_id,
+ Kf.PersonaStore.anti_links_key_name, anti_links.to_array ());
+
+ /* Get the PersonaStore to save the key file */
+ yield ((Kf.PersonaStore) this.store).save_key_file ();
+
+ /* Update the stored anti-links. */
+ this._anti_links.clear ();
+ this._anti_links.add_all (anti_links);
+ this.notify_property ("anti-links");
+ }
+
+ /**
+ * Create a new persona.
+ *
+ * Create a new persona for the { link PersonaStore} `store`, representing
+ * the Persona given by the group `uid` in the key file `key_file`.
+ */
+ public Persona (string id, Folks.PersonaStore store)
+ {
+ var iid = store.id + ":" + id;
+ var uid = this.build_uid ("key-file", store.id, id);
+
+ Object (display_id: id,
+ iid: iid,
+ uid: uid,
+ store: store,
+ is_user: false);
+ }
+
+ construct
+ {
+ debug ("Adding key-file Persona '%s' (IID '%s', group '%s')", this.uid,
+ this.iid, this.display_id);
+
+ this._im_addresses = new HashMultiMap<string, ImFieldDetails> (
+ null, null, AbstractFieldDetails<string>.hash_static,
+ AbstractFieldDetails<string>.equal_static);
+ this._web_service_addresses =
+ new HashMultiMap<string, WebServiceFieldDetails> (
+ null, null,
+ AbstractFieldDetails<string>.hash_static,
+ AbstractFieldDetails<string>.equal_static);
+ this._anti_links = new HashSet<string> ();
+ this._anti_links_ro = this._anti_links.read_only_view;
+
+ /* Load the IM addresses from the key file */
+ unowned KeyFile key_file = ((Kf.PersonaStore) this.store).get_key_file ();
+
+ try
+ {
+ var keys = key_file.get_keys (this.display_id);
+ foreach (unowned string key in keys)
+ {
+ /* Alias */
+ if (key == "__alias")
+ {
+ this._alias = key_file.get_string (this.display_id, key);
+
+ if (this._alias == null)
+ {
+ this._alias = "";
+ }
+
+ debug (" Loaded alias '%s'.", this._alias);
+ continue;
+ }
+
+ /* Anti-links. */
+ if (key == Kf.PersonaStore.anti_links_key_name)
+ {
+ var anti_link_array =
+ key_file.get_string_list (this.display_id, key);
+
+ if (anti_link_array != null)
+ {
+ foreach (var anti_link in anti_link_array)
+ {
+ this._anti_links.add (anti_link);
+ }
+
+ debug (" Loaded %u anti-links.",
+ anti_link_array.length);
+ continue;
+ }
+ }
+
+ /* Web service addresses */
+ var decomposed_key = key.split(".", 2);
+ if (decomposed_key.length == 2 &&
+ decomposed_key[0] == "web-service")
+ {
+ unowned string web_service = decomposed_key[1];
+ var web_service_addresses = key_file.get_string_list (
+ this.display_id, web_service);
+
+ foreach (var web_service_address in web_service_addresses)
+ {
+ this._web_service_addresses.set (web_service,
+ new WebServiceFieldDetails (web_service_address));
+ }
+
+ continue;
+ }
+
+ /* IM addresses */
+ unowned string protocol = key;
+ var im_addresses = key_file.get_string_list (
+ this.display_id, protocol);
+
+ foreach (var im_address in im_addresses)
+ {
+ string address;
+ try
+ {
+ address = ImDetails.normalise_im_address (im_address,
+ protocol);
+ }
+ catch (ImDetailsError e)
+ {
+ /* Warn of and ignore any invalid IM addresses */
+ warning (e.message);
+ continue;
+ }
+
+ var im_fd = new ImFieldDetails (address);
+ this._im_addresses.set (protocol, im_fd);
+ }
+ }
+ }
+ catch (KeyFileError e)
+ {
+ /* We get a GROUP_NOT_FOUND exception if we're creating a new
+ * Persona, since it doesn't yet exist in the key file. We shouldn't
+ * get any other exceptions, since we're iterating through a list of
+ * keys we've just retrieved. */
+ if (!(e is KeyFileError.GROUP_NOT_FOUND))
+ {
+ /* Translators: the parameter is an error message. */
+ warning (_("Couldn't load data from key file: %s"), e.message);
+ }
+ }
+ }
+
+ /**
+ * { inheritDoc}
+ */
+ public override void linkable_property_to_links (string prop_name,
+ Folks.Persona.LinkablePropertyCallback callback)
+ {
+ if (prop_name == "im-addresses")
+ {
+ foreach (var protocol in this._im_addresses.get_keys ())
+ {
+ var im_addresses = this._im_addresses.get (protocol);
+
+ foreach (var im_fd in im_addresses)
+ callback (protocol + ":" + im_fd.value);
+ }
+ }
+ else if (prop_name == "web-service-addresses")
+ {
+ foreach (var web_service in this.web_service_addresses.get_keys ())
+ {
+ var web_service_addresses =
+ this._web_service_addresses.get (web_service);
+
+ foreach (var ws_fd in web_service_addresses)
+ callback (web_service + ":" + ws_fd.value);
+ }
+ }
+ else
+ {
+ /* Chain up */
+ base.linkable_property_to_links (prop_name, callback);
+ }
+ }
+}
diff --git a/configure.ac b/configure.ac
index aadec2e..229e294 100644
--- a/configure.ac
+++ b/configure.ac
@@ -263,6 +263,7 @@ AS_IF([test \
! -e ${sd}tests/folks/backend_loading_vala.stamp -o \
! -e ${sd}tests/key-file/individual_retrieval_vala.stamp -o \
! -e ${sd}tests/lib/folks-test.vapi -o \
+ ! -e ${sd}tests/lib/dummy/dummy-test.vapi -o \
! -e ${sd}tests/lib/key-file/kf-test.vapi -o \
! -e ${sd}tests/lib/key-file/libkf_test_la_vala.stamp -o \
! -e ${sd}tests/lib/telepathy/contactlist/tp-test-contactlist.gir -o \
@@ -272,6 +273,7 @@ AS_IF([test \
! -e ${sd}tests/telepathy/individual_retrieval_vala.stamp -o \
! -e ${sd}tests/telepathy/individual_properties_vala.stamp -o \
! -e ${sd}tests/folks/backend_loading_vala.stamp -o \
+ ! -e ${sd}backends/dummy/dummy_la_vala.stamp -o \
! -e ${sd}backends/key-file/key_file_la_vala.stamp -o \
! -e ${sd}backends/telepathy/telepathy_la_vala.stamp \
-o \
@@ -352,6 +354,8 @@ AC_DEFINE([MODULE_VERSION], "folks_module_version", [Module interface version])
BACKEND_DIR='$(libdir)/folks/$(FOLKS_MODULE_VERSION)/backends'
AC_SUBST([BACKEND_DIR])
+BACKEND_DUMMY='$(top_builddir)/backends/dummy/.libs/dummy.so'
+AC_SUBST([BACKEND_DUMMY])
BACKEND_KF='$(top_builddir)/backends/key-file/.libs/key-file.so'
AC_SUBST([BACKEND_KF])
BACKEND_TP='$(top_builddir)/backends/telepathy/.libs/telepathy.so'
@@ -378,7 +382,7 @@ if test x$enable_ofono_backend = xyes; then
fi
# All of the backend libraries in our tree; to be used by the tests
-BACKEND_UNINST_PATH='$(BACKEND_KF):$(BACKEND_TP)'
+BACKEND_UNINST_PATH='$(BACKEND_DUMMY):$(BACKEND_KF):$(BACKEND_TP)'
AS_IF([test x$have_libsocialweb_backend = xyes], [
LIBSOCIALWEB_BACKEND_UNINST_PATH='$(BACKEND_LIBSOCIALWEB)'
BACKEND_UNINST_PATH="$BACKEND_UNINST_PATH:$LIBSOCIALWEB_BACKEND_UNINST_PATH"
@@ -634,6 +638,7 @@ AC_CONFIG_FILES([
folks/org.freedesktop.folks.gschema.xml
Makefile
backends/Makefile
+ backends/dummy/Makefile
backends/key-file/Makefile
backends/libsocialweb/Makefile
backends/libsocialweb/lib/Makefile
@@ -659,6 +664,7 @@ AC_CONFIG_FILES([
tests/tracker/Makefile
tests/lib/Makefile
tests/lib/folks-test-uninstalled.pc
+ tests/lib/dummy/Makefile
tests/lib/eds/Makefile
tests/lib/key-file/Makefile
tests/lib/libsocialweb/Makefile
diff --git a/tests/lib/Makefile.am b/tests/lib/Makefile.am
index bcaf81d..f11ed70 100644
--- a/tests/lib/Makefile.am
+++ b/tests/lib/Makefile.am
@@ -1,4 +1,5 @@
SUBDIRS = \
+ dummy \
key-file \
$(NULL)
@@ -19,6 +20,7 @@ SUBDIRS += eds
endif
DIST_SUBDIRS = \
+ dummy \
key-file \
telepathy \
eds \
diff --git a/tests/lib/dummy/Makefile.am b/tests/lib/dummy/Makefile.am
new file mode 100644
index 0000000..581dd0e
--- /dev/null
+++ b/tests/lib/dummy/Makefile.am
@@ -0,0 +1,59 @@
+noinst_LTLIBRARIES = libdummy-test.la
+
+libdummy_test_la_SOURCES = \
+ backend.vala \
+ persona-store.vala \
+ $(NULL)
+
+libdummy_test_la_VALAFLAGS = \
+ $(AM_VALAFLAGS) \
+ $(ERROR_VALAFLAGS) \
+ --library=dummy-test \
+ --header=dummy-test.h \
+ --vapidir=. \
+ --vapidir=$(top_srcdir)/folks \
+ --pkg folks \
+ --pkg folks-internal \
+ --pkg gee-0.8 \
+ --pkg gio-2.0 \
+ --pkg gobject-2.0 \
+ $(NULL)
+
+libdummy_test_la_CPPFLAGS = \
+ -I$(top_srcdir)/folks \
+ -include $(CONFIG_HEADER) \
+ -DPACKAGE_DATADIR=\"$(pkgdatadir)\" \
+ -DG_LOG_DOMAIN=\"$(BACKEND_NAME)\" \
+ $(NULL)
+
+libdummy_test_la_CFLAGS = \
+ $(AM_CFLAGS) \
+ $(GIO_CFLAGS) \
+ $(GLIB_CFLAGS) \
+ $(GEE_CFLAGS) \
+ $(NULL)
+
+libdummy_test_la_LIBADD = \
+ $(AM_LIBADD) \
+ $(GIO_LIBS) \
+ $(GLIB_LIBS) \
+ $(GEE_LIBS) \
+ $(top_builddir)/folks/libfolks.la \
+ $(NULL)
+
+MAINTAINERCLEANFILES = \
+ dummy-test.vapi \
+ dummy-test.h \
+ $(NULL)
+
+EXTRA_DIST = \
+ dummy-test.vapi \
+ dummy-test.h \
+ $(NULL)
+
+GITIGNOREFILES = \
+ $(libdummy_test_la_SOURCES:.vala=.c) \
+ libdummy_test_la_vala.stamp \
+ $(NULL)
+
+-include $(top_srcdir)/git.mk
diff --git a/tests/lib/dummy/backend.vala b/tests/lib/dummy/backend.vala
new file mode 100644
index 0000000..c7bd3d2
--- /dev/null
+++ b/tests/lib/dummy/backend.vala
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2012 Philip Withnall
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Philip Withnall <philip tecnocode co uk>
+ */
+
+public class DummyTest.Backend
+{
+ private DBusObjectManagerServer _manager;
+
+ public async void set_up () throws GLib.Error
+ {
+ /* Create a new D-Bus object manager for our persona stores. */
+ this._manager =
+ new DBusObjectManagerServer ("/org/freedesktop/Folks/DummyBackend");
+ var connection = yield Bus get (BusType.SESSION);
+
+ /* Export the manager on the bus. */
+ this._manager.connection = connection;
+ }
+
+ public async void tear_down () throws GLib.Error
+ {
+ /* Remove the manager from the bus. */
+ this._manager.connection = null;
+ }
+
+ public void export_persona_store (PersonaStore persona_store)
+ {
+ this._manager.export (persona_store);
+ }
+
+ public void unexport_persona_store (PersonaStore persona_store)
+ {
+ this._manager.unexport (persona_store.g_object_path);
+ }
+}
diff --git a/tests/lib/dummy/persona-store.vala b/tests/lib/dummy/persona-store.vala
new file mode 100644
index 0000000..045e44b
--- /dev/null
+++ b/tests/lib/dummy/persona-store.vala
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2012 Philip Withnall
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Philip Withnall <philip tecnocode co uk>
+ */
+
+using GLib;
+using Gee;
+using Folks;
+
+[DBus (name = "org.freedesktop.Folks.DummyBackend.PersonaStore")]
+public interface DummyPersonaStore : Object
+{
+ public abstract string id { owned get; }
+ public abstract string display_name { owned get; }
+ public abstract PersonaStoreTrust trust_level { get; set; }
+
+ /* These are bool rather than MaybeBool because we never actually use MAYBE */
+ public abstract bool can_add_personas { get; }
+ public abstract bool can_alias_personas { get; }
+ public abstract bool can_group_personas { get; }
+ public abstract bool can_remove_personas { get; }
+
+ public abstract bool is_prepared { get; }
+ public abstract bool is_quiescent { get; }
+
+ public abstract string[] always_writeable_properties { owned get; }
+
+ public abstract async void prepare () throws GLib.Error;
+}
+
+[DBus (name = "org.freedesktop.Folks.DummyBackend.PersonaStore")]
+public class DummyTest.PersonaStore : DBusObjectSkeleton
+{
+ private string _id;
+ public string id { owned get { return this._id; } }
+
+ private string _display_name;
+ public string display_name { owned get { return this._display_name; } }
+
+ public PersonaStoreTrust trust_level { get; set; }
+
+ /* These are bool rather than MaybeBool because we never actually use MAYBE */
+ private bool _can_add_personas;
+ public bool can_add_personas { get { return this._can_add_personas; } }
+
+ private bool _can_alias_personas;
+ public bool can_alias_personas { get { return this._can_alias_personas; } }
+
+ private bool _can_group_personas;
+ public bool can_group_personas { get { return this._can_group_personas; } }
+
+ private bool _can_remove_personas;
+ public bool can_remove_personas { get { return this._can_remove_personas; } }
+
+ private bool _is_prepared;
+ public bool is_prepared { get { return this._is_prepared; } }
+
+ private bool _is_quiescent;
+ public bool is_quiescent { get { return this._is_quiescent; } }
+
+ private string[] _always_writeable_properties;
+ public string[] always_writeable_properties { owned get { return this._always_writeable_properties /* TODO
*/; } }
+
+ public PersonaStore (string id, string display_name)
+ {
+ Object (g_object_path: "/org/freedesktop/Folks/DummyBackend/" + id);
+
+ this._id = id;
+ this._display_name = display_name;
+ }
+
+ public async void prepare () throws GLib.Error
+ {
+ message ("TODO");
+ }
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]