* dbusbind.c (XD_BASIC_DBUS_TYPE): Use dbus_type_is_valid and
[bpt/emacs.git] / src / dbusbind.c
index 0ea08d7..d80bb21 100644 (file)
@@ -64,6 +64,11 @@ 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;
 
@@ -111,12 +116,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 +147,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 +181,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,22 +259,6 @@ 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 {                                                                 \
     if (STRINGP (bus))                                                 \
@@ -360,9 +355,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 +527,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 +599,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 +615,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 +641,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 +657,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 +669,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 +682,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 +811,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 +821,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 +836,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 +869,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 +943,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 +964,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);
@@ -984,7 +1064,7 @@ 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;
 
@@ -1003,7 +1083,7 @@ xd_close_bus (Lisp_Object bus)
   dbus_connection_unref (connection);
 
   /* Remove bus from list of registered buses.  */
-  Vdbus_registered_buses = Fdelete (val, Vdbus_registered_buses);
+  xd_registered_buses = Fdelete (val, xd_registered_buses);
 
   /* Return.  */
   return;
@@ -1036,7 +1116,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);
@@ -1095,8 +1175,8 @@ this connection to those buses.  */)
     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);
+  XSETFASTINT (val, (intptr_t) connection);
+  xd_registered_buses = Fcons (Fcons (bus, val), xd_registered_buses);
 
   /* We do not want to abort.  */
   putenv ((char *) "DBUS_FATAL_WARNINGS=0");
@@ -1106,7 +1186,7 @@ this connection to those buses.  */)
 
   /* 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 +1250,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 +1265,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 +1282,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 +1330,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 +1420,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 +1506,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;
@@ -1587,7 +1670,7 @@ xd_read_message (Lisp_Object bus)
 static void
 xd_read_queued_messages (int fd, void *data, int for_read)
 {
-  Lisp_Object busp = Vdbus_registered_buses;
+  Lisp_Object busp = xd_registered_buses;
   Lisp_Object bus = Qnil;
   Lisp_Object key;
 
@@ -1672,10 +1755,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));
+    sprintf (s, "%d.%d.%d", major, minor, micro);
+    Vdbus_runtime_version = build_string (s);
 #else
     Vdbus_runtime_version = Qnil;
 #endif
@@ -1707,14 +1790,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 +1843,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);
 
 }