#ifdef HAVE_DBUS
#include <stdio.h>
#include <dbus/dbus.h>
-#include <setjmp.h>
+
#include "lisp.h"
#include "frame.h"
#include "termhooks.h"
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
#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) \
|| (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
#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; \
/* 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 \
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)
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;
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;
}
case DBUS_TYPE_INT16:
- CHECK_NUMBER (object);
{
- dbus_int16_t val = XINT (object);
+ 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))
}
case DBUS_TYPE_UINT16:
- CHECK_NATNUM (object);
{
- dbus_uint16_t val = XFASTINT (object);
+ 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))
case DBUS_TYPE_INT32:
{
- dbus_int32_t val = extract_float (object);
+ 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))
case DBUS_TYPE_UNIX_FD:
#endif
{
- dbus_uint32_t val = extract_float (object);
+ 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))
case DBUS_TYPE_INT64:
{
- dbus_int64_t val = extract_float (object);
+ 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))
case DBUS_TYPE_UINT64:
{
- dbus_uint64_t val = extract_float (object);
+ 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))
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)
}
/* Return the number of references of the shared CONNECTION. */
-static int
+static ptrdiff_t
xd_get_connection_references (DBusConnection *connection)
{
ptrdiff_t *refcount;
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
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);
}
/* 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
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);
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;
DBusConnection *connection;
DBusError derror;
Lisp_Object val;
- int refcount;
+ ptrdiff_t refcount;
/* Check parameter. */
XD_DBUS_VALIDATE_BUS_ADDRESS (bus);
/* 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, (intptr_t) 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. */
+ putenv ((char *) "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);
}
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;
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))
}
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;
}
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;
}
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;
/* 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;
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");
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
{
#ifdef DBUS_VERSION
int major, minor, micro;
- char s[1024];
+ char s[sizeof ".." + 3 * INT_STRLEN_BOUND (int)];
dbus_get_version (&major, &minor, µ);
- 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
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.
Vdbus_debug = Qnil;
#endif
+ /* Initialize internal objects. */
+ xd_registered_buses = Qnil;
+ staticpro (&xd_registered_buses);
+
Fprovide (intern_c_string ("dbusbind"), Qnil);
}