Factor out the Telepathy backend into a separate, loadable module.
authorTravis Reitter <travis.reitter@collabora.co.uk>
Wed, 2 Jun 2010 23:48:48 +0000 (16:48 -0700)
committerTravis Reitter <travis.reitter@collabora.co.uk>
Wed, 2 Jun 2010 23:48:48 +0000 (16:48 -0700)
22 files changed:
.gitignore
Makefile.am
backends/Makefile.am [new file with mode: 0644]
backends/telepathy/Makefile.am [new file with mode: 0644]
backends/telepathy/folks-backend-telepathy-uninstalled.pc.in [new file with mode: 0644]
backends/telepathy/folks-backend-telepathy.pc.in [new file with mode: 0644]
backends/telepathy/lowlevel.c [moved from folks/lowlevel.c with 100% similarity]
backends/telepathy/lowlevel.h [moved from folks/lowlevel.h with 100% similarity]
backends/telepathy/lowlevel.metadata [moved from folks/lowlevel.metadata with 100% similarity]
backends/telepathy/tp-backend-factory.vala [new file with mode: 0644]
backends/telepathy/tp-backend.vala [new file with mode: 0644]
backends/telepathy/tp-persona-store.vala [moved from folks/tp-persona-store.vala with 98% similarity]
backends/telepathy/tp-persona.vala [moved from folks/tp-persona.vala with 100% similarity]
configure.ac
folks/Makefile.am
folks/backend-store.vala [new file with mode: 0644]
folks/backend.vala [new file with mode: 0644]
folks/build-conf.vapi [new file with mode: 0644]
folks/folks-uninstalled.pc.in
folks/folks.pc.in
folks/individual-aggregator.vala
folks/persona-store.vala

index 6609bfa..e376efb 100644 (file)
@@ -48,7 +48,19 @@ Makefile.in
 /folks-*/
 /xmldocs.make
 
+/backends/telepathy/folks-backend-telepathy.h
+/backends/telepathy/folks-backend-telepathy.pc
+/backends/telepathy/folks-backend-telepathy-uninstalled.pc
+/backends/telepathy/folks-backend-telepathy.vapi
+/backends/telepathy/lowlevel.gi
+/backends/telepathy/lowlevel.vapi
+/backends/telepathy/tp-backend.c
+/backends/telepathy/tp-backend-factory.c
+/backends/telepathy/tp-persona.c
+/backends/telepathy/tp-persona-store.c
 /folks/alias.c
+/folks/backend.c
+/folks/backend-store.c
 /folks/capabilities.c
 /folks/individual.c
 /folks/individual-aggregator.c
@@ -60,9 +72,5 @@ Makefile.in
 /folks/folks-uninstalled.pc
 /folks/folks.vapi
 /folks/groups.c
-/folks/lowlevel.gi
-/folks/lowlevel.vapi
-/folks/tp-persona.c
-/folks/tp-persona-store.c
 
 /tests/test-*[^ch]
index eaf1050..1735ad1 100644 (file)
@@ -1,5 +1,6 @@
 SUBDIRS = \
        folks \
+       backends \
        $(NULL)
 
 ACLOCAL_AMFLAGS = -I m4
diff --git a/backends/Makefile.am b/backends/Makefile.am
new file mode 100644 (file)
index 0000000..280c5b1
--- /dev/null
@@ -0,0 +1,3 @@
+SUBDIRS = \
+       telepathy \
+       $(NULL)
diff --git a/backends/telepathy/Makefile.am b/backends/telepathy/Makefile.am
new file mode 100644 (file)
index 0000000..95acb3d
--- /dev/null
@@ -0,0 +1,150 @@
+GEN_INTROSPECT = $(shell pkg-config vala-1.0 --variable="gen_introspect")
+VAPIGEN = $(shell pkg-config vala-1.0 --variable="vapigen")
+
+AM_CPPFLAGS = \
+       $(LIBFOLKS_BACKEND_TELEPATHY_CFLAGS) \
+       $(LIBFOLKS_CFLAGS) \
+       -include $(CONFIG_HEADER) \
+       -DPACKAGE_DATADIR=\"$(pkgdatadir)\" \
+       $(NULL)
+
+# this seems to work, even if vim's syntax highlighting suggests otherwise
+VALAFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) pkg-config --variable=valaflags telepathy-vala)
+VALAFLAGS += --vapidir=. --vapidir=$(top_srcdir)/folks
+
+VALAFLAGS += \
+       --pkg build-conf \
+       --pkg folks \
+       --pkg gobject-2.0 \
+       --pkg gio-2.0 \
+       --pkg gee-1.0 \
+       --pkg gmodule-2.0 \
+       --pkg dbus-glib-1 \
+       --pkg telepathy-glib \
+       $(NULL)
+
+backenddir = $(libdir)/folks/backends/telepathy
+backend_LTLIBRARIES = libfolks-backend-telepathy.la
+noinst_LTLIBRARIES = liblowlevel.la
+
+liblowlevel_la_SOURCES = \
+       lowlevel.c \
+       lowlevel.h \
+       $(NULL)
+
+liblowlevel_la_CPPFLAGS = \
+       $(LIBLOWLEVEL_CFLAGS) \
+       $(NULL)
+
+# the -shared and -rpath arguments are to force it to be compiled to a .so,
+# despite not being installed (it needs to be a shared library for
+# vala-gen-introspect)
+liblowlevel_la_LDFLAGS = \
+       -shared -rpath $(backenddir) \
+       $(LIBLOWLEVEL_LIBS) \
+       $(NULL)
+
+lowlevel.gi: $(liblowlevel_la_SOURCES) liblowlevel.la
+       $(VGI_V)$(GEN_INTROSPECT) --namespace=Folks lowlevel.h \
+               $(shell pkg-config telepathy-glib --cflags) \
+               .libs/liblowlevel.so > lowlevel.gi
+
+lowlevel.vapi: lowlevel.gi lowlevel.metadata
+       $(VAPIGEN_V)$(VAPIGEN) $(VALAFLAGS) --library lowlevel \
+               --metadata=lowlevel.metadata \
+               lowlevel.gi
+
+internal_vapi_files = \
+       lowlevel.vapi \
+       $(NULL)
+
+libfolks_backend_telepathy_la_VALASOURCES = \
+       tp-backend.vala \
+       tp-backend-factory.vala \
+       tp-persona.vala \
+       tp-persona-store.vala \
+       $(NULL)
+
+libfolks_backend_telepathy_la_SOURCES = \
+       folks-backend-telepathy.vala.stamp \
+       $(libfolks_backend_telepathy_la_VALASOURCES:.vala=.c) \
+       $(liblowlevel_la_SOURCES) \
+       $(NULL)
+
+libfolks_backend_telepathy_la_LIBADD = \
+       $(LIBFOLKS_BACKEND_TELEPATHY_LIBS) \
+       $(LIBFOLKS_LIBS) \
+       $(NULL)
+
+libfolks_backend_telepathy_la_LDFLAGS = -shared -fPIC -module -avoid-version
+
+backend_includedir = $(includedir)/folks
+backend_include_HEADERS = \
+       folks-backend-telepathy.h \
+       $(NULL)
+
+folks_backend_telepathy_stamp_targets = \
+       folks-backend-telepathy.h \
+       $(libfolks_backend_telepathy_la_VALASOURCES:.vala=.c) \
+       $(libfolks_backend_telepathy_la_VALASOURCES:.vala=.h) \
+       $(NULL)
+
+$(folks_backend_telepathy_stamp_targets): folks-backend-telepathy.vala.stamp
+
+vapi_deps = \
+       $(libfolks_backend_telepathy_la_VALASOURCES) \
+       $(internal_vapi_files) \
+       $(NULL)
+
+folks-backend-telepathy.vapi folks-backend-telepathy.vala.stamp: $(vapi_deps)
+       $(VALA_V)$(VALAC) $(VALAFLAGS) -H folks-backend-telepathy.h -C \
+               --library folks-backend-telepathy \
+               --pkg lowlevel \
+               $(libfolks_backend_telepathy_la_VALASOURCES)
+       touch $@
+
+pkgconfig_in = folks-backend-telepathy.pc.in
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = $(pkgconfig_in:.in=)
+
+BUILT_SOURCES = \
+       folks-backend-telepathy.h \
+       folks-backend-telepathy.vala.stamp \
+       folks-backend-telepathy.vapi \
+       lowlevel.gi \
+       lowlevel.vapi \
+       $(libfolks_backend_telepathy_la_VALASOURCES:.vala=.c) \
+       $(pkgconfig_in:.in=) \
+       folks-backend-telepathy-uninstalled.pc \
+       $(NULL)
+
+CLEANFILES = $(BUILT_SOURCES)
+
+EXTRA_DIST = \
+       $(pkgconfig_in) \
+       folks-backend-telepathy.vala.stamp \
+       folks-backend-telepathy.vapi \
+       lowlevel.vapi \
+       $(NULL)
+
+DISTCLEANFILES = \
+       $(NULL)
+
+MAINTAINERCLEANFILES = \
+       $(libfolks_backend_telepathy_la_VALASOURCES:.vala=.c) \
+       $(NULL)
+
+# set up the verbosity rules to avoid some build noise
+# XXX: once automake >= 1.11 is common, remove these, push VALASOURCES files
+# into SOURCES and add AM_PROG_VALAC to configure.ac
+VALA_V = $(VALA_V_$(V))
+VALA_V_ = $(VALA_V_$(AM_DEFAULT_VERBOSITY))
+VALA_V_0 = @echo "  VALAC " $^;
+
+VAPIGEN_V = $(VAPIGEN_V_$(V))
+VAPIGEN_V_ = $(VAPIGEN_V_$(AM_DEFAULT_VERBOSITY))
+VAPIGEN_V_0 = @echo "  VAPIG " $^;
+
+VGI_V = $(VGI_V_$(V))
+VGI_V_ = $(VGI_V_$(AM_DEFAULT_VERBOSITY))
+VGI_V_0 = @echo "  VGI   " $^;
diff --git a/backends/telepathy/folks-backend-telepathy-uninstalled.pc.in b/backends/telepathy/folks-backend-telepathy-uninstalled.pc.in
new file mode 100644 (file)
index 0000000..5c965f7
--- /dev/null
@@ -0,0 +1,12 @@
+prefix=
+exec_prefix=
+abs_top_srcdir=@abs_top_srcdir@
+abs_top_builddir=@abs_top_builddir@
+vapidir=@abs_top_srcdir@/folks
+
+Name: Folks Telepathy backend (uninstalled copy)
+Description: Telepathy backend for the Folks meta-contacts library
+Version: @VERSION@
+Requires: folks glib-2.0 gobject-2.0 gee-1.0 telepathy-vala >= 0.11.6.1
+Libs: ${abs_top_builddir}/folks/libfolks-backend-telepathy.la
+Cflags: -I${abs_top_srcdir} -I${abs_top_srcdir}/backends/telepathy -I${abs_top_builddir}
diff --git a/backends/telepathy/folks-backend-telepathy.pc.in b/backends/telepathy/folks-backend-telepathy.pc.in
new file mode 100644 (file)
index 0000000..0412ce9
--- /dev/null
@@ -0,0 +1,15 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+bindir=@bindir@
+includedir=@includedir@
+datarootdir=@datarootdir@
+datadir=@datadir@
+vapidir=@datadir@/vala/vapi
+
+Name: Folks Telepathy backend
+Description: Telepathy backend for the Folks meta-contacts library
+Version: @VERSION@
+Requires: folks glib-2.0 gobject-2.0 gee-1.0 telepathy-vala >= 0.11.6.1
+Libs: -L${libdir}/folks/backends/telepathy -lfolks-backend-telepathy
+Cflags: -I${includedir} -I${includedir}/folks
diff --git a/backends/telepathy/tp-backend-factory.vala b/backends/telepathy/tp-backend-factory.vala
new file mode 100644 (file)
index 0000000..d5766a5
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2009 Zeeshan Ali (Khattak) <zeeshanak@gnome.org>.
+ * Copyright (C) 2009 Nokia Corporation.
+ * 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: Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
+ *          Travis Reitter <travis.reitter@collabora.co.uk>
+ *
+ * This file was originally part of Rygel.
+ */
+
+using Folks;
+
+private TpBackendFactory backend_factory;
+
+public void module_init (BackendStore backend_store)
+{
+  backend_factory = new TpBackendFactory (backend_store);
+}
+
+public class TpBackendFactory : Object
+{
+  BackendStore backend_store;
+
+  public TpBackendFactory (BackendStore backend_store)
+    {
+      this.backend_store = backend_store;
+
+      try
+        {
+          this.backend_store.add_backend (new TpBackend ());
+        }
+      catch (GLib.Error e)
+        {
+          warning ("Failed to add Telepathy backend to libfolks: %s",
+              e.message);
+        }
+    }
+}
diff --git a/backends/telepathy/tp-backend.vala b/backends/telepathy/tp-backend.vala
new file mode 100644 (file)
index 0000000..99371c4
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * 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:
+ *       Travis Reitter <travis.reitter@collabora.co.uk>
+ */
+
+using GLib;
+using Gee;
+using Tp;
+using Folks;
+
+public class TpBackend : Folks.Backend
+{
+  private AccountManager account_manager;
+
+  public override string name { get; private set; }
+  public override HashTable<string, PersonaStore> persona_stores
+    {
+      get; private set;
+    }
+
+  public TpBackend () throws GLib.Error
+    {
+      Object (name: "telepathy");
+
+      this.persona_stores = new HashTable<string, PersonaStore> (str_hash,
+          str_equal);
+
+      this.setup_account_manager ();
+    }
+
+  private async void setup_account_manager () throws GLib.Error
+    {
+      this.account_manager = AccountManager.dup ();
+      yield this.account_manager.prepare_async (null);
+      this.account_manager.account_enabled.connect (this.account_enabled_cb);
+
+      /* FIXME: react to accounts being deleted, invalidated, etc. */
+
+      unowned GLib.List<Account> accounts =
+          this.account_manager.get_valid_accounts ();
+      foreach (Account account in accounts)
+        {
+          this.account_enabled_cb (account);
+        }
+    }
+
+  private void account_enabled_cb (Account account)
+    {
+      PersonaStore store = this.persona_stores.lookup (
+          account.get_object_path (account));
+
+      if (store != null)
+        return;
+
+      store = new TpPersonaStore (account);
+
+      this.persona_stores.insert (store.id, store);
+      store.removed.connect (this.store_removed_cb);
+
+      this.persona_store_added (store);
+    }
+
+  private void store_removed_cb (PersonaStore store)
+    {
+      this.persona_store_removed (store);
+      this.persona_stores.remove (store.id);
+    }
+}
similarity index 98%
rename from folks/tp-persona-store.vala
rename to backends/telepathy/tp-persona-store.vala
index 586d841..341825b 100644 (file)
@@ -47,6 +47,8 @@ public class Folks.TpPersonaStore : PersonaStore
   [Property(nick = "basis account",
       blurb = "Telepathy account this store is based upon")]
   public Account account { get; construct; }
+  public override string type_id { get; private set; }
+  public override string id { get; private set; }
   public override HashTable<string, Persona> personas
     {
       get { return this._personas; }
@@ -56,6 +58,9 @@ public class Folks.TpPersonaStore : PersonaStore
     {
       Object (account: account);
 
+      this.type_id = "telepathy";
+      this.id = account.get_object_path (account);
+
       this._personas = new HashTable<string, Persona> (str_hash, str_equal);
       this.conn = null;
       this.handle_persona_map = new HashMap<uint, Persona> ();
index f2ac06a..c02912a 100644 (file)
@@ -47,6 +47,7 @@ AC_SUBST(VALAFLAGS)
 AC_SUBST(CFLAGS)
 AC_SUBST(CPPFLAGS)
 AC_SUBST(LDFLAGS)
+GTK_DOC_CHECK([1.10])
 
 GLIB_REQUIRED=2.12.0
 TP_GLIB_REQUIRED=0.11.4.1
@@ -62,6 +63,20 @@ PKG_CHECK_MODULES(LIBFOLKS,
 AC_SUBST(LIBFOLKS_CFLAGS)
 AC_SUBST(LIBFOLKS_LIBS)
 
+# -----------------------------------------------------------
+# Telepathy backend
+# -----------------------------------------------------------
+PKG_CHECK_MODULES(LIBFOLKS_BACKEND_TELEPATHY,
+                  glib-2.0 >= $GLIB_REQUIRED
+                  gobject-2.0 >= $GLIB_REQUIRED
+                  dbus-glib-1
+                  gee-1.0
+                  telepathy-vala >= $TP_VALA_REQUIRED
+                  folks
+                  )
+AC_SUBST(LIBFOLKS_BACKEND_TELEPATHY_CFLAGS)
+AC_SUBST(LIBFOLKS_BACKEND_TELEPATHY_LIBS)
+
 PKG_CHECK_MODULES(LIBLOWLEVEL,
                   glib-2.0 >= $GLIB_REQUIRED
                   gobject-2.0 >= $GLIB_REQUIRED
@@ -70,8 +85,6 @@ PKG_CHECK_MODULES(LIBLOWLEVEL,
 AC_SUBST(LIBLOWLEVEL_CFLAGS)
 AC_SUBST(LIBLOWLEVEL_LIBS)
 
-GTK_DOC_CHECK([1.10])
-
 # -----------------------------------------------------------
 # Error flags
 # -----------------------------------------------------------
@@ -120,6 +133,10 @@ AC_SUBST(ERROR_CFLAGS)
 # -----------------------------------------------------------
 
 AC_CONFIG_FILES([Makefile
+       backends/Makefile
+       backends/telepathy/Makefile
+       backends/telepathy/folks-backend-telepathy.pc
+       backends/telepathy/folks-backend-telepathy-uninstalled.pc
        folks/Makefile
        folks/folks.pc
        folks/folks-uninstalled.pc
index 7449ae6..25fb23a 100644 (file)
@@ -1,59 +1,32 @@
 GEN_INTROSPECT = $(shell pkg-config vala-1.0 --variable="gen_introspect")
 VAPIGEN = $(shell pkg-config vala-1.0 --variable="vapigen")
 
+sharedir = $(datadir)/folks
+backenddir = $(libdir)/folks
+
 AM_CPPFLAGS = \
        $(LIBFOLKS_CFLAGS) \
        -include $(CONFIG_HEADER) \
        -DPACKAGE_DATADIR=\"$(pkgdatadir)\" \
+       -DDATA_DIR=\"$(shareddir)\" \
+       -DBACKEND_DIR=\"$(backenddir)\" \
        $(NULL)
 
 # this seems to work, even if vim's syntax highlighting suggests otherwise
 VALAFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) pkg-config --variable=valaflags telepathy-vala)
 VALAFLAGS += --vapidir=.
-VALAFLAGS += --pkg gobject-2.0 --pkg gio-2.0 --pkg gee-1.0 --pkg dbus-glib-1 --pkg telepathy-glib
+VALAFLAGS += --pkg build-conf --pkg gobject-2.0 --pkg gio-2.0 --pkg gee-1.0 \
+               --pkg gmodule-2.0 --pkg dbus-glib-1 --pkg telepathy-glib
 
 libfolksdir = $(includedir)/folks
 lib_LTLIBRARIES = \
-       liblowlevel.la \
        libfolks.la \
        $(NULL)
 
-# FIXME: cut the redundancy here with lowlevel_sources, etc.
-liblowlevel_la_SOURCES = \
-       lowlevel.c \
-       lowlevel.h \
-       $(NULL)
-
-liblowlevel_la_CPPFLAGS = \
-       $(LIBLOWLEVEL_CFLAGS) \
-       $(NULL)
-
-liblowlevel_la_LDFLAGS = \
-       $(LIBLOWLEVEL_LIBS) \
-       $(NULL)
-
-lowlevel_sources = \
-       lowlevel.c \
-       lowlevel.h \
-       $(NULL)
-
-# FIXME: wrap lines
-# FIXME: use a better path to the .so file
-lowlevel.gi: $(lowlevel_sources) liblowlevel.la
-       $(VGI_V)$(GEN_INTROSPECT) --namespace=Folks lowlevel.h \
-               $(shell pkg-config telepathy-glib --cflags) .libs/liblowlevel.so > lowlevel.gi
-
-lowlevel.vapi: lowlevel.gi lowlevel.metadata
-       $(VAPIGEN_V)$(VAPIGEN) $(VALAFLAGS) --library lowlevel \
-               --metadata=lowlevel.metadata \
-               lowlevel.gi
-
-internal_vapi_files = \
-       lowlevel.vapi \
-       $(NULL)
-
 libfolks_la_VALASOURCES = \
        alias.vala \
+       backend.vala \
+       backend-store.vala \
        capabilities.vala \
        groups.vala \
        individual.vala \
@@ -61,14 +34,11 @@ libfolks_la_VALASOURCES = \
        persona.vala \
        persona-store.vala \
        presence.vala \
-       tp-persona.vala \
-       tp-persona-store.vala \
        $(NULL)
 
 libfolks_la_SOURCES = \
        folks.vala.stamp \
        $(libfolks_la_VALASOURCES:.vala=.c) \
-       $(lowlevel_sources) \
        $(NULL)
 
 libfolks_la_LIBADD = \
@@ -83,8 +53,9 @@ folks_HEADERS = \
 
 folks.h $(libfolks_la_VALASOURCES:.vala=.c) $(libfolks_la_VALASOURCES:.vala=.h): folks.vala.stamp
 
-folks.vapi folks.vala.stamp: $(libfolks_la_VALASOURCES) $(internal_vapi_files)
-       $(VALA_V)$(VALAC) $(VALAFLAGS) -C --pkg lowlevel -H folks.h --library folks $(libfolks_la_VALASOURCES)
+folks.vapi folks.vala.stamp: $(libfolks_la_VALASOURCES)
+       $(VALA_V)$(VALAC) $(VALAFLAGS) -C -H folks.h --library folks \
+               $(libfolks_la_VALASOURCES)
        touch $@
 
 pkgconfig_in = folks.pc.in
@@ -95,19 +66,18 @@ BUILT_SOURCES = \
        folks.h \
        folks.vala.stamp \
        folks.vapi \
-       lowlevel.gi \
-       lowlevel.vapi \
        $(libfolks_la_VALASOURCES:.vala=.c) \
        $(pkgconfig_in:.in=) \
+       folks-uninstalled.pc \
        $(NULL)
 
 CLEANFILES = $(BUILT_SOURCES)
 
 EXTRA_DIST = \
        $(pkgconfig_in) \
+       build-conf.vapi \
        folks.vala.stamp \
        folks.vapi \
-       lowlevel.vapi \
        $(NULL)
 
 DISTCLEANFILES = \
diff --git a/folks/backend-store.vala b/folks/backend-store.vala
new file mode 100644 (file)
index 0000000..500edb9
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation.
+ * Copyright (C) 2008 Zeeshan Ali (Khattak) <zeeshanak@gnome.org>.
+ * 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: Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
+ *          Travis Reitter <travis.reitter@collabora.co.uk>
+ *
+ * This file was originally part of Rygel.
+ */
+
+using BuildConf;
+using Gee;
+using GLib;
+
+/**
+ * Responsible for backend loading. Probes for shared library files in a
+ * specific directory, looking for (and calling) a specific function (by name,
+ * signature).
+ */
+public class Folks.BackendStore : Object {
+  private delegate void ModuleInitFunc (BackendStore store);
+
+  private HashMap<string,Backend> backend_hash;
+
+  public signal void backend_available (Backend backend);
+
+  public BackendStore ()
+    {
+      this.backend_hash = new HashMap<string,Backend> (str_hash, str_equal);
+    }
+
+  public void load_backends () {
+      assert (Module.supported());
+
+      var path = Environment.get_variable ("FOLKS_BACKEND_DIR");
+      if (path == null)
+        {
+          path = BuildConf.BACKEND_DIR;
+
+          debug ("Using built-in backend dir '%s' (override with environment "
+              + "variable FOLKS_BACKEND_DIR)", path);
+        }
+      else
+        {
+          debug ("Using environment variable FOLKS_BACKEND_DIR = '%s' to look "
+              + "for backends", path);
+        }
+
+      File dir = File.new_for_path (path);
+      assert (dir != null && is_dir (dir));
+
+      this.load_modules_from_dir.begin (dir);
+  }
+
+  public void add_backend (Backend backend)
+    {
+      message ("New backend '%s' available", backend.name);
+      this.backend_hash.set (backend.name, backend);
+      this.backend_available (backend);
+    }
+
+  public Backend? get_backend_by_name (string name)
+    {
+      return this.backend_hash.get (name);
+    }
+
+  public Collection<Backend> list_backends ()
+    {
+      return this.backend_hash.values;
+    }
+
+  private async void load_modules_from_dir (File dir)
+    {
+      debug ("Searching for modules in folder '%s' ..", dir.get_path ());
+
+      string attributes = FILE_ATTRIBUTE_STANDARD_NAME + "," +
+                          FILE_ATTRIBUTE_STANDARD_TYPE + "," +
+                          FILE_ATTRIBUTE_STANDARD_IS_SYMLINK + "," +
+                          FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE;
+
+      GLib.List<FileInfo> infos;
+      FileEnumerator enumerator;
+
+      try
+        {
+          enumerator = yield dir.enumerate_children_async (attributes,
+              FileQueryInfoFlags.NONE, Priority.DEFAULT, null);
+
+          infos = yield enumerator.next_files_async (int.MAX,
+              Priority.DEFAULT, null);
+        }
+      catch (Error error)
+        {
+          critical ("Error listing contents of folder '%s': %s",
+              dir.get_path (), error.message);
+
+          return;
+        }
+
+      foreach (var info in infos)
+        {
+          string file_name = info.get_name ();
+          string file_path = Path.build_filename (dir.get_path (), file_name);
+
+          File file = File.new_for_path (file_path);
+          FileType file_type = info.get_file_type ();
+          string content_type = info.get_content_type ();
+          /* don't load the library multiple times for its various symlink
+           * aliases */
+          var is_symlink = info.get_is_symlink ();
+
+          weak string mime = g_content_type_get_mime_type (content_type);
+
+          if (file_type == FileType.DIRECTORY)
+              this.load_modules_from_dir.begin (file);
+          else if (mime == "application/x-sharedlib" && !is_symlink)
+              this.load_module_from_file (file_path);
+        }
+
+      debug ("Finished searching for modules in folder '%s'",
+          dir.get_path ());
+    }
+
+  private void load_module_from_file (string file_path)
+    {
+      Module module = Module.open (file_path, ModuleFlags.BIND_LOCAL);
+      if (module == null)
+        {
+          warning ("Failed to load module from path '%s' : %s",
+                    file_path, Module.error ());
+
+          return;
+        }
+
+      void* function;
+
+      if (!module.symbol("module_init", out function))
+        {
+          warning ("Failed to find entry point function '%s' in '%s': %s",
+                    "module_init",
+                    file_path,
+                    Module.error ());
+
+          return;
+        }
+
+      ModuleInitFunc module_init = (ModuleInitFunc) function;
+      assert (module_init != null);
+
+      /* We don't want our modules to ever unload */
+      module.make_resident ();
+
+      module_init (this);
+
+      debug ("Loaded module source: '%s'", module.name ());
+    }
+
+  private static bool is_dir (File file)
+    {
+      FileInfo file_info;
+
+      if (!file.query_exists (null))
+        {
+          critical ("File or directory '%s' does not exist", file.get_path ());
+          return false;
+        }
+
+      try
+        {
+          file_info = file.query_info (FILE_ATTRIBUTE_STANDARD_TYPE,
+              FileQueryInfoFlags.NONE, null);
+        }
+      catch (Error error)
+        {
+          critical ("Failed to get content type for '%s'",
+              file.get_path ());
+
+          return false;
+        }
+
+      return file_info.get_file_type () == FileType.DIRECTORY;
+    }
+}
diff --git a/folks/backend.vala b/folks/backend.vala
new file mode 100644 (file)
index 0000000..fd3785a
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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:
+ *       Travis Reitter <travis.reitter@collabora.co.uk>
+ */
+
+using BuildConf;
+using Folks;
+
+public abstract class Folks.Backend : Object
+{
+  public abstract string name { get; protected set; }
+  public abstract HashTable<string, PersonaStore> persona_stores
+    {
+      get; protected set;
+    }
+
+  public abstract signal void persona_store_added (PersonaStore store);
+  public abstract signal void persona_store_removed (PersonaStore store);
+}
diff --git a/folks/build-conf.vapi b/folks/build-conf.vapi
new file mode 100644 (file)
index 0000000..40a5d50
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2008 Zeeshan Ali (Khattak) <zeeshanak@gnome.org>.
+ * 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: Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
+ *          Travis Reitter <travis.reitter@collabora.co.uk>
+ *
+ * This file was originally part of Rygel.
+ */
+
+public class BuildConf
+{
+  [CCode (cname = "DATA_DIR")]
+  public static const string DATA_DIR;
+
+  [CCode (cname = "BACKEND_DIR")]
+  public static const string BACKEND_DIR;
+
+  [CCode (cname = "PACKAGE_NAME")]
+  public static const string PACKAGE_NAME;
+
+  [CCode (cname = "PACKAGE_VERSION")]
+  public static const string PACKAGE_VERSION;
+
+  [CCode (cname = "PACKAGE_STRING")]
+  public static const string PACKAGE_STRING;
+}
index bfffd7a..9f36442 100644 (file)
@@ -7,6 +7,6 @@ vapidir=@abs_top_srcdir@/folks
 Name: Folks (uninstalled copy)
 Description: The Folks meta-contacts library
 Version: @VERSION@
-Requires: glib-2.0 gobject-2.0 telepathy-vala >= 0.11.6.1
-Libs: ${abs_top_builddir}/libfolks/libfolks.la
-Cflags: -I${abs_top_srcdir} -I${abs_top_builddir}
+Requires: glib-2.0 gobject-2.0 gee-1.0 telepathy-vala >= 0.11.6.1
+Libs: ${abs_top_builddir}/folks/libfolks.la
+Cflags: -I${abs_top_srcdir} -I${abs_top_srcdir}/folks -I${abs_top_builddir}
index 592a6de..0d7b8e5 100644 (file)
@@ -10,6 +10,6 @@ vapidir=@datadir@/vala/vapi
 Name: Folks
 Description: The Folks meta-contacts library
 Version: @VERSION@
-Requires: glib-2.0 gobject-2.0 telepathy-vala >= 0.11.6.1
+Requires: glib-2.0 gobject-2.0 gee-1.0 telepathy-vala >= 0.11.6.1
 Libs: -L${libdir} -lfolks
 Cflags: -I${includedir}
index 5e5cec8..3e76eb8 100644 (file)
  *       Travis Reitter <travis.reitter@collabora.co.uk>
  */
 
-using GLib;
+using Folks;
 using Gee;
-using Tp;
-using Folks.PersonaStore;
-using Folks.TpPersonaStore;
+using GLib;
 
 public class Folks.IndividualAggregator : Object
 {
-  private AccountManager account_manager;
+  private BackendStore backend_store;
   private HashMap<string, PersonaStore> stores;
+  private HashSet<Backend> backends;
 
   public HashTable<string, Individual> members { get; private set; }
 
@@ -42,59 +41,43 @@ public class Folks.IndividualAggregator : Object
       this.stores = new HashMap<string, PersonaStore> ();
       this.members = new HashTable<string, Individual> (str_hash, str_equal);
 
-      this.setup_account_manager ();
-    }
-
-  private async void setup_account_manager () throws GLib.Error
-    {
-      this.account_manager = AccountManager.dup ();
-      yield this.account_manager.prepare_async (null);
-      this.account_manager.account_enabled.connect (this.account_enabled_cb);
-
-      /* FIXME: react to accounts being deleted, invalidated, etc. */
+      this.backends = new HashSet<Backend> ();
 
-      unowned GLib.List<Account> accounts =
-          this.account_manager.get_valid_accounts ();
-      foreach (Account account in accounts)
-        {
-          this.account_enabled_cb (account);
-        }
+      this.backend_store = new BackendStore ();
+      this.backend_store.backend_available.connect (this.backend_available_cb);
+      this.backend_store.load_backends ();
     }
 
-  private void account_enabled_cb (Account account)
+  private void backend_available_cb (BackendStore backend_store,
+      Backend backend)
     {
-      var store = this.stores.get (account.get_object_path (account));
-
-      if (store != null)
-        return;
-
-      /* FIXME: cut this */
-      debug ("   adding account name: '%s'", account.get_display_name ());
-
-      this.store_add_from_account (account);
+      backend.persona_store_added.connect (this.backend_persona_store_added_cb);
+      backend.persona_store_removed.connect (
+          this.backend_persona_store_removed_cb);
     }
 
-  private void store_add_from_account (Account account)
+  private void backend_persona_store_added_cb (Backend backend,
+      PersonaStore store)
     {
-      var store = new TpPersonaStore (account);
-
-      this.stores.set (account.get_object_path (account), store);
+      this.stores.set (this.store_get_full_id (store), store);
       store.personas_added.connect (this.personas_added_cb);
-      store.removed.connect (this.store_removed_cb);
     }
 
-  private void store_removed_cb (PersonaStore store)
+  private void backend_persona_store_removed_cb (Backend backend,
+      PersonaStore store)
     {
-      var account = ((TpPersonaStore) store).account;
-
       store.personas_added.disconnect (this.personas_added_cb);
-      store.removed.disconnect (this.store_removed_cb);
 
       /* no need to remove this stores' personas from all the individuals, since
        * they'll do that themselves (and emit their own 'removed' signal if
        * necessary) */
 
-      this.stores.unset (account.get_object_path (account));
+      this.stores.unset (this.store_get_full_id (store));
+    }
+
+  private string store_get_full_id (PersonaStore store)
+    {
+      return store.type_id + ":" + store.id;
     }
 
   private void personas_added_cb (PersonaStore store,
index d0a8ac7..9242cf4 100644 (file)
@@ -32,6 +32,8 @@ public abstract class Folks.PersonaStore : Object
   /* the backing store itself was deleted and its personas are now invalid */
   public abstract signal void removed ();
 
+  public abstract string type_id { get; protected set; }
+  public abstract string id { get; protected set; }
   public abstract HashTable<string, Persona> personas { get; }
 
   public abstract async void change_group_membership (Persona persona,