]> code.delx.au - gnu-emacs/blobdiff - src/dbusbind.c
Merge from emacs-24; up to 2012-12-06T01:39:03Z!monnier@iro.umontreal.ca
[gnu-emacs] / src / dbusbind.c
index 0ea08d7bf0e817d9daff39903b7135a7f22e339b..863f7634eb5a6df20d1318ce77382259765d8aa0 100644 (file)
@@ -1,5 +1,5 @@
 /* Elisp bindings for D-Bus.
-   Copyright (C) 2007-2012 Free Software Foundation, Inc.
+   Copyright (C) 2007-2013 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -21,7 +21,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #ifdef HAVE_DBUS
 #include <stdio.h>
 #include <dbus/dbus.h>
-#include <setjmp.h>
+
 #include "lisp.h"
 #include "frame.h"
 #include "termhooks.h"
@@ -32,6 +32,14 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #define DBUS_NUM_MESSAGE_TYPES 5
 #endif
 
+
+/* Some platforms define the symbol "interface", but we want to use it
+ * as a variable name below.  */
+
+#ifdef interface
+#undef interface
+#endif
+
 \f
 /* Subroutines.  */
 static Lisp_Object Qdbus_init_bus;
@@ -64,8 +72,13 @@ static Lisp_Object QCdbus_type_struct, QCdbus_type_dict_entry;
 static Lisp_Object QCdbus_registered_serial, QCdbus_registered_method;
 static Lisp_Object QCdbus_registered_signal;
 
+/* Alist of D-Bus buses we are polling for messages.
+   The key is the symbol or string of the bus, and the value is the
+   connection address.  */
+static Lisp_Object xd_registered_buses;
+
 /* Whether we are reading a D-Bus event.  */
-static int xd_in_read_queued_messages = 0;
+static bool xd_in_read_queued_messages = 0;
 
 \f
 /* We use "xd_" and "XD_" as prefix for all internal symbols, because
@@ -111,12 +124,13 @@ static int xd_in_read_queued_messages = 0;
 /* Macros for debugging.  In order to enable them, build with
    "env MYCPPFLAGS='-DDBUS_DEBUG -Wall' make".  */
 #ifdef DBUS_DEBUG
-#define XD_DEBUG_MESSAGE(...)           \
-  do {                                  \
-    char s[1024];                       \
-    snprintf (s, sizeof s, __VA_ARGS__); \
-    printf ("%s: %s\n", __func__, s);   \
-    message ("%s: %s", __func__, s);    \
+#define XD_DEBUG_MESSAGE(...)                                          \
+  do {                                                                 \
+    char s[1024];                                                      \
+    snprintf (s, sizeof s, __VA_ARGS__);                               \
+    if (!noninteractive)                                               \
+      printf ("%s: %s\n", __func__, s);                                        \
+    message ("%s: %s", __func__, s);                                   \
   } while (0)
 #define XD_DEBUG_VALID_LISP_OBJECT_P(object)                           \
   do {                                                                 \
@@ -141,6 +155,10 @@ static int xd_in_read_queued_messages = 0;
 #endif
 
 /* Check whether TYPE is a basic DBusType.  */
+#ifdef HAVE_DBUS_TYPE_IS_VALID
+#define XD_BASIC_DBUS_TYPE(type)                                       \
+  (dbus_type_is_valid (type) && dbus_type_is_basic (type))
+#else
 #ifdef DBUS_TYPE_UNIX_FD
 #define XD_BASIC_DBUS_TYPE(type)                                       \
   ((type ==  DBUS_TYPE_BYTE)                                           \
@@ -171,6 +189,7 @@ static int xd_in_read_queued_messages = 0;
    || (type ==  DBUS_TYPE_OBJECT_PATH)                                 \
    || (type ==  DBUS_TYPE_SIGNATURE))
 #endif
+#endif
 
 /* This was a macro.  On Solaris 2.11 it was said to compile for
    hours, when optimization is enabled.  So we have transferred it into
@@ -248,24 +267,9 @@ xd_symbol_to_dbus_type (Lisp_Object object)
 #define XD_OBJECT_TO_STRING(object)                                    \
   SDATA (format2 ("%s", object, Qnil))
 
-/* Check whether X is a valid dbus serial number.  If valid, set
-   SERIAL to its value.  Otherwise, signal an error. */
-#define XD_CHECK_DBUS_SERIAL(x, serial)                                        \
-  do {                                                                 \
-    dbus_uint32_t DBUS_SERIAL_MAX = -1;                                        \
-    if (NATNUMP (x) && XINT (x) <= DBUS_SERIAL_MAX)                    \
-      serial = XINT (x);                                               \
-    else if (MOST_POSITIVE_FIXNUM < DBUS_SERIAL_MAX                    \
-            && FLOATP (x)                                              \
-            && 0 <= XFLOAT_DATA (x)                                    \
-            && XFLOAT_DATA (x) <= DBUS_SERIAL_MAX)                     \
-      serial = XFLOAT_DATA (x);                                                \
-    else                                                               \
-      XD_SIGNAL2 (build_string ("Invalid dbus serial"), x);            \
-  } while (0)
-
 #define XD_DBUS_VALIDATE_BUS_ADDRESS(bus)                              \
   do {                                                                 \
+    char const *session_bus_address = getenv ("DBUS_SESSION_BUS_ADDRESS"); \
     if (STRINGP (bus))                                                 \
       {                                                                        \
        DBusAddressEntry **entries;                                     \
@@ -277,6 +281,11 @@ xd_symbol_to_dbus_type (Lisp_Object object)
        /* Cleanup.  */                                                 \
        dbus_error_free (&derror);                                      \
        dbus_address_entries_free (entries);                            \
+       /* Canonicalize session bus address.  */                        \
+       if ((session_bus_address != NULL)                               \
+           && (!NILP (Fstring_equal                                    \
+                      (bus, build_string (session_bus_address)))))     \
+         bus = QCdbus_session_bus;                                     \
       }                                                                        \
                                                                        \
     else                                                               \
@@ -285,14 +294,13 @@ xd_symbol_to_dbus_type (Lisp_Object object)
        if (!(EQ (bus, QCdbus_system_bus) || EQ (bus, QCdbus_session_bus))) \
          XD_SIGNAL2 (build_string ("Wrong bus name"), bus);            \
        /* We do not want to have an autolaunch for the session bus.  */ \
-       if (EQ (bus, QCdbus_session_bus)                                \
-           && getenv ("DBUS_SESSION_BUS_ADDRESS") == NULL)             \
+       if (EQ (bus, QCdbus_session_bus) && session_bus_address == NULL) \
          XD_SIGNAL2 (build_string ("No connection to bus"), bus);      \
       }                                                                        \
   } while (0)
 
-#if (HAVE_DBUS_VALIDATE_BUS_NAME || HAVE_DBUS_VALIDATE_PATH \
-     || XD_DBUS_VALIDATE_OBJECT || HAVE_DBUS_VALIDATE_MEMBER)
+#if (HAVE_DBUS_VALIDATE_BUS_NAME || HAVE_DBUS_VALIDATE_PATH            \
+     || HAVE_DBUS_VALIDATE_INTERFACE || HAVE_DBUS_VALIDATE_MEMBER)
 #define XD_DBUS_VALIDATE_OBJECT(object, func)                          \
   do {                                                                 \
     if (!NILP (object))                                                        \
@@ -360,9 +368,9 @@ xd_signature_cat (char *signature, char const *x)
    signature is embedded, or DBUS_TYPE_INVALID.  It is needed for the
    check that DBUS_TYPE_DICT_ENTRY occurs only as array element.  */
 static void
-xd_signature (char *signature, unsigned int dtype, unsigned int parent_type, Lisp_Object object)
+xd_signature (char *signature, int dtype, int parent_type, Lisp_Object object)
 {
-  unsigned int subtype;
+  int subtype;
   Lisp_Object elt;
   char const *subsig;
   int subsiglen;
@@ -532,13 +540,67 @@ xd_signature (char *signature, unsigned int dtype, unsigned int parent_type, Lis
   XD_DEBUG_MESSAGE ("%s", signature);
 }
 
+/* Convert X to a signed integer with bounds LO and HI.  */
+static intmax_t
+xd_extract_signed (Lisp_Object x, intmax_t lo, intmax_t hi)
+{
+  CHECK_NUMBER_OR_FLOAT (x);
+  if (INTEGERP (x))
+    {
+      if (lo <= XINT (x) && XINT (x) <= hi)
+       return XINT (x);
+    }
+  else
+    {
+      double d = XFLOAT_DATA (x);
+      if (lo <= d && d <= hi)
+       {
+         intmax_t n = d;
+         if (n == d)
+           return n;
+       }
+    }
+  if (xd_in_read_queued_messages)
+    Fthrow (Qdbus_error, Qnil);
+  else
+    args_out_of_range_3 (x,
+                        make_fixnum_or_float (lo),
+                        make_fixnum_or_float (hi));
+}
+
+/* Convert X to an unsigned integer with bounds 0 and HI.  */
+static uintmax_t
+xd_extract_unsigned (Lisp_Object x, uintmax_t hi)
+{
+  CHECK_NUMBER_OR_FLOAT (x);
+  if (INTEGERP (x))
+    {
+      if (0 <= XINT (x) && XINT (x) <= hi)
+       return XINT (x);
+    }
+  else
+    {
+      double d = XFLOAT_DATA (x);
+      if (0 <= d && d <= hi)
+       {
+         uintmax_t n = d;
+         if (n == d)
+           return n;
+       }
+    }
+  if (xd_in_read_queued_messages)
+    Fthrow (Qdbus_error, Qnil);
+  else
+    args_out_of_range_3 (x, make_number (0), make_fixnum_or_float (hi));
+}
+
 /* Append C value, extracted from Lisp OBJECT, to iteration ITER.
    DTYPE must be a valid DBusType.  It is used to convert Lisp
    objects, being arguments of `dbus-call-method' or
    `dbus-send-signal', into corresponding C values appended as
    arguments to a D-Bus message.  */
 static void
-xd_append_arg (unsigned int dtype, Lisp_Object object, DBusMessageIter *iter)
+xd_append_arg (int dtype, Lisp_Object object, DBusMessageIter *iter)
 {
   char signature[DBUS_MAXIMUM_SIGNATURE_LENGTH];
   DBusMessageIter subiter;
@@ -550,7 +612,7 @@ xd_append_arg (unsigned int dtype, Lisp_Object object, DBusMessageIter *iter)
        CHECK_NATNUM (object);
        {
          unsigned char val = XFASTINT (object) & 0xFF;
-         XD_DEBUG_MESSAGE ("%c %d", dtype, val);
+         XD_DEBUG_MESSAGE ("%c %u", dtype, val);
          if (!dbus_message_iter_append_basic (iter, dtype, &val))
            XD_SIGNAL2 (build_string ("Unable to append argument"), object);
          return;
@@ -566,20 +628,25 @@ xd_append_arg (unsigned int dtype, Lisp_Object object, DBusMessageIter *iter)
        }
 
       case DBUS_TYPE_INT16:
-       CHECK_NUMBER (object);
        {
-         dbus_int16_t val = XINT (object);
-         XD_DEBUG_MESSAGE ("%c %d", dtype, (int) val);
+         dbus_int16_t val =
+           xd_extract_signed (object,
+                              TYPE_MINIMUM (dbus_int16_t),
+                              TYPE_MAXIMUM (dbus_int16_t));
+         int pval = val;
+         XD_DEBUG_MESSAGE ("%c %d", dtype, pval);
          if (!dbus_message_iter_append_basic (iter, dtype, &val))
            XD_SIGNAL2 (build_string ("Unable to append argument"), object);
          return;
        }
 
       case DBUS_TYPE_UINT16:
-       CHECK_NATNUM (object);
        {
-         dbus_uint16_t val = XFASTINT (object);
-         XD_DEBUG_MESSAGE ("%c %u", dtype, (unsigned int) val);
+         dbus_uint16_t val =
+           xd_extract_unsigned (object,
+                                TYPE_MAXIMUM (dbus_uint16_t));
+         unsigned int pval = val;
+         XD_DEBUG_MESSAGE ("%c %u", dtype, pval);
          if (!dbus_message_iter_append_basic (iter, dtype, &val))
            XD_SIGNAL2 (build_string ("Unable to append argument"), object);
          return;
@@ -587,8 +654,12 @@ xd_append_arg (unsigned int dtype, Lisp_Object object, DBusMessageIter *iter)
 
       case DBUS_TYPE_INT32:
        {
-         dbus_int32_t val = extract_float (object);
-         XD_DEBUG_MESSAGE ("%c %d", dtype, val);
+         dbus_int32_t val =
+           xd_extract_signed (object,
+                              TYPE_MINIMUM (dbus_int32_t),
+                              TYPE_MAXIMUM (dbus_int32_t));
+         int pval = val;
+         XD_DEBUG_MESSAGE ("%c %d", dtype, pval);
          if (!dbus_message_iter_append_basic (iter, dtype, &val))
            XD_SIGNAL2 (build_string ("Unable to append argument"), object);
          return;
@@ -599,8 +670,11 @@ xd_append_arg (unsigned int dtype, Lisp_Object object, DBusMessageIter *iter)
       case DBUS_TYPE_UNIX_FD:
 #endif
        {
-         dbus_uint32_t val = extract_float (object);
-         XD_DEBUG_MESSAGE ("%c %u", dtype, val);
+         dbus_uint32_t val =
+           xd_extract_unsigned (object,
+                                TYPE_MAXIMUM (dbus_uint32_t));
+         unsigned int pval = val;
+         XD_DEBUG_MESSAGE ("%c %u", dtype, pval);
          if (!dbus_message_iter_append_basic (iter, dtype, &val))
            XD_SIGNAL2 (build_string ("Unable to append argument"), object);
          return;
@@ -608,8 +682,12 @@ xd_append_arg (unsigned int dtype, Lisp_Object object, DBusMessageIter *iter)
 
       case DBUS_TYPE_INT64:
        {
-         dbus_int64_t val = extract_float (object);
-         XD_DEBUG_MESSAGE ("%c %d", dtype, (int) val);
+         dbus_int64_t val =
+           xd_extract_signed (object,
+                              TYPE_MINIMUM (dbus_int64_t),
+                              TYPE_MAXIMUM (dbus_int64_t));
+         printmax_t pval = val;
+         XD_DEBUG_MESSAGE ("%c %"pMd, dtype, pval);
          if (!dbus_message_iter_append_basic (iter, dtype, &val))
            XD_SIGNAL2 (build_string ("Unable to append argument"), object);
          return;
@@ -617,8 +695,11 @@ xd_append_arg (unsigned int dtype, Lisp_Object object, DBusMessageIter *iter)
 
       case DBUS_TYPE_UINT64:
        {
-         dbus_uint64_t val = extract_float (object);
-         XD_DEBUG_MESSAGE ("%c %"pI"d", dtype, val);
+         dbus_uint64_t val =
+           xd_extract_unsigned (object,
+                                TYPE_MAXIMUM (dbus_uint64_t));
+         uprintmax_t pval = val;
+         XD_DEBUG_MESSAGE ("%c %"pMu, dtype, pval);
          if (!dbus_message_iter_append_basic (iter, dtype, &val))
            XD_SIGNAL2 (build_string ("Unable to append argument"), object);
          return;
@@ -743,7 +824,7 @@ xd_append_arg (unsigned int dtype, Lisp_Object object, DBusMessageIter *iter)
    D-Bus message must be a valid DBusType.  Compound D-Bus types
    result always in a Lisp list.  */
 static Lisp_Object
-xd_retrieve_arg (unsigned int dtype, DBusMessageIter *iter)
+xd_retrieve_arg (int dtype, DBusMessageIter *iter)
 {
 
   switch (dtype)
@@ -753,7 +834,7 @@ xd_retrieve_arg (unsigned int dtype, DBusMessageIter *iter)
        unsigned int val;
        dbus_message_iter_get_basic (iter, &val);
        val = val & 0xFF;
-       XD_DEBUG_MESSAGE ("%c %d", dtype, val);
+       XD_DEBUG_MESSAGE ("%c %u", dtype, val);
        return make_number (val);
       }
 
@@ -768,24 +849,30 @@ xd_retrieve_arg (unsigned int dtype, DBusMessageIter *iter)
     case DBUS_TYPE_INT16:
       {
        dbus_int16_t val;
+       int pval;
        dbus_message_iter_get_basic (iter, &val);
-       XD_DEBUG_MESSAGE ("%c %d", dtype, val);
+       pval = val;
+       XD_DEBUG_MESSAGE ("%c %d", dtype, pval);
        return make_number (val);
       }
 
     case DBUS_TYPE_UINT16:
       {
        dbus_uint16_t val;
+       int pval;
        dbus_message_iter_get_basic (iter, &val);
-       XD_DEBUG_MESSAGE ("%c %d", dtype, val);
+       pval = val;
+       XD_DEBUG_MESSAGE ("%c %d", dtype, pval);
        return make_number (val);
       }
 
     case DBUS_TYPE_INT32:
       {
        dbus_int32_t val;
+       int pval;
        dbus_message_iter_get_basic (iter, &val);
-       XD_DEBUG_MESSAGE ("%c %d", dtype, val);
+       pval = val;
+       XD_DEBUG_MESSAGE ("%c %d", dtype, pval);
        return make_fixnum_or_float (val);
       }
 
@@ -795,24 +882,30 @@ xd_retrieve_arg (unsigned int dtype, DBusMessageIter *iter)
 #endif
       {
        dbus_uint32_t val;
+       unsigned int pval = val;
        dbus_message_iter_get_basic (iter, &val);
-       XD_DEBUG_MESSAGE ("%c %d", dtype, val);
+       pval = val;
+       XD_DEBUG_MESSAGE ("%c %u", dtype, pval);
        return make_fixnum_or_float (val);
       }
 
     case DBUS_TYPE_INT64:
       {
        dbus_int64_t val;
+       printmax_t pval;
        dbus_message_iter_get_basic (iter, &val);
-       XD_DEBUG_MESSAGE ("%c %d", dtype, (int) val);
+       pval = val;
+       XD_DEBUG_MESSAGE ("%c %"pMd, dtype, pval);
        return make_fixnum_or_float (val);
       }
 
     case DBUS_TYPE_UINT64:
       {
        dbus_uint64_t val;
+       uprintmax_t pval;
        dbus_message_iter_get_basic (iter, &val);
-       XD_DEBUG_MESSAGE ("%c %d", dtype, (int) val);
+       pval = val;
+       XD_DEBUG_MESSAGE ("%c %"pMd, dtype, pval);
        return make_fixnum_or_float (val);
       }
 
@@ -863,7 +956,7 @@ xd_retrieve_arg (unsigned int dtype, DBusMessageIter *iter)
 }
 
 /* Return the number of references of the shared CONNECTION.  */
-static int
+static ptrdiff_t
 xd_get_connection_references (DBusConnection *connection)
 {
   ptrdiff_t *refcount;
@@ -884,11 +977,11 @@ xd_get_connection_address (Lisp_Object bus)
   DBusConnection *connection;
   Lisp_Object val;
 
-  val = CDR_SAFE (Fassoc (bus, Vdbus_registered_buses));
+  val = CDR_SAFE (Fassoc (bus, xd_registered_buses));
   if (NILP (val))
     XD_SIGNAL2 (build_string ("No connection to bus"), bus);
   else
-    connection = (DBusConnection *) XFASTINT (val);
+    connection = (DBusConnection *) (intptr_t) XFASTINT (val);
 
   if (!dbus_connection_get_is_connected (connection))
     XD_SIGNAL2 (build_string ("No connection to bus"), bus);
@@ -901,7 +994,7 @@ static int
 xd_find_watch_fd (DBusWatch *watch)
 {
 #if HAVE_DBUS_WATCH_GET_UNIX_FD
-  /* TODO: Reverse these on Win32, which prefers the opposite.  */
+  /* TODO: Reverse these on w32, which prefers the opposite.  */
   int fd = dbus_watch_get_unix_fd (watch);
   if (fd == -1)
     fd = dbus_watch_get_socket (watch);
@@ -912,8 +1005,7 @@ xd_find_watch_fd (DBusWatch *watch)
 }
 
 /* Prototype.  */
-static void
-xd_read_queued_messages (int fd, void *data, int for_read);
+static void xd_read_queued_messages (int fd, void *data);
 
 /* Start monitoring WATCH for possible I/O.  */
 static dbus_bool_t
@@ -954,11 +1046,13 @@ xd_remove_watch (DBusWatch *watch, void *data)
     return;
 
   /* Unset session environment.  */
+#if 0
   if (XSYMBOL (QCdbus_session_bus) == data)
     {
-      //      XD_DEBUG_MESSAGE ("unsetenv DBUS_SESSION_BUS_ADDRESS");
-      //      unsetenv ("DBUS_SESSION_BUS_ADDRESS");
+      XD_DEBUG_MESSAGE ("unsetenv DBUS_SESSION_BUS_ADDRESS");
+      unsetenv ("DBUS_SESSION_BUS_ADDRESS");
     }
+#endif
 
   if (flags & DBUS_WATCH_WRITABLE)
     delete_write_fd (fd);
@@ -984,26 +1078,26 @@ xd_close_bus (Lisp_Object bus)
   Lisp_Object val;
 
   /* Check whether we are connected.  */
-  val = Fassoc (bus, Vdbus_registered_buses);
+  val = Fassoc (bus, xd_registered_buses);
   if (NILP (val))
     return;
 
   /* Retrieve bus address.  */
   connection = xd_get_connection_address (bus);
 
-  /* Close connection, if there isn't another shared application.  */
   if (xd_get_connection_references (connection) == 1)
     {
+      /* Close connection, if there isn't another shared application.  */
       XD_DEBUG_MESSAGE ("Close connection to bus %s",
                        XD_OBJECT_TO_STRING (bus));
       dbus_connection_close (connection);
-    }
 
-  /* Decrement reference count.  */
-  dbus_connection_unref (connection);
+      xd_registered_buses = Fdelete (val, xd_registered_buses);
+    }
 
-  /* Remove bus from list of registered buses.  */
-  Vdbus_registered_buses = Fdelete (val, Vdbus_registered_buses);
+  else
+    /* Decrement reference count.  */
+    dbus_connection_unref (connection);
 
   /* Return.  */
   return;
@@ -1036,7 +1130,7 @@ this connection to those buses.  */)
   DBusConnection *connection;
   DBusError derror;
   Lisp_Object val;
-  int refcount;
+  ptrdiff_t refcount;
 
   /* Check parameter.  */
   XD_DBUS_VALIDATE_BUS_ADDRESS (bus);
@@ -1044,69 +1138,80 @@ this connection to those buses.  */)
   /* Close bus if it is already open.  */
   xd_close_bus (bus);
 
-  /* Initialize.  */
-  dbus_error_init (&derror);
-
-  /* Open the connection.  */
-  if (STRINGP (bus))
-    if (NILP (private))
-      connection = dbus_connection_open (SSDATA (bus), &derror);
-    else
-      connection = dbus_connection_open_private (SSDATA (bus), &derror);
+  /* Check, whether we are still connected.  */
+  val = Fassoc (bus, xd_registered_buses);
+  if (!NILP (val))
+    {
+      connection = xd_get_connection_address (bus);
+      dbus_connection_ref (connection);
+    }
 
   else
-    if (NILP (private))
-      connection = dbus_bus_get (EQ (bus, QCdbus_system_bus)
-                                ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION,
-                                &derror);
-    else
-      connection = dbus_bus_get_private (EQ (bus, QCdbus_system_bus)
-                                        ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION,
-                                        &derror);
-
-  if (dbus_error_is_set (&derror))
-    XD_ERROR (derror);
-
-  if (connection == NULL)
-    XD_SIGNAL2 (build_string ("No connection to bus"), bus);
+    {
+      /* Initialize.  */
+      dbus_error_init (&derror);
 
-  /* If it is not the system or session bus, we must register
-     ourselves.  Otherwise, we have called dbus_bus_get, which has
-     configured us to exit if the connection closes - we undo this
-     setting.  */
-  if (STRINGP (bus))
-    dbus_bus_register (connection, &derror);
-  else
-    dbus_connection_set_exit_on_disconnect (connection, FALSE);
-
-  if (dbus_error_is_set (&derror))
-    XD_ERROR (derror);
-
-  /* Add the watch functions.  We pass also the bus as data, in order
-     to distinguish between the buses in xd_remove_watch.  */
-  if (!dbus_connection_set_watch_functions (connection,
-                                           xd_add_watch,
-                                           xd_remove_watch,
-                                            xd_toggle_watch,
-                                           SYMBOLP (bus)
-                                           ? (void *) XSYMBOL (bus)
-                                           : (void *) XSTRING (bus),
-                                           NULL))
-    XD_SIGNAL1 (build_string ("Cannot add watch functions"));
-
-  /* Add bus to list of registered buses.  */
-  XSETFASTINT (val, connection);
-  Vdbus_registered_buses = Fcons (Fcons (bus, val), Vdbus_registered_buses);
-
-  /* We do not want to abort.  */
-  putenv ((char *) "DBUS_FATAL_WARNINGS=0");
+      /* Open the connection.  */
+      if (STRINGP (bus))
+       if (NILP (private))
+         connection = dbus_connection_open (SSDATA (bus), &derror);
+       else
+         connection = dbus_connection_open_private (SSDATA (bus), &derror);
 
-  /* Cleanup.  */
-  dbus_error_free (&derror);
+      else
+       if (NILP (private))
+         connection = dbus_bus_get (EQ (bus, QCdbus_system_bus)
+                                    ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION,
+                                    &derror);
+       else
+         connection = dbus_bus_get_private (EQ (bus, QCdbus_system_bus)
+                                            ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION,
+                                            &derror);
+
+      if (dbus_error_is_set (&derror))
+       XD_ERROR (derror);
+
+      if (connection == NULL)
+       XD_SIGNAL2 (build_string ("No connection to bus"), bus);
+
+      /* If it is not the system or session bus, we must register
+        ourselves.  Otherwise, we have called dbus_bus_get, which has
+        configured us to exit if the connection closes - we undo this
+        setting.  */
+      if (STRINGP (bus))
+       dbus_bus_register (connection, &derror);
+      else
+       dbus_connection_set_exit_on_disconnect (connection, FALSE);
+
+      if (dbus_error_is_set (&derror))
+       XD_ERROR (derror);
+
+      /* Add the watch functions.  We pass also the bus as data, in
+        order to distinguish between the buses in xd_remove_watch.  */
+      if (!dbus_connection_set_watch_functions (connection,
+                                               xd_add_watch,
+                                               xd_remove_watch,
+                                               xd_toggle_watch,
+                                               SYMBOLP (bus)
+                                               ? (void *) XSYMBOL (bus)
+                                               : (void *) XSTRING (bus),
+                                               NULL))
+       XD_SIGNAL1 (build_string ("Cannot add watch functions"));
+
+      /* Add bus to list of registered buses.  */
+      XSETFASTINT (val, (intptr_t) connection);
+      xd_registered_buses = Fcons (Fcons (bus, val), xd_registered_buses);
+
+      /* We do not want to abort.  */
+      xputenv ("DBUS_FATAL_WARNINGS=0");
+
+      /* Cleanup.  */
+      dbus_error_free (&derror);
+    }
 
   /* Return reference counter.  */
   refcount = xd_get_connection_references (connection);
-  XD_DEBUG_MESSAGE ("Bus %s, Reference counter %d",
+  XD_DEBUG_MESSAGE ("Bus %s, Reference counter %"pD"d",
                    XD_OBJECT_TO_STRING (bus), refcount);
   return make_number (refcount);
 }
@@ -1170,9 +1275,10 @@ usage: (dbus-message-internal &rest REST)  */)
   DBusConnection *connection;
   DBusMessage *dmessage;
   DBusMessageIter iter;
-  unsigned int dtype;
-  unsigned int mtype;
+  int dtype;
+  int mtype;
   dbus_uint32_t serial = 0;
+  unsigned int ui_serial;
   int timeout = -1;
   ptrdiff_t count;
   char signature[DBUS_MAXIMUM_SIGNATURE_LENGTH];
@@ -1184,9 +1290,10 @@ usage: (dbus-message-internal &rest REST)  */)
   handler = Qnil;
 
   CHECK_NATNUM (message_type);
-  mtype = XFASTINT (message_type);
-  if ((mtype <= DBUS_MESSAGE_TYPE_INVALID) || (mtype >= DBUS_NUM_MESSAGE_TYPES))
+  if (! (DBUS_MESSAGE_TYPE_INVALID < XFASTINT (message_type)
+        && XFASTINT (message_type) < DBUS_NUM_MESSAGE_TYPES))
     XD_SIGNAL2 (build_string ("Invalid message type"), message_type);
+  mtype = XFASTINT (message_type);
 
   if ((mtype == DBUS_MESSAGE_TYPE_METHOD_CALL)
       || (mtype == DBUS_MESSAGE_TYPE_SIGNAL))
@@ -1200,7 +1307,7 @@ usage: (dbus-message-internal &rest REST)  */)
     }
   else /* DBUS_MESSAGE_TYPE_METHOD_RETURN, DBUS_MESSAGE_TYPE_ERROR  */
     {
-      XD_CHECK_DBUS_SERIAL (args[3], serial);
+      serial = xd_extract_unsigned (args[3], TYPE_MAXIMUM (dbus_uint32_t));
       count = 4;
     }
 
@@ -1248,11 +1355,12 @@ usage: (dbus-message-internal &rest REST)  */)
                        XD_OBJECT_TO_STRING (member));
       break;
     default: /* DBUS_MESSAGE_TYPE_METHOD_RETURN, DBUS_MESSAGE_TYPE_ERROR  */
+      ui_serial = serial;
       XD_DEBUG_MESSAGE ("%s %s %s %u",
                        XD_MESSAGE_TYPE_TO_STRING (mtype),
                        XD_OBJECT_TO_STRING (bus),
                        XD_OBJECT_TO_STRING (service),
-                       serial);
+                       ui_serial);
     }
 
   /* Retrieve bus address.  */
@@ -1337,7 +1445,7 @@ usage: (dbus-message-internal &rest REST)  */)
   if ((count+2 <= nargs) && (EQ ((args[count]), QCdbus_timeout)))
     {
       CHECK_NATNUM (args[count+1]);
-      timeout = XFASTINT (args[count+1]);
+      timeout = min (XFASTINT (args[count+1]), INT_MAX);
       count = count+2;
     }
 
@@ -1423,8 +1531,8 @@ xd_read_message_1 (DBusConnection *connection, Lisp_Object bus)
   struct input_event event;
   DBusMessage *dmessage;
   DBusMessageIter iter;
-  unsigned int dtype;
-  unsigned int mtype;
+  int dtype;
+  int mtype;
   dbus_uint32_t serial;
   unsigned int ui_serial;
   const char *uname, *path, *interface, *member;
@@ -1585,9 +1693,9 @@ xd_read_message (Lisp_Object bus)
 
 /* Callback called when something is ready to read or write.  */
 static void
-xd_read_queued_messages (int fd, void *data, int for_read)
+xd_read_queued_messages (int fd, void *data)
 {
-  Lisp_Object busp = Vdbus_registered_buses;
+  Lisp_Object busp = xd_registered_buses;
   Lisp_Object bus = Qnil;
   Lisp_Object key;
 
@@ -1629,7 +1737,7 @@ syms_of_dbusbind (void)
   Fput (Qdbus_error, Qerror_conditions,
        list2 (Qdbus_error, Qerror));
   Fput (Qdbus_error, Qerror_message,
-       make_pure_c_string ("D-Bus error"));
+       build_pure_c_string ("D-Bus error"));
 
   DEFSYM (QCdbus_system_bus, ":system");
   DEFSYM (QCdbus_session_bus, ":session");
@@ -1661,7 +1769,7 @@ syms_of_dbusbind (void)
               Vdbus_compiled_version,
     doc: /* The version of D-Bus Emacs is compiled against.  */);
 #ifdef DBUS_VERSION_STRING
-  Vdbus_compiled_version = make_pure_c_string (DBUS_VERSION_STRING);
+  Vdbus_compiled_version = build_pure_c_string (DBUS_VERSION_STRING);
 #else
   Vdbus_compiled_version = Qnil;
 #endif
@@ -1672,10 +1780,10 @@ syms_of_dbusbind (void)
   {
 #ifdef DBUS_VERSION
     int major, minor, micro;
-    char s[1024];
+    char s[sizeof ".." + 3 * INT_STRLEN_BOUND (int)];
     dbus_get_version (&major, &minor, &micro);
-    snprintf (s, sizeof s, "%d.%d.%d", major, minor, micro);
-    Vdbus_runtime_version = make_string (s, strlen (s));
+    Vdbus_runtime_version
+      = make_formatted_string (s, "%d.%d.%d", major, minor, micro);
 #else
     Vdbus_runtime_version = Qnil;
 #endif
@@ -1707,14 +1815,6 @@ syms_of_dbusbind (void)
     doc: /* Message type of a signal message.  */);
   Vdbus_message_type_signal = make_number (DBUS_MESSAGE_TYPE_SIGNAL);
 
-  DEFVAR_LISP ("dbus-registered-buses",
-              Vdbus_registered_buses,
-    doc: /* Alist of D-Bus buses we are polling for messages.
-
-The key is the symbol or string of the bus, and the value is the
-connection address.  */);
-  Vdbus_registered_buses = Qnil;
-
   DEFVAR_LISP ("dbus-registered-objects-table",
               Vdbus_registered_objects_table,
     doc: /* Hash table of registered functions for D-Bus.
@@ -1768,6 +1868,10 @@ be called when the D-Bus reply message arrives.  */);
   Vdbus_debug = Qnil;
 #endif
 
+  /* Initialize internal objects.  */
+  xd_registered_buses = Qnil;
+  staticpro (&xd_registered_buses);
+
   Fprovide (intern_c_string ("dbusbind"), Qnil);
 
 }