I've built a package including the patch pointed by Josselin. Could
someone test it and report back as I don't have an http-based
syncevolution setup.

Packages are available at
http://molly.corsac.net/~corsac/debian/wheezy/syncevolution/ and debdiff
is attached.

Regards,
-- 
Yves-Alexis
Differences in syncevolution between 1.2.99.1-1 and 1.2.99.1-1.1
diff -Nru syncevolution-1.2.99.1/debian/changelog syncevolution-1.2.99.1/debian/changelog
--- syncevolution-1.2.99.1/debian/changelog	2012-06-29 12:42:39.000000000 +0200
+++ syncevolution-1.2.99.1/debian/changelog	2013-03-07 22:25:10.000000000 +0100
@@ -1,3 +1,12 @@
+syncevolution (1.2.99.1-1.1) UNRELEASED; urgency=low
+
+  * Non-maintainer upload.
+  * debian/patches:
+    - 0001-D-Bus-server-GIO-D-Bus-fix-auto-activation-Debian-bu added, cherry
+      picked from upstream git. Fix DBus auto-activation.       closes: #699852
+
+ -- Yves-Alexis Perez <cor...@debian.org>  Thu, 07 Mar 2013 22:24:55 +0100
+
 syncevolution (1.2.99.1-1) unstable; urgency=low
 
   * New upstream release candidate (Closes: #675288)
diff -Nru syncevolution-1.2.99.1/debian/patches/0001-D-Bus-server-GIO-D-Bus-fix-auto-activation-Debian-bu.patch syncevolution-1.2.99.1/debian/patches/0001-D-Bus-server-GIO-D-Bus-fix-auto-activation-Debian-bu.patch
--- syncevolution-1.2.99.1/debian/patches/0001-D-Bus-server-GIO-D-Bus-fix-auto-activation-Debian-bu.patch	1970-01-01 01:00:00.000000000 +0100
+++ syncevolution-1.2.99.1/debian/patches/0001-D-Bus-server-GIO-D-Bus-fix-auto-activation-Debian-bu.patch	2013-03-07 22:25:22.000000000 +0100
@@ -0,0 +1,316 @@
+From f7718ebb48bbd85b2b7eb29b45892ec20cbba0a2 Mon Sep 17 00:00:00 2001
+From: Patrick Ohly <patrick.o...@intel.com>
+Date: Mon, 13 Aug 2012 21:51:21 +0200
+Subject: [PATCH] D-Bus server + GIO D-Bus: fix auto-activation (Debian bug
+ #599247)
+
+When syncevo-dbus-server was started on demand by the D-Bus daemon,
+then it registered itself with the daemon before it was ready to
+serve requests. Only happened in combination with GIO D-Bus and
+thus was not a problem before 1.2.99.x.
+
+One user-visible effect was that the GTK UI did select the default
+service when it was started for the first time, because it could not
+retrieve that information from syncevo-dbus-server.
+
+The fix consists of delaying the name acquisition. That gives the
+caller a chance to register D-Bus objects first, before completing the
+connection setup. The semantic change is that
+dbus_bus_connection_undelay() must be called on new connections which
+have a name (a NOP with libdbus).
+
+This patch tries to minimize code changes. The downside of not
+changing the GDBusCXX API more radically is that the bus name must be
+attached to DBusConnectionPtr, where it will be copied into each
+reference to the connection. Hopefully std::string is smart enough to
+share the (small) data in this case. Should be solved cleaner once
+libdbus support can be deprecated.
+
+A test for auto-activation and double start of syncevo-dbus-server
+is also added.
+---
+ src/dbus/server/main.cpp         |    1 +
+ src/gdbusxx/gdbus-cxx-bridge.cpp |   89 +++++++++++++++++++++++++++++---------
+ src/gdbusxx/gdbus-cxx-bridge.h   |   13 +++++-
+ test/test-dbus.py                |   71 ++++++++++++++++++++++++++++++
+ 4 files changed, 152 insertions(+), 22 deletions(-)
+
+diff --git a/src/dbus/server/main.cpp b/src/dbus/server/main.cpp
+index 965821b..a63c735 100644
+--- a/src/dbus/server/main.cpp
++++ b/src/dbus/server/main.cpp
+@@ -150,6 +150,7 @@ int main(int argc, char **argv, char **envp)
+             unsetenv("G_DBUS_DEBUG");
+         }
+ 
++        dbus_bus_connection_undelay(conn);
+         server->run();
+         SE_LOG_DEBUG(NULL, NULL, "cleaning up");
+         server.reset();
+diff --git a/src/gdbusxx/gdbus-cxx-bridge.cpp b/src/gdbusxx/gdbus-cxx-bridge.cpp
+index 62c0fc9..6d70d2f 100644
+--- a/src/gdbusxx/gdbus-cxx-bridge.cpp
++++ b/src/gdbusxx/gdbus-cxx-bridge.cpp
+@@ -33,12 +33,63 @@ namespace GDBusCXX {
+ MethodHandler::MethodMap MethodHandler::m_methodMap;
+ boost::function<void (void)> MethodHandler::m_callback;
+ 
+-static void GDBusNameLost(GDBusConnection *connection,
+-                          const gchar *name,
+-                          gpointer user_data)
++// It should be okay to use global variables here because they are
++// only used inside the main thread while it waits in undelay() for a
++// positive or negative result to g_bus_own_name_on_connection().
++// Once acquired, the name can only get lost again when the
++// D-Bus daemon dies (no name owership alloed), in which case the
++// process dies anyway.
++static bool nameError;
++static bool nameAcquired;
++static void BusNameAcquired(GDBusConnection *connection,
++                            const gchar *name,
++                            gpointer userData) throw ()
+ {
+-    g_critical("lost D-Bus connection or failed to obtain %s D-Bus name, quitting", name);
+-    exit(1);
++    try {
++        g_debug("got D-Bus name %s", name);
++        nameAcquired = true;
++    } catch (...) {
++        nameError = true;
++    }
++}
++
++static void BusNameLost(GDBusConnection *connection,
++                        const gchar *name,
++                        gpointer userData) throw ()
++{
++    try {
++        g_debug("lost %s %s",
++                connection ? "D-Bus connection for name" :
++                "D-Bus name",
++                name);
++    } catch (...) {
++    }
++    nameError = true;
++}
++
++void DBusConnectionPtr::undelay() const
++{
++    if (!m_name.empty()) {
++        g_debug("starting to acquire D-Bus name %s", m_name.c_str());
++        nameAcquired = false;
++        nameError = false;
++        char *copy = g_strdup(m_name.c_str());
++        g_bus_own_name_on_connection(get(),
++                                     copy,
++                                     G_BUS_NAME_OWNER_FLAGS_NONE,
++                                     BusNameAcquired,
++                                     BusNameLost,
++                                     copy,
++                                     g_free);
++        while (!nameAcquired && !nameError) {
++            g_main_context_iteration(NULL, true);
++        }
++        g_debug("done with acquisition of %s", m_name.c_str());
++        if (nameError) {
++            throw std::runtime_error("could not obtain D-Bus name - already running?");
++        }
++    }
++    g_dbus_connection_start_message_processing(get());
+ }
+ 
+ DBusConnectionPtr dbus_get_bus_connection(const char *busType,
+@@ -48,10 +99,13 @@ DBusConnectionPtr dbus_get_bus_connection(const char *busType,
+ {
+     DBusConnectionPtr conn;
+     GError* error = NULL;
++    GBusType type =
++        boost::iequals(busType, "SESSION") ?
++        G_BUS_TYPE_SESSION :
++        G_BUS_TYPE_SYSTEM;
+ 
+-    if(unshared) {
+-        char *address = g_dbus_address_get_for_bus_sync(boost::iequals(busType, "SESSION") ?
+-                                                        G_BUS_TYPE_SESSION : G_BUS_TYPE_SYSTEM,
++    if (unshared) {
++        char *address = g_dbus_address_get_for_bus_sync(type,
+                                                         NULL, &error);
+         if(address == NULL) {
+             if (err) {
+@@ -76,9 +130,7 @@ DBusConnectionPtr dbus_get_bus_connection(const char *busType,
+         }
+     } else {
+         // This returns a singleton, shared connection object.
+-        conn = DBusConnectionPtr(g_bus_get_sync(boost::iequals(busType, "SESSION") ?
+-                                                G_BUS_TYPE_SESSION :
+-                                                G_BUS_TYPE_SYSTEM,
++        conn = DBusConnectionPtr(g_bus_get_sync(type,
+                                                 NULL, &error),
+                                  false);
+         if(conn == NULL) {
+@@ -89,11 +141,11 @@ DBusConnectionPtr dbus_get_bus_connection(const char *busType,
+         }
+     }
+ 
+-    if(name) {
+-        // Copy name, to ensure that it remains available.
+-        char *copy = g_strdup(name);
+-        g_bus_own_name_on_connection(conn.get(), copy, G_BUS_NAME_OWNER_FLAGS_NONE,
+-                                     NULL, GDBusNameLost, copy, g_free);
++    if (name) {
++        // Request name later in undelay(), after the caller
++        // had a chance to add objects.
++        conn.addName(name);
++        // Acting as client, need to stop when D-Bus daemon dies.
+         g_dbus_connection_set_exit_on_close(conn.get(), TRUE);
+     }
+ 
+@@ -124,11 +176,6 @@ DBusConnectionPtr dbus_get_bus_connection(const std::string &address,
+     return conn;
+ }
+ 
+-void dbus_bus_connection_undelay(const DBusConnectionPtr &conn)
+-{
+-    g_dbus_connection_start_message_processing(conn.get());
+-}
+-
+ static void ConnectionLost(GDBusConnection *connection,
+                            gboolean remotePeerVanished,
+                            GError *error,
+diff --git a/src/gdbusxx/gdbus-cxx-bridge.h b/src/gdbusxx/gdbus-cxx-bridge.h
+index e45b1cd..2a1dcfe 100644
+--- a/src/gdbusxx/gdbus-cxx-bridge.h
++++ b/src/gdbusxx/gdbus-cxx-bridge.h
+@@ -124,6 +124,14 @@ inline void throwFailure(const std::string &object,
+ 
+ class DBusConnectionPtr : public boost::intrusive_ptr<GDBusConnection>
+ {
++    /**
++     * Bus name of client, as passed to dbus_get_bus_connection().
++     * The name will be requested in dbus_bus_connection_undelay() =
++     * undelay(), to give the caller a chance to register objects on
++     * the new connection.
++     */
++    std::string m_name;
++
+  public:
+     DBusConnectionPtr() {}
+     // connections are typically created once, so increment the ref counter by default
+@@ -141,6 +149,9 @@ class DBusConnectionPtr : public boost::intrusive_ptr<GDBusConnection>
+     typedef boost::function<void ()> Disconnect_t;
+     void setDisconnect(const Disconnect_t &func);
+     // #define GDBUS_CXX_HAVE_DISCONNECT 1
++
++    void undelay() const;
++    void addName(const std::string &name) { m_name = name; }
+ };
+ 
+ class DBusMessagePtr : public boost::intrusive_ptr<GDBusMessage>
+@@ -224,7 +235,7 @@ DBusConnectionPtr dbus_get_bus_connection(const std::string &address,
+                                           DBusErrorCXX *err,
+                                           bool delayed = false);
+ 
+-void dbus_bus_connection_undelay(const DBusConnectionPtr &conn);
++inline void dbus_bus_connection_undelay(const DBusConnectionPtr &conn) { conn.undelay(); }
+ 
+ /**
+  * Wrapper around DBusServer. Does intentionally not expose
+diff --git a/test/test-dbus.py b/test/test-dbus.py
+index c38bf18..8578b26 100755
+--- a/test/test-dbus.py
++++ b/test/test-dbus.py
+@@ -63,6 +63,18 @@ configName = "dbus_unittest"
+ def usingValgrind():
+     return 'valgrind' in os.environ.get("TEST_DBUS_PREFIX", "")
+ 
++def which(program):
++    '''find absolute path to program (simple file name, no path) in PATH env variable'''
++    def isExe(fpath):
++        return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
++
++    for path in os.environ["PATH"].split(os.pathsep):
++        exeFile = os.path.join(path, program)
++        if isExe(exeFile):
++            return os.path.abspath(exeFile)
++
++    return None
++
+ def GrepNotifications(dbuslog):
+     '''finds all Notify calls and returns their parameters as list of line lists'''
+     return re.findall(r'^method call .* dest=.* .*interface=org.freedesktop.Notifications; member=Notify\n((?:^   .*\n)*)',
+@@ -1250,6 +1262,56 @@ class TestDBusServer(DBusUtil, unittest.TestCase):
+         else:
+             self.fail("no exception thrown")
+ 
++class TestDBusServerStart(DBusUtil, unittest.TestCase):
++    def testAutoActivation(self):
++        '''TestDBusServerStart.testAutoActivation - check that activating syncevo-dbus-server via D-Bus daemon works'''
++        # Create a D-Bus service file for the syncevo-dbus-server that we
++        # are testing (= the one in PATH).
++        shutil.rmtree(xdg_root, True)
++        dirname = os.path.join(xdg_root, "share", "dbus-1", "services")
++        os.makedirs(dirname)
++        service = open(os.path.join(dirname, "org.syncevolution.service"), "w")
++        service.write('''[D-BUS Service]
++Name=org.syncevolution
++Exec=%s
++''' % which('syncevo-dbus-server'))
++        service.close()
++
++        # Now run a private D-Bus session in which dbus-send activates
++        # that syncevo-dbus-server. Uses a dbus-session.sh from the
++        # same dir as test-dbus.py itself.
++        env = copy.deepcopy(os.environ)
++        env['XDG_DATA_DIRS'] = os.path.abspath(os.path.join(xdg_root, "share"))
++
++        # First run something which just starts the daemon.
++        dbus = subprocess.Popen((os.path.join(os.path.dirname(sys.argv[0]), 'dbus-session.sh'),
++                                 'dbus-send',
++                                 '--print-reply',
++                                 '--dest=org.syncevolution',
++                                 '/',
++                                 'org.freedesktop.DBus.Introspectable.Introspect'),
++                                env=env,
++                                stdout=subprocess.PIPE,
++                                stderr=subprocess.STDOUT)
++        (out, err) = dbus.communicate()
++        self.assertEqual(0, dbus.returncode,
++                         msg='introspection of syncevo-dbus-server failed:\n' + out)
++
++        # Now try some real command.
++        dbus = subprocess.Popen((os.path.join(os.path.dirname(sys.argv[0]), 'dbus-session.sh'),
++                                 'dbus-send',
++                                 '--print-reply',
++                                 '--dest=org.syncevolution',
++                                 '/org/syncevolution/Server',
++                                 'org.syncevolution.Server.GetVersions'),
++                                env=env,
++                                stdout=subprocess.PIPE,
++                                stderr=subprocess.STDOUT)
++        (out, err) = dbus.communicate()
++        self.assertEqual(0, dbus.returncode,
++                         msg='GetVersions of syncevo-dbus-server failed:\n' + out)
++
++
+ class TestDBusServerTerm(DBusUtil, unittest.TestCase):
+     def setUp(self):
+         self.setUpServer()
+@@ -1257,6 +1319,15 @@ class TestDBusServerTerm(DBusUtil, unittest.TestCase):
+     def run(self, result):
+         self.runTest(result, True, ["-d", "10"])
+ 
++    def testSingleton(self):
++        """TestDBusServerTerm.testSingleton - a second instance of syncevo-dbus-server must terminate right away"""
++        dbus = subprocess.Popen([ 'syncevo-dbus-server' ],
++                                stdout=subprocess.PIPE,
++                                stderr=subprocess.STDOUT)
++        (out, err) = dbus.communicate()
++        if not re.search(r'''\[ERROR.*already running\?\n''', out):
++            self.fail('second dbus server did not recognize already running server:\n%s' % out)
++
+     @timeout(100)
+     def testNoTerm(self):
+         """TestDBusServerTerm.testNoTerm - D-Bus server must stay around during calls"""
+-- 
+1.7.10.4
+
diff -Nru syncevolution-1.2.99.1/debian/patches/series syncevolution-1.2.99.1/debian/patches/series
--- syncevolution-1.2.99.1/debian/patches/series	1970-01-01 01:00:00.000000000 +0100
+++ syncevolution-1.2.99.1/debian/patches/series	2013-03-07 22:25:41.000000000 +0100
@@ -0,0 +1 @@
+0001-D-Bus-server-GIO-D-Bus-fix-auto-activation-Debian-bu.patch

Attachment: signature.asc
Description: This is a digitally signed message part

Reply via email to