Merge from emacs-24; up to 2012-12-30T19:34:25Z!jan.h.d@swipnet.se
[bpt/emacs.git] / src / dbusbind.c
CommitLineData
033b73e2 1/* Elisp bindings for D-Bus.
ab422c4d 2 Copyright (C) 2007-2013 Free Software Foundation, Inc.
033b73e2
MA
3
4This file is part of GNU Emacs.
5
9ec0b715 6GNU Emacs is free software: you can redistribute it and/or modify
033b73e2 7it under the terms of the GNU General Public License as published by
9ec0b715
GM
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version.
033b73e2
MA
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
9ec0b715 17along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
033b73e2 18
08a494a3 19#include <config.h>
033b73e2
MA
20
21#ifdef HAVE_DBUS
f5306ca3 22#include <stdio.h>
033b73e2 23#include <dbus/dbus.h>
0328b6de 24
033b73e2
MA
25#include "lisp.h"
26#include "frame.h"
27#include "termhooks.h"
28#include "keyboard.h"
3fad2ad2 29#include "process.h"
033b73e2 30
dcbf5805
MA
31#ifndef DBUS_NUM_MESSAGE_TYPES
32#define DBUS_NUM_MESSAGE_TYPES 5
33#endif
34
9520f2f2
DC
35
36/* Some platforms define the symbol "interface", but we want to use it
37 * as a variable name below. */
38
3e0341b0
DC
39#ifdef interface
40#undef interface
41#endif
42
033b73e2
MA
43\f
44/* Subroutines. */
955cbe7b 45static Lisp_Object Qdbus_init_bus;
955cbe7b 46static Lisp_Object Qdbus_get_unique_name;
dcbf5805 47static Lisp_Object Qdbus_message_internal;
033b73e2
MA
48
49/* D-Bus error symbol. */
955cbe7b 50static Lisp_Object Qdbus_error;
033b73e2
MA
51
52/* Lisp symbols of the system and session buses. */
955cbe7b 53static Lisp_Object QCdbus_system_bus, QCdbus_session_bus;
033b73e2 54
90b3fc84 55/* Lisp symbol for method call timeout. */
955cbe7b 56static Lisp_Object QCdbus_timeout;
90b3fc84 57
54371585 58/* Lisp symbols of D-Bus types. */
955cbe7b
PE
59static Lisp_Object QCdbus_type_byte, QCdbus_type_boolean;
60static Lisp_Object QCdbus_type_int16, QCdbus_type_uint16;
61static Lisp_Object QCdbus_type_int32, QCdbus_type_uint32;
62static Lisp_Object QCdbus_type_int64, QCdbus_type_uint64;
63static Lisp_Object QCdbus_type_double, QCdbus_type_string;
64static Lisp_Object QCdbus_type_object_path, QCdbus_type_signature;
da1fec2b 65#ifdef DBUS_TYPE_UNIX_FD
b4289b64 66static Lisp_Object QCdbus_type_unix_fd;
da1fec2b 67#endif
955cbe7b
PE
68static Lisp_Object QCdbus_type_array, QCdbus_type_variant;
69static Lisp_Object QCdbus_type_struct, QCdbus_type_dict_entry;
54371585 70
dcbf5805
MA
71/* Lisp symbols of objects in `dbus-registered-objects-table'. */
72static Lisp_Object QCdbus_registered_serial, QCdbus_registered_method;
73static Lisp_Object QCdbus_registered_signal;
74
5cb67954
MA
75/* Alist of D-Bus buses we are polling for messages.
76 The key is the symbol or string of the bus, and the value is the
77 connection address. */
78static Lisp_Object xd_registered_buses;
79
1dae9197 80/* Whether we are reading a D-Bus event. */
de1339b0 81static bool xd_in_read_queued_messages = 0;
1dae9197 82
033b73e2
MA
83\f
84/* We use "xd_" and "XD_" as prefix for all internal symbols, because
85 we don't want to poison other namespaces with "dbus_". */
86
1dae9197
MA
87/* Raise a signal. If we are reading events, we cannot signal; we
88 throw to xd_read_queued_messages then. */
89#define XD_SIGNAL1(arg) \
90 do { \
91 if (xd_in_read_queued_messages) \
92 Fthrow (Qdbus_error, Qnil); \
93 else \
94 xsignal1 (Qdbus_error, arg); \
95 } while (0)
96
97#define XD_SIGNAL2(arg1, arg2) \
98 do { \
99 if (xd_in_read_queued_messages) \
100 Fthrow (Qdbus_error, Qnil); \
101 else \
102 xsignal2 (Qdbus_error, arg1, arg2); \
103 } while (0)
104
105#define XD_SIGNAL3(arg1, arg2, arg3) \
106 do { \
107 if (xd_in_read_queued_messages) \
108 Fthrow (Qdbus_error, Qnil); \
109 else \
110 xsignal3 (Qdbus_error, arg1, arg2, arg3); \
111 } while (0)
112
54371585 113/* Raise a Lisp error from a D-Bus ERROR. */
033b73e2 114#define XD_ERROR(error) \
17bc8f94 115 do { \
033b73e2 116 /* Remove the trailing newline. */ \
573f4b54
PE
117 char const *mess = error.message; \
118 char const *nl = strchr (mess, '\n'); \
119 Lisp_Object err = make_string (mess, nl ? nl - mess : strlen (mess)); \
120 dbus_error_free (&error); \
121 XD_SIGNAL1 (err); \
17bc8f94 122 } while (0)
033b73e2
MA
123
124/* Macros for debugging. In order to enable them, build with
dcbf5805 125 "env MYCPPFLAGS='-DDBUS_DEBUG -Wall' make". */
033b73e2 126#ifdef DBUS_DEBUG
9a4b36f8
MA
127#define XD_DEBUG_MESSAGE(...) \
128 do { \
129 char s[1024]; \
130 snprintf (s, sizeof s, __VA_ARGS__); \
131 if (!noninteractive) \
132 printf ("%s: %s\n", __func__, s); \
133 message ("%s: %s", __func__, s); \
17bc8f94 134 } while (0)
033b73e2 135#define XD_DEBUG_VALID_LISP_OBJECT_P(object) \
17bc8f94
MA
136 do { \
137 if (!valid_lisp_object_p (object)) \
138 { \
139 XD_DEBUG_MESSAGE ("%d Assertion failure", __LINE__); \
1dae9197 140 XD_SIGNAL1 (build_string ("Assertion failure")); \
17bc8f94
MA
141 } \
142 } while (0)
033b73e2
MA
143
144#else /* !DBUS_DEBUG */
17bc8f94
MA
145#define XD_DEBUG_MESSAGE(...) \
146 do { \
147 if (!NILP (Vdbus_debug)) \
148 { \
149 char s[1024]; \
dcbf5805 150 snprintf (s, sizeof s, __VA_ARGS__); \
17bc8f94 151 message ("%s: %s", __func__, s); \
80f9d13b 152 } \
17bc8f94 153 } while (0)
033b73e2
MA
154#define XD_DEBUG_VALID_LISP_OBJECT_P(object)
155#endif
156
87cf1a39 157/* Check whether TYPE is a basic DBusType. */
ff88beb8
MA
158#ifdef HAVE_DBUS_TYPE_IS_VALID
159#define XD_BASIC_DBUS_TYPE(type) \
160 (dbus_type_is_valid (type) && dbus_type_is_basic (type))
161#else
da1fec2b
MA
162#ifdef DBUS_TYPE_UNIX_FD
163#define XD_BASIC_DBUS_TYPE(type) \
164 ((type == DBUS_TYPE_BYTE) \
165 || (type == DBUS_TYPE_BOOLEAN) \
166 || (type == DBUS_TYPE_INT16) \
167 || (type == DBUS_TYPE_UINT16) \
168 || (type == DBUS_TYPE_INT32) \
169 || (type == DBUS_TYPE_UINT32) \
170 || (type == DBUS_TYPE_INT64) \
171 || (type == DBUS_TYPE_UINT64) \
172 || (type == DBUS_TYPE_DOUBLE) \
173 || (type == DBUS_TYPE_STRING) \
174 || (type == DBUS_TYPE_OBJECT_PATH) \
01768686 175 || (type == DBUS_TYPE_SIGNATURE) \
da1fec2b
MA
176 || (type == DBUS_TYPE_UNIX_FD))
177#else
87cf1a39
MA
178#define XD_BASIC_DBUS_TYPE(type) \
179 ((type == DBUS_TYPE_BYTE) \
180 || (type == DBUS_TYPE_BOOLEAN) \
181 || (type == DBUS_TYPE_INT16) \
182 || (type == DBUS_TYPE_UINT16) \
183 || (type == DBUS_TYPE_INT32) \
184 || (type == DBUS_TYPE_UINT32) \
185 || (type == DBUS_TYPE_INT64) \
186 || (type == DBUS_TYPE_UINT64) \
187 || (type == DBUS_TYPE_DOUBLE) \
188 || (type == DBUS_TYPE_STRING) \
189 || (type == DBUS_TYPE_OBJECT_PATH) \
190 || (type == DBUS_TYPE_SIGNATURE))
da1fec2b 191#endif
ff88beb8 192#endif
87cf1a39 193
78c38319 194/* This was a macro. On Solaris 2.11 it was said to compile for
e1dbe924 195 hours, when optimization is enabled. So we have transferred it into
78c38319 196 a function. */
54371585
MA
197/* Determine the DBusType of a given Lisp symbol. OBJECT must be one
198 of the predefined D-Bus type symbols. */
78c38319 199static int
971de7fb 200xd_symbol_to_dbus_type (Lisp_Object object)
78c38319
MA
201{
202 return
203 ((EQ (object, QCdbus_type_byte)) ? DBUS_TYPE_BYTE
204 : (EQ (object, QCdbus_type_boolean)) ? DBUS_TYPE_BOOLEAN
205 : (EQ (object, QCdbus_type_int16)) ? DBUS_TYPE_INT16
206 : (EQ (object, QCdbus_type_uint16)) ? DBUS_TYPE_UINT16
207 : (EQ (object, QCdbus_type_int32)) ? DBUS_TYPE_INT32
208 : (EQ (object, QCdbus_type_uint32)) ? DBUS_TYPE_UINT32
209 : (EQ (object, QCdbus_type_int64)) ? DBUS_TYPE_INT64
210 : (EQ (object, QCdbus_type_uint64)) ? DBUS_TYPE_UINT64
211 : (EQ (object, QCdbus_type_double)) ? DBUS_TYPE_DOUBLE
212 : (EQ (object, QCdbus_type_string)) ? DBUS_TYPE_STRING
213 : (EQ (object, QCdbus_type_object_path)) ? DBUS_TYPE_OBJECT_PATH
214 : (EQ (object, QCdbus_type_signature)) ? DBUS_TYPE_SIGNATURE
da1fec2b
MA
215#ifdef DBUS_TYPE_UNIX_FD
216 : (EQ (object, QCdbus_type_unix_fd)) ? DBUS_TYPE_UNIX_FD
217#endif
78c38319
MA
218 : (EQ (object, QCdbus_type_array)) ? DBUS_TYPE_ARRAY
219 : (EQ (object, QCdbus_type_variant)) ? DBUS_TYPE_VARIANT
220 : (EQ (object, QCdbus_type_struct)) ? DBUS_TYPE_STRUCT
221 : (EQ (object, QCdbus_type_dict_entry)) ? DBUS_TYPE_DICT_ENTRY
222 : DBUS_TYPE_INVALID);
223}
87cf1a39
MA
224
225/* Check whether a Lisp symbol is a predefined D-Bus type symbol. */
226#define XD_DBUS_TYPE_P(object) \
78c38319 227 (SYMBOLP (object) && ((xd_symbol_to_dbus_type (object) != DBUS_TYPE_INVALID)))
54371585
MA
228
229/* Determine the DBusType of a given Lisp OBJECT. It is used to
033b73e2
MA
230 convert Lisp objects, being arguments of `dbus-call-method' or
231 `dbus-send-signal', into corresponding C values appended as
232 arguments to a D-Bus message. */
87cf1a39
MA
233#define XD_OBJECT_TO_DBUS_TYPE(object) \
234 ((EQ (object, Qt) || EQ (object, Qnil)) ? DBUS_TYPE_BOOLEAN \
235 : (NATNUMP (object)) ? DBUS_TYPE_UINT32 \
236 : (INTEGERP (object)) ? DBUS_TYPE_INT32 \
237 : (FLOATP (object)) ? DBUS_TYPE_DOUBLE \
238 : (STRINGP (object)) ? DBUS_TYPE_STRING \
78c38319 239 : (XD_DBUS_TYPE_P (object)) ? xd_symbol_to_dbus_type (object) \
07a4cb03
MA
240 : (CONSP (object)) \
241 ? ((XD_DBUS_TYPE_P (CAR_SAFE (object))) \
78c38319 242 ? ((XD_BASIC_DBUS_TYPE (xd_symbol_to_dbus_type (CAR_SAFE (object)))) \
07a4cb03 243 ? DBUS_TYPE_ARRAY \
78c38319 244 : xd_symbol_to_dbus_type (CAR_SAFE (object))) \
07a4cb03 245 : DBUS_TYPE_ARRAY) \
87cf1a39
MA
246 : DBUS_TYPE_INVALID)
247
248/* Return a list pointer which does not have a Lisp symbol as car. */
a8e72f4f 249#define XD_NEXT_VALUE(object) \
5125905e 250 ((XD_DBUS_TYPE_P (CAR_SAFE (object))) ? CDR_SAFE (object) : object)
87cf1a39 251
dcbf5805
MA
252/* Transform the message type to its string representation for debug
253 messages. */
254#define XD_MESSAGE_TYPE_TO_STRING(mtype) \
255 ((mtype == DBUS_MESSAGE_TYPE_INVALID) \
256 ? "DBUS_MESSAGE_TYPE_INVALID" \
257 : (mtype == DBUS_MESSAGE_TYPE_METHOD_CALL) \
258 ? "DBUS_MESSAGE_TYPE_METHOD_CALL" \
259 : (mtype == DBUS_MESSAGE_TYPE_METHOD_RETURN) \
260 ? "DBUS_MESSAGE_TYPE_METHOD_RETURN" \
261 : (mtype == DBUS_MESSAGE_TYPE_ERROR) \
262 ? "DBUS_MESSAGE_TYPE_ERROR" \
263 : "DBUS_MESSAGE_TYPE_SIGNAL")
264
265/* Transform the object to its string representation for debug
266 messages. */
267#define XD_OBJECT_TO_STRING(object) \
268 SDATA (format2 ("%s", object, Qnil))
269
dcbf5805
MA
270#define XD_DBUS_VALIDATE_BUS_ADDRESS(bus) \
271 do { \
e518bc71 272 char const *session_bus_address = getenv ("DBUS_SESSION_BUS_ADDRESS"); \
dcbf5805
MA
273 if (STRINGP (bus)) \
274 { \
275 DBusAddressEntry **entries; \
276 int len; \
277 DBusError derror; \
278 dbus_error_init (&derror); \
279 if (!dbus_parse_address (SSDATA (bus), &entries, &len, &derror)) \
280 XD_ERROR (derror); \
281 /* Cleanup. */ \
282 dbus_error_free (&derror); \
283 dbus_address_entries_free (entries); \
e518bc71 284 /* Canonicalize session bus address. */ \
1e4be88c
MA
285 if ((session_bus_address != NULL) \
286 && (!NILP (Fstring_equal \
287 (bus, build_string (session_bus_address))))) \
e518bc71 288 bus = QCdbus_session_bus; \
dcbf5805
MA
289 } \
290 \
291 else \
292 { \
293 CHECK_SYMBOL (bus); \
294 if (!(EQ (bus, QCdbus_system_bus) || EQ (bus, QCdbus_session_bus))) \
295 XD_SIGNAL2 (build_string ("Wrong bus name"), bus); \
296 /* We do not want to have an autolaunch for the session bus. */ \
e518bc71 297 if (EQ (bus, QCdbus_session_bus) && session_bus_address == NULL) \
dcbf5805
MA
298 XD_SIGNAL2 (build_string ("No connection to bus"), bus); \
299 } \
300 } while (0)
301
220cb2bd
MA
302#if (HAVE_DBUS_VALIDATE_BUS_NAME || HAVE_DBUS_VALIDATE_PATH \
303 || HAVE_DBUS_VALIDATE_INTERFACE || HAVE_DBUS_VALIDATE_MEMBER)
dcbf5805
MA
304#define XD_DBUS_VALIDATE_OBJECT(object, func) \
305 do { \
306 if (!NILP (object)) \
307 { \
308 DBusError derror; \
309 CHECK_STRING (object); \
310 dbus_error_init (&derror); \
311 if (!func (SSDATA (object), &derror)) \
312 XD_ERROR (derror); \
313 /* Cleanup. */ \
314 dbus_error_free (&derror); \
315 } \
316 } while (0)
de85e130 317#endif
dcbf5805
MA
318
319#if HAVE_DBUS_VALIDATE_BUS_NAME
320#define XD_DBUS_VALIDATE_BUS_NAME(bus_name) \
321 XD_DBUS_VALIDATE_OBJECT(bus_name, dbus_validate_bus_name);
322#else
323#define XD_DBUS_VALIDATE_BUS_NAME(bus_name) \
324 if (!NILP (bus_name)) CHECK_STRING (bus_name);
325#endif
326
327#if HAVE_DBUS_VALIDATE_PATH
328#define XD_DBUS_VALIDATE_PATH(path) \
329 XD_DBUS_VALIDATE_OBJECT(path, dbus_validate_path);
330#else
331#define XD_DBUS_VALIDATE_PATH(path) \
332 if (!NILP (path)) CHECK_STRING (path);
333#endif
334
335#if HAVE_DBUS_VALIDATE_INTERFACE
336#define XD_DBUS_VALIDATE_INTERFACE(interface) \
337 XD_DBUS_VALIDATE_OBJECT(interface, dbus_validate_interface);
338#else
339#define XD_DBUS_VALIDATE_INTERFACE(interface) \
340 if (!NILP (interface)) CHECK_STRING (interface);
341#endif
342
343#if HAVE_DBUS_VALIDATE_MEMBER
344#define XD_DBUS_VALIDATE_MEMBER(member) \
345 XD_DBUS_VALIDATE_OBJECT(member, dbus_validate_member);
346#else
347#define XD_DBUS_VALIDATE_MEMBER(member) \
348 if (!NILP (member)) CHECK_STRING (member);
349#endif
08686060 350
e936e76e 351/* Append to SIGNATURE a copy of X, making sure SIGNATURE does
2be7d702
PE
352 not become too long. */
353static void
ecfc0a49 354xd_signature_cat (char *signature, char const *x)
2be7d702
PE
355{
356 ptrdiff_t siglen = strlen (signature);
357 ptrdiff_t xlen = strlen (x);
358 if (DBUS_MAXIMUM_SIGNATURE_LENGTH - xlen <= siglen)
359 string_overflow ();
360 strcat (signature, x);
361}
362
87cf1a39
MA
363/* Compute SIGNATURE of OBJECT. It must have a form that it can be
364 used in dbus_message_iter_open_container. DTYPE is the DBusType
365 the object is related to. It is passed as argument, because it
366 cannot be detected in basic type objects, when they are preceded by
367 a type symbol. PARENT_TYPE is the DBusType of a container this
368 signature is embedded, or DBUS_TYPE_INVALID. It is needed for the
369 check that DBUS_TYPE_DICT_ENTRY occurs only as array element. */
78c38319 370static void
243e0530 371xd_signature (char *signature, int dtype, int parent_type, Lisp_Object object)
033b73e2 372{
243e0530 373 int subtype;
87cf1a39 374 Lisp_Object elt;
2ea16b89 375 char const *subsig;
8666506e 376 int subsiglen;
87cf1a39
MA
377 char x[DBUS_MAXIMUM_SIGNATURE_LENGTH];
378
379 elt = object;
033b73e2 380
033b73e2
MA
381 switch (dtype)
382 {
54371585
MA
383 case DBUS_TYPE_BYTE:
384 case DBUS_TYPE_UINT16:
54371585 385 CHECK_NATNUM (object);
87cf1a39 386 sprintf (signature, "%c", dtype);
54371585 387 break;
87cf1a39 388
54371585
MA
389 case DBUS_TYPE_BOOLEAN:
390 if (!EQ (object, Qt) && !EQ (object, Qnil))
391 wrong_type_argument (intern ("booleanp"), object);
87cf1a39 392 sprintf (signature, "%c", dtype);
54371585 393 break;
87cf1a39 394
54371585 395 case DBUS_TYPE_INT16:
54371585 396 CHECK_NUMBER (object);
87cf1a39 397 sprintf (signature, "%c", dtype);
54371585 398 break;
87cf1a39 399
dcbf5805
MA
400 case DBUS_TYPE_UINT32:
401 case DBUS_TYPE_UINT64:
402#ifdef DBUS_TYPE_UNIX_FD
403 case DBUS_TYPE_UNIX_FD:
404#endif
405 case DBUS_TYPE_INT32:
406 case DBUS_TYPE_INT64:
033b73e2 407 case DBUS_TYPE_DOUBLE:
dcbf5805 408 CHECK_NUMBER_OR_FLOAT (object);
87cf1a39 409 sprintf (signature, "%c", dtype);
54371585 410 break;
87cf1a39 411
033b73e2 412 case DBUS_TYPE_STRING:
54371585
MA
413 case DBUS_TYPE_OBJECT_PATH:
414 case DBUS_TYPE_SIGNATURE:
415 CHECK_STRING (object);
87cf1a39 416 sprintf (signature, "%c", dtype);
54371585 417 break;
87cf1a39 418
54371585 419 case DBUS_TYPE_ARRAY:
9af5078b 420 /* Check that all list elements have the same D-Bus type. For
87cf1a39
MA
421 complex element types, we just check the container type, not
422 the whole element's signature. */
54371585 423 CHECK_CONS (object);
87cf1a39 424
5125905e
MA
425 /* Type symbol is optional. */
426 if (EQ (QCdbus_type_array, CAR_SAFE (elt)))
87cf1a39 427 elt = XD_NEXT_VALUE (elt);
5125905e
MA
428
429 /* If the array is empty, DBUS_TYPE_STRING is the default
430 element type. */
431 if (NILP (elt))
432 {
433 subtype = DBUS_TYPE_STRING;
2ea16b89 434 subsig = DBUS_TYPE_STRING_AS_STRING;
5125905e
MA
435 }
436 else
437 {
438 subtype = XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (elt));
439 xd_signature (x, subtype, dtype, CAR_SAFE (XD_NEXT_VALUE (elt)));
2ea16b89 440 subsig = x;
5125905e
MA
441 }
442
443 /* If the element type is DBUS_TYPE_SIGNATURE, and this is the
dcbf5805
MA
444 only element, the value of this element is used as the
445 array's element signature. */
5125905e
MA
446 if ((subtype == DBUS_TYPE_SIGNATURE)
447 && STRINGP (CAR_SAFE (XD_NEXT_VALUE (elt)))
448 && NILP (CDR_SAFE (XD_NEXT_VALUE (elt))))
2ea16b89 449 subsig = SSDATA (CAR_SAFE (XD_NEXT_VALUE (elt)));
87cf1a39
MA
450
451 while (!NILP (elt))
452 {
5125905e
MA
453 if (subtype != XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (elt)))
454 wrong_type_argument (intern ("D-Bus"), CAR_SAFE (elt));
455 elt = CDR_SAFE (XD_NEXT_VALUE (elt));
87cf1a39
MA
456 }
457
8666506e
PE
458 subsiglen = snprintf (signature, DBUS_MAXIMUM_SIGNATURE_LENGTH,
459 "%c%s", dtype, subsig);
460 if (! (0 <= subsiglen && subsiglen < DBUS_MAXIMUM_SIGNATURE_LENGTH))
2ea16b89 461 string_overflow ();
54371585 462 break;
87cf1a39 463
54371585 464 case DBUS_TYPE_VARIANT:
9af5078b 465 /* Check that there is exactly one list element. */
54371585 466 CHECK_CONS (object);
87cf1a39
MA
467
468 elt = XD_NEXT_VALUE (elt);
5125905e
MA
469 subtype = XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (elt));
470 xd_signature (x, subtype, dtype, CAR_SAFE (XD_NEXT_VALUE (elt)));
87cf1a39 471
5125905e 472 if (!NILP (CDR_SAFE (XD_NEXT_VALUE (elt))))
87cf1a39 473 wrong_type_argument (intern ("D-Bus"),
5125905e 474 CAR_SAFE (CDR_SAFE (XD_NEXT_VALUE (elt))));
87cf1a39 475
a271e124 476 sprintf (signature, "%c", dtype);
54371585 477 break;
87cf1a39 478
54371585 479 case DBUS_TYPE_STRUCT:
9af5078b
MA
480 /* A struct list might contain any number of elements with
481 different types. No further check needed. */
87cf1a39
MA
482 CHECK_CONS (object);
483
484 elt = XD_NEXT_VALUE (elt);
485
486 /* Compose the signature from the elements. It is enclosed by
487 parentheses. */
488 sprintf (signature, "%c", DBUS_STRUCT_BEGIN_CHAR );
489 while (!NILP (elt))
490 {
5125905e
MA
491 subtype = XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (elt));
492 xd_signature (x, subtype, dtype, CAR_SAFE (XD_NEXT_VALUE (elt)));
ecfc0a49 493 xd_signature_cat (signature, x);
5125905e 494 elt = CDR_SAFE (XD_NEXT_VALUE (elt));
87cf1a39 495 }
ecfc0a49 496 xd_signature_cat (signature, DBUS_STRUCT_END_CHAR_AS_STRING);
54371585 497 break;
54371585 498
87cf1a39 499 case DBUS_TYPE_DICT_ENTRY:
9af5078b
MA
500 /* Check that there are exactly two list elements, and the first
501 one is of basic type. The dictionary entry itself must be an
502 element of an array. */
87cf1a39 503 CHECK_CONS (object);
54371585 504
9af5078b 505 /* Check the parent object type. */
87cf1a39
MA
506 if (parent_type != DBUS_TYPE_ARRAY)
507 wrong_type_argument (intern ("D-Bus"), object);
54371585 508
87cf1a39
MA
509 /* Compose the signature from the elements. It is enclosed by
510 curly braces. */
511 sprintf (signature, "%c", DBUS_DICT_ENTRY_BEGIN_CHAR);
54371585 512
87cf1a39
MA
513 /* First element. */
514 elt = XD_NEXT_VALUE (elt);
5125905e
MA
515 subtype = XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (elt));
516 xd_signature (x, subtype, dtype, CAR_SAFE (XD_NEXT_VALUE (elt)));
ecfc0a49 517 xd_signature_cat (signature, x);
54371585 518
87cf1a39 519 if (!XD_BASIC_DBUS_TYPE (subtype))
5125905e 520 wrong_type_argument (intern ("D-Bus"), CAR_SAFE (XD_NEXT_VALUE (elt)));
54371585 521
87cf1a39 522 /* Second element. */
5125905e
MA
523 elt = CDR_SAFE (XD_NEXT_VALUE (elt));
524 subtype = XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (elt));
525 xd_signature (x, subtype, dtype, CAR_SAFE (XD_NEXT_VALUE (elt)));
ecfc0a49 526 xd_signature_cat (signature, x);
54371585 527
5125905e 528 if (!NILP (CDR_SAFE (XD_NEXT_VALUE (elt))))
87cf1a39 529 wrong_type_argument (intern ("D-Bus"),
5125905e 530 CAR_SAFE (CDR_SAFE (XD_NEXT_VALUE (elt))));
54371585 531
87cf1a39 532 /* Closing signature. */
ecfc0a49 533 xd_signature_cat (signature, DBUS_DICT_ENTRY_END_CHAR_AS_STRING);
87cf1a39 534 break;
54371585 535
87cf1a39
MA
536 default:
537 wrong_type_argument (intern ("D-Bus"), object);
54371585
MA
538 }
539
87cf1a39
MA
540 XD_DEBUG_MESSAGE ("%s", signature);
541}
54371585 542
42b2a986
PE
543/* Convert X to a signed integer with bounds LO and HI. */
544static intmax_t
ff88beb8 545xd_extract_signed (Lisp_Object x, intmax_t lo, intmax_t hi)
42b2a986
PE
546{
547 CHECK_NUMBER_OR_FLOAT (x);
548 if (INTEGERP (x))
549 {
550 if (lo <= XINT (x) && XINT (x) <= hi)
551 return XINT (x);
552 }
553 else
554 {
555 double d = XFLOAT_DATA (x);
556 if (lo <= d && d <= hi)
557 {
558 intmax_t n = d;
559 if (n == d)
560 return n;
561 }
562 }
243e0530
PE
563 if (xd_in_read_queued_messages)
564 Fthrow (Qdbus_error, Qnil);
565 else
566 args_out_of_range_3 (x,
567 make_fixnum_or_float (lo),
568 make_fixnum_or_float (hi));
42b2a986
PE
569}
570
571/* Convert X to an unsigned integer with bounds 0 and HI. */
572static uintmax_t
ff88beb8 573xd_extract_unsigned (Lisp_Object x, uintmax_t hi)
42b2a986
PE
574{
575 CHECK_NUMBER_OR_FLOAT (x);
576 if (INTEGERP (x))
577 {
578 if (0 <= XINT (x) && XINT (x) <= hi)
579 return XINT (x);
580 }
581 else
582 {
583 double d = XFLOAT_DATA (x);
584 if (0 <= d && d <= hi)
585 {
586 uintmax_t n = d;
587 if (n == d)
588 return n;
589 }
590 }
243e0530
PE
591 if (xd_in_read_queued_messages)
592 Fthrow (Qdbus_error, Qnil);
593 else
594 args_out_of_range_3 (x, make_number (0), make_fixnum_or_float (hi));
42b2a986
PE
595}
596
87cf1a39
MA
597/* Append C value, extracted from Lisp OBJECT, to iteration ITER.
598 DTYPE must be a valid DBusType. It is used to convert Lisp
599 objects, being arguments of `dbus-call-method' or
600 `dbus-send-signal', into corresponding C values appended as
601 arguments to a D-Bus message. */
78c38319 602static void
243e0530 603xd_append_arg (int dtype, Lisp_Object object, DBusMessageIter *iter)
87cf1a39 604{
87cf1a39
MA
605 char signature[DBUS_MAXIMUM_SIGNATURE_LENGTH];
606 DBusMessageIter subiter;
87cf1a39
MA
607
608 if (XD_BASIC_DBUS_TYPE (dtype))
17bc8f94
MA
609 switch (dtype)
610 {
611 case DBUS_TYPE_BYTE:
2d1fc3c7 612 CHECK_NATNUM (object);
54371585 613 {
2d1fc3c7 614 unsigned char val = XFASTINT (object) & 0xFF;
3478ec45 615 XD_DEBUG_MESSAGE ("%c %u", dtype, val);
17bc8f94 616 if (!dbus_message_iter_append_basic (iter, dtype, &val))
1dae9197 617 XD_SIGNAL2 (build_string ("Unable to append argument"), object);
17bc8f94
MA
618 return;
619 }
87cf1a39 620
17bc8f94
MA
621 case DBUS_TYPE_BOOLEAN:
622 {
623 dbus_bool_t val = (NILP (object)) ? FALSE : TRUE;
624 XD_DEBUG_MESSAGE ("%c %s", dtype, (val == FALSE) ? "false" : "true");
625 if (!dbus_message_iter_append_basic (iter, dtype, &val))
1dae9197 626 XD_SIGNAL2 (build_string ("Unable to append argument"), object);
17bc8f94
MA
627 return;
628 }
87cf1a39 629
17bc8f94
MA
630 case DBUS_TYPE_INT16:
631 {
ff88beb8
MA
632 dbus_int16_t val =
633 xd_extract_signed (object,
634 TYPE_MINIMUM (dbus_int16_t),
635 TYPE_MAXIMUM (dbus_int16_t));
3478ec45
PE
636 int pval = val;
637 XD_DEBUG_MESSAGE ("%c %d", dtype, pval);
17bc8f94 638 if (!dbus_message_iter_append_basic (iter, dtype, &val))
1dae9197 639 XD_SIGNAL2 (build_string ("Unable to append argument"), object);
17bc8f94
MA
640 return;
641 }
87cf1a39 642
17bc8f94
MA
643 case DBUS_TYPE_UINT16:
644 {
ff88beb8
MA
645 dbus_uint16_t val =
646 xd_extract_unsigned (object,
647 TYPE_MAXIMUM (dbus_uint16_t));
3478ec45
PE
648 unsigned int pval = val;
649 XD_DEBUG_MESSAGE ("%c %u", dtype, pval);
17bc8f94 650 if (!dbus_message_iter_append_basic (iter, dtype, &val))
1dae9197 651 XD_SIGNAL2 (build_string ("Unable to append argument"), object);
17bc8f94
MA
652 return;
653 }
87cf1a39 654
17bc8f94
MA
655 case DBUS_TYPE_INT32:
656 {
ff88beb8
MA
657 dbus_int32_t val =
658 xd_extract_signed (object,
659 TYPE_MINIMUM (dbus_int32_t),
660 TYPE_MAXIMUM (dbus_int32_t));
3478ec45
PE
661 int pval = val;
662 XD_DEBUG_MESSAGE ("%c %d", dtype, pval);
17bc8f94 663 if (!dbus_message_iter_append_basic (iter, dtype, &val))
1dae9197 664 XD_SIGNAL2 (build_string ("Unable to append argument"), object);
17bc8f94
MA
665 return;
666 }
87cf1a39 667
17bc8f94 668 case DBUS_TYPE_UINT32:
da1fec2b
MA
669#ifdef DBUS_TYPE_UNIX_FD
670 case DBUS_TYPE_UNIX_FD:
671#endif
17bc8f94 672 {
ff88beb8
MA
673 dbus_uint32_t val =
674 xd_extract_unsigned (object,
675 TYPE_MAXIMUM (dbus_uint32_t));
3478ec45
PE
676 unsigned int pval = val;
677 XD_DEBUG_MESSAGE ("%c %u", dtype, pval);
17bc8f94 678 if (!dbus_message_iter_append_basic (iter, dtype, &val))
1dae9197 679 XD_SIGNAL2 (build_string ("Unable to append argument"), object);
17bc8f94
MA
680 return;
681 }
87cf1a39 682
17bc8f94
MA
683 case DBUS_TYPE_INT64:
684 {
ff88beb8
MA
685 dbus_int64_t val =
686 xd_extract_signed (object,
687 TYPE_MINIMUM (dbus_int64_t),
688 TYPE_MAXIMUM (dbus_int64_t));
3478ec45
PE
689 printmax_t pval = val;
690 XD_DEBUG_MESSAGE ("%c %"pMd, dtype, pval);
17bc8f94 691 if (!dbus_message_iter_append_basic (iter, dtype, &val))
1dae9197 692 XD_SIGNAL2 (build_string ("Unable to append argument"), object);
17bc8f94
MA
693 return;
694 }
87cf1a39 695
17bc8f94
MA
696 case DBUS_TYPE_UINT64:
697 {
ff88beb8
MA
698 dbus_uint64_t val =
699 xd_extract_unsigned (object,
700 TYPE_MAXIMUM (dbus_uint64_t));
3478ec45
PE
701 uprintmax_t pval = val;
702 XD_DEBUG_MESSAGE ("%c %"pMu, dtype, pval);
17bc8f94 703 if (!dbus_message_iter_append_basic (iter, dtype, &val))
1dae9197 704 XD_SIGNAL2 (build_string ("Unable to append argument"), object);
17bc8f94 705 return;
54371585 706 }
87cf1a39 707
17bc8f94 708 case DBUS_TYPE_DOUBLE:
f601cdf3 709 {
dcbf5805 710 double val = extract_float (object);
f601cdf3
KR
711 XD_DEBUG_MESSAGE ("%c %f", dtype, val);
712 if (!dbus_message_iter_append_basic (iter, dtype, &val))
713 XD_SIGNAL2 (build_string ("Unable to append argument"), object);
714 return;
715 }
17bc8f94
MA
716
717 case DBUS_TYPE_STRING:
718 case DBUS_TYPE_OBJECT_PATH:
719 case DBUS_TYPE_SIGNATURE:
e454a4a3 720 CHECK_STRING (object);
17bc8f94 721 {
e454a4a3
SM
722 /* We need to send a valid UTF-8 string. We could encode `object'
723 but by not encoding it, we guarantee it's valid utf-8, even if
724 it contains eight-bit-bytes. Of course, you can still send
725 manually-crafted junk by passing a unibyte string. */
59d6fe83 726 char *val = SSDATA (object);
17bc8f94
MA
727 XD_DEBUG_MESSAGE ("%c %s", dtype, val);
728 if (!dbus_message_iter_append_basic (iter, dtype, &val))
1dae9197 729 XD_SIGNAL2 (build_string ("Unable to append argument"), object);
17bc8f94
MA
730 return;
731 }
732 }
87cf1a39
MA
733
734 else /* Compound types. */
735 {
736
737 /* All compound types except array have a type symbol. For
738 array, it is optional. Skip it. */
5125905e 739 if (!XD_BASIC_DBUS_TYPE (XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (object))))
87cf1a39
MA
740 object = XD_NEXT_VALUE (object);
741
742 /* Open new subiteration. */
743 switch (dtype)
744 {
745 case DBUS_TYPE_ARRAY:
5125905e
MA
746 /* An array has only elements of the same type. So it is
747 sufficient to check the first element's signature
748 only. */
749
750 if (NILP (object))
751 /* If the array is empty, DBUS_TYPE_STRING is the default
752 element type. */
753 strcpy (signature, DBUS_TYPE_STRING_AS_STRING);
754
755 else
756 /* If the element type is DBUS_TYPE_SIGNATURE, and this is
757 the only element, the value of this element is used as
758 the array's element signature. */
759 if ((XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (object))
760 == DBUS_TYPE_SIGNATURE)
761 && STRINGP (CAR_SAFE (XD_NEXT_VALUE (object)))
762 && NILP (CDR_SAFE (XD_NEXT_VALUE (object))))
763 {
59d6fe83 764 strcpy (signature, SSDATA (CAR_SAFE (XD_NEXT_VALUE (object))));
5125905e
MA
765 object = CDR_SAFE (XD_NEXT_VALUE (object));
766 }
767
768 else
769 xd_signature (signature,
770 XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (object)),
771 dtype, CAR_SAFE (XD_NEXT_VALUE (object)));
772
773 XD_DEBUG_MESSAGE ("%c %s %s", dtype, signature,
dcbf5805 774 XD_OBJECT_TO_STRING (object));
5125905e
MA
775 if (!dbus_message_iter_open_container (iter, dtype,
776 signature, &subiter))
1dae9197
MA
777 XD_SIGNAL3 (build_string ("Cannot open container"),
778 make_number (dtype), build_string (signature));
5125905e
MA
779 break;
780
87cf1a39 781 case DBUS_TYPE_VARIANT:
5125905e
MA
782 /* A variant has just one element. */
783 xd_signature (signature, XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (object)),
784 dtype, CAR_SAFE (XD_NEXT_VALUE (object)));
785
87cf1a39 786 XD_DEBUG_MESSAGE ("%c %s %s", dtype, signature,
dcbf5805 787 XD_OBJECT_TO_STRING (object));
87cf1a39
MA
788 if (!dbus_message_iter_open_container (iter, dtype,
789 signature, &subiter))
1dae9197
MA
790 XD_SIGNAL3 (build_string ("Cannot open container"),
791 make_number (dtype), build_string (signature));
87cf1a39
MA
792 break;
793
794 case DBUS_TYPE_STRUCT:
795 case DBUS_TYPE_DICT_ENTRY:
9af5078b 796 /* These containers do not require a signature. */
dcbf5805 797 XD_DEBUG_MESSAGE ("%c %s", dtype, XD_OBJECT_TO_STRING (object));
87cf1a39 798 if (!dbus_message_iter_open_container (iter, dtype, NULL, &subiter))
1dae9197
MA
799 XD_SIGNAL2 (build_string ("Cannot open container"),
800 make_number (dtype));
87cf1a39
MA
801 break;
802 }
803
804 /* Loop over list elements. */
805 while (!NILP (object))
806 {
5125905e 807 dtype = XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (object));
87cf1a39
MA
808 object = XD_NEXT_VALUE (object);
809
5125905e 810 xd_append_arg (dtype, CAR_SAFE (object), &subiter);
87cf1a39 811
5125905e 812 object = CDR_SAFE (object);
87cf1a39
MA
813 }
814
9af5078b 815 /* Close the subiteration. */
87cf1a39 816 if (!dbus_message_iter_close_container (iter, &subiter))
1dae9197
MA
817 XD_SIGNAL2 (build_string ("Cannot close container"),
818 make_number (dtype));
87cf1a39 819 }
033b73e2
MA
820}
821
822/* Retrieve C value from a DBusMessageIter structure ITER, and return
823 a converted Lisp object. The type DTYPE of the argument of the
9af5078b
MA
824 D-Bus message must be a valid DBusType. Compound D-Bus types
825 result always in a Lisp list. */
78c38319 826static Lisp_Object
243e0530 827xd_retrieve_arg (int dtype, DBusMessageIter *iter)
033b73e2
MA
828{
829
830 switch (dtype)
831 {
9af5078b 832 case DBUS_TYPE_BYTE:
9af5078b 833 {
17bc8f94 834 unsigned int val;
9af5078b 835 dbus_message_iter_get_basic (iter, &val);
17bc8f94 836 val = val & 0xFF;
3478ec45 837 XD_DEBUG_MESSAGE ("%c %u", dtype, val);
9af5078b
MA
838 return make_number (val);
839 }
840
033b73e2
MA
841 case DBUS_TYPE_BOOLEAN:
842 {
843 dbus_bool_t val;
844 dbus_message_iter_get_basic (iter, &val);
87cf1a39 845 XD_DEBUG_MESSAGE ("%c %s", dtype, (val == FALSE) ? "false" : "true");
033b73e2
MA
846 return (val == FALSE) ? Qnil : Qt;
847 }
87cf1a39 848
17bc8f94 849 case DBUS_TYPE_INT16:
1cae01f7
AS
850 {
851 dbus_int16_t val;
3478ec45 852 int pval;
1cae01f7 853 dbus_message_iter_get_basic (iter, &val);
3478ec45
PE
854 pval = val;
855 XD_DEBUG_MESSAGE ("%c %d", dtype, pval);
1cae01f7
AS
856 return make_number (val);
857 }
858
17bc8f94
MA
859 case DBUS_TYPE_UINT16:
860 {
861 dbus_uint16_t val;
3478ec45 862 int pval;
17bc8f94 863 dbus_message_iter_get_basic (iter, &val);
3478ec45
PE
864 pval = val;
865 XD_DEBUG_MESSAGE ("%c %d", dtype, pval);
17bc8f94
MA
866 return make_number (val);
867 }
868
033b73e2 869 case DBUS_TYPE_INT32:
1cae01f7
AS
870 {
871 dbus_int32_t val;
3478ec45 872 int pval;
1cae01f7 873 dbus_message_iter_get_basic (iter, &val);
3478ec45
PE
874 pval = val;
875 XD_DEBUG_MESSAGE ("%c %d", dtype, pval);
1cae01f7
AS
876 return make_fixnum_or_float (val);
877 }
878
033b73e2 879 case DBUS_TYPE_UINT32:
da1fec2b
MA
880#ifdef DBUS_TYPE_UNIX_FD
881 case DBUS_TYPE_UNIX_FD:
882#endif
033b73e2
MA
883 {
884 dbus_uint32_t val;
31ff141c 885 unsigned int pval;
033b73e2 886 dbus_message_iter_get_basic (iter, &val);
3478ec45
PE
887 pval = val;
888 XD_DEBUG_MESSAGE ("%c %u", dtype, pval);
1cae01f7 889 return make_fixnum_or_float (val);
9af5078b
MA
890 }
891
892 case DBUS_TYPE_INT64:
1cae01f7
AS
893 {
894 dbus_int64_t val;
3478ec45 895 printmax_t pval;
1cae01f7 896 dbus_message_iter_get_basic (iter, &val);
3478ec45
PE
897 pval = val;
898 XD_DEBUG_MESSAGE ("%c %"pMd, dtype, pval);
1cae01f7
AS
899 return make_fixnum_or_float (val);
900 }
901
9af5078b
MA
902 case DBUS_TYPE_UINT64:
903 {
904 dbus_uint64_t val;
3478ec45 905 uprintmax_t pval;
9af5078b 906 dbus_message_iter_get_basic (iter, &val);
3478ec45
PE
907 pval = val;
908 XD_DEBUG_MESSAGE ("%c %"pMd, dtype, pval);
9af5078b
MA
909 return make_fixnum_or_float (val);
910 }
911
912 case DBUS_TYPE_DOUBLE:
913 {
914 double val;
915 dbus_message_iter_get_basic (iter, &val);
916 XD_DEBUG_MESSAGE ("%c %f", dtype, val);
917 return make_float (val);
033b73e2 918 }
87cf1a39 919
033b73e2
MA
920 case DBUS_TYPE_STRING:
921 case DBUS_TYPE_OBJECT_PATH:
9af5078b 922 case DBUS_TYPE_SIGNATURE:
033b73e2
MA
923 {
924 char *val;
925 dbus_message_iter_get_basic (iter, &val);
87cf1a39 926 XD_DEBUG_MESSAGE ("%c %s", dtype, val);
033b73e2
MA
927 return build_string (val);
928 }
87cf1a39 929
033b73e2
MA
930 case DBUS_TYPE_ARRAY:
931 case DBUS_TYPE_VARIANT:
932 case DBUS_TYPE_STRUCT:
933 case DBUS_TYPE_DICT_ENTRY:
934 {
935 Lisp_Object result;
936 struct gcpro gcpro1;
033b73e2
MA
937 DBusMessageIter subiter;
938 int subtype;
fa8e045a
MA
939 result = Qnil;
940 GCPRO1 (result);
033b73e2
MA
941 dbus_message_iter_recurse (iter, &subiter);
942 while ((subtype = dbus_message_iter_get_arg_type (&subiter))
943 != DBUS_TYPE_INVALID)
944 {
945 result = Fcons (xd_retrieve_arg (subtype, &subiter), result);
946 dbus_message_iter_next (&subiter);
947 }
dcbf5805 948 XD_DEBUG_MESSAGE ("%c %s", dtype, XD_OBJECT_TO_STRING (result));
033b73e2
MA
949 RETURN_UNGCPRO (Fnreverse (result));
950 }
87cf1a39 951
033b73e2 952 default:
87cf1a39 953 XD_DEBUG_MESSAGE ("DBusType '%c' not supported", dtype);
033b73e2
MA
954 return Qnil;
955 }
956}
957
dcbf5805 958/* Return the number of references of the shared CONNECTION. */
243e0530 959static ptrdiff_t
dcbf5805
MA
960xd_get_connection_references (DBusConnection *connection)
961{
962 ptrdiff_t *refcount;
de85e130 963
dcbf5805
MA
964 /* We cannot access the DBusConnection structure, it is not public.
965 But we know, that the reference counter is the first field in
966 that structure. */
967 refcount = (void *) &connection;
968 refcount = (void *) *refcount;
969 return *refcount;
970}
971
972/* Return D-Bus connection address. BUS is either a Lisp symbol,
973 :system or :session, or a string denoting the bus address. */
78c38319 974static DBusConnection *
dcbf5805 975xd_get_connection_address (Lisp_Object bus)
033b73e2
MA
976{
977 DBusConnection *connection;
dcbf5805 978 Lisp_Object val;
033b73e2 979
5cb67954 980 val = CDR_SAFE (Fassoc (bus, xd_registered_buses));
dcbf5805
MA
981 if (NILP (val))
982 XD_SIGNAL2 (build_string ("No connection to bus"), bus);
033b73e2 983 else
3478ec45 984 connection = (DBusConnection *) (intptr_t) XFASTINT (val);
033b73e2 985
dcbf5805 986 if (!dbus_connection_get_is_connected (connection))
3f56d3c6 987 XD_SIGNAL2 (build_string ("No connection to bus"), bus);
033b73e2 988
033b73e2
MA
989 return connection;
990}
991
3fad2ad2 992/* Return the file descriptor for WATCH, -1 if not found. */
3fad2ad2
J
993static int
994xd_find_watch_fd (DBusWatch *watch)
058ed861 995{
eb4c6ace 996#if HAVE_DBUS_WATCH_GET_UNIX_FD
b46a6a83 997 /* TODO: Reverse these on w32, which prefers the opposite. */
3fad2ad2
J
998 int fd = dbus_watch_get_unix_fd (watch);
999 if (fd == -1)
1000 fd = dbus_watch_get_socket (watch);
3f56d3c6 1001#else
3fad2ad2 1002 int fd = dbus_watch_get_fd (watch);
3f56d3c6 1003#endif
3fad2ad2
J
1004 return fd;
1005}
3f56d3c6 1006
08609ffd 1007/* Prototype. */
de1339b0 1008static void xd_read_queued_messages (int fd, void *data);
058ed861 1009
3fad2ad2 1010/* Start monitoring WATCH for possible I/O. */
3fad2ad2
J
1011static dbus_bool_t
1012xd_add_watch (DBusWatch *watch, void *data)
1013{
1014 unsigned int flags = dbus_watch_get_flags (watch);
1015 int fd = xd_find_watch_fd (watch);
1016
1017 XD_DEBUG_MESSAGE ("fd %d, write %d, enabled %d",
dcbf5805
MA
1018 fd, flags & DBUS_WATCH_WRITABLE,
1019 dbus_watch_get_enabled (watch));
3fad2ad2
J
1020
1021 if (fd == -1)
1022 return FALSE;
1023
1024 if (dbus_watch_get_enabled (watch))
1025 {
1026 if (flags & DBUS_WATCH_WRITABLE)
08609ffd 1027 add_write_fd (fd, xd_read_queued_messages, data);
3fad2ad2 1028 if (flags & DBUS_WATCH_READABLE)
08609ffd 1029 add_read_fd (fd, xd_read_queued_messages, data);
3fad2ad2 1030 }
058ed861
MA
1031 return TRUE;
1032}
1033
3fad2ad2
J
1034/* Stop monitoring WATCH for possible I/O.
1035 DATA is the used bus, either a string or QCdbus_system_bus or
0c372655 1036 QCdbus_session_bus. */
3fad2ad2 1037static void
971de7fb 1038xd_remove_watch (DBusWatch *watch, void *data)
058ed861 1039{
3fad2ad2
J
1040 unsigned int flags = dbus_watch_get_flags (watch);
1041 int fd = xd_find_watch_fd (watch);
3f56d3c6 1042
3fad2ad2
J
1043 XD_DEBUG_MESSAGE ("fd %d", fd);
1044
08609ffd
MA
1045 if (fd == -1)
1046 return;
777013f2 1047
3fad2ad2 1048 /* Unset session environment. */
9b994fed 1049#if 0
b4289b64 1050 if (XSYMBOL (QCdbus_session_bus) == data)
3fad2ad2 1051 {
9b994fed
PE
1052 XD_DEBUG_MESSAGE ("unsetenv DBUS_SESSION_BUS_ADDRESS");
1053 unsetenv ("DBUS_SESSION_BUS_ADDRESS");
058ed861 1054 }
9b994fed 1055#endif
058ed861 1056
3fad2ad2
J
1057 if (flags & DBUS_WATCH_WRITABLE)
1058 delete_write_fd (fd);
1059 if (flags & DBUS_WATCH_READABLE)
1060 delete_read_fd (fd);
1061}
1062
1063/* Toggle monitoring WATCH for possible I/O. */
3fad2ad2
J
1064static void
1065xd_toggle_watch (DBusWatch *watch, void *data)
1066{
1067 if (dbus_watch_get_enabled (watch))
1068 xd_add_watch (watch, data);
1069 else
1070 xd_remove_watch (watch, data);
058ed861
MA
1071}
1072
dcbf5805
MA
1073/* Close connection to D-Bus BUS. */
1074static void
1075xd_close_bus (Lisp_Object bus)
1076{
1077 DBusConnection *connection;
1078 Lisp_Object val;
1079
1080 /* Check whether we are connected. */
5cb67954 1081 val = Fassoc (bus, xd_registered_buses);
dcbf5805
MA
1082 if (NILP (val))
1083 return;
1084
1085 /* Retrieve bus address. */
1086 connection = xd_get_connection_address (bus);
1087
dcbf5805
MA
1088 if (xd_get_connection_references (connection) == 1)
1089 {
e518bc71 1090 /* Close connection, if there isn't another shared application. */
dcbf5805
MA
1091 XD_DEBUG_MESSAGE ("Close connection to bus %s",
1092 XD_OBJECT_TO_STRING (bus));
1093 dbus_connection_close (connection);
dcbf5805 1094
e518bc71
MA
1095 xd_registered_buses = Fdelete (val, xd_registered_buses);
1096 }
dcbf5805 1097
e518bc71
MA
1098 else
1099 /* Decrement reference count. */
1100 dbus_connection_unref (connection);
dcbf5805
MA
1101
1102 /* Return. */
1103 return;
1104}
1105
1106DEFUN ("dbus-init-bus", Fdbus_init_bus, Sdbus_init_bus, 1, 2, 0,
1107 doc: /* Establish the connection to D-Bus BUS.
1108
1109BUS can be either the symbol `:system' or the symbol `:session', or it
1110can be a string denoting the address of the corresponding bus. For
1111the system and session buses, this function is called when loading
1112`dbus.el', there is no need to call it again.
1113
1114The function returns a number, which counts the connections this Emacs
1115session has established to the BUS under the same unique name (see
1116`dbus-get-unique-name'). It depends on the libraries Emacs is linked
1117with, and on the environment Emacs is running. For example, if Emacs
1118is linked with the gtk toolkit, and it runs in a GTK-aware environment
1119like Gnome, another connection might already be established.
1120
1121When PRIVATE is non-nil, a new connection is established instead of
1122reusing an existing one. It results in a new unique name at the bus.
1123This can be used, if it is necessary to distinguish from another
1124connection used in the same Emacs process, like the one established by
1125GTK+. It should be used with care for at least the `:system' and
1126`:session' buses, because other Emacs Lisp packages might already use
1127this connection to those buses. */)
1128 (Lisp_Object bus, Lisp_Object private)
058ed861
MA
1129{
1130 DBusConnection *connection;
dcbf5805
MA
1131 DBusError derror;
1132 Lisp_Object val;
243e0530 1133 ptrdiff_t refcount;
058ed861 1134
b4289b64 1135 /* Check parameter. */
dcbf5805
MA
1136 XD_DBUS_VALIDATE_BUS_ADDRESS (bus);
1137
1138 /* Close bus if it is already open. */
1139 xd_close_bus (bus);
1140
e518bc71
MA
1141 /* Check, whether we are still connected. */
1142 val = Fassoc (bus, xd_registered_buses);
1143 if (!NILP (val))
1144 {
1145 connection = xd_get_connection_address (bus);
1146 dbus_connection_ref (connection);
1147 }
dcbf5805
MA
1148
1149 else
e518bc71
MA
1150 {
1151 /* Initialize. */
1152 dbus_error_init (&derror);
dcbf5805 1153
e518bc71
MA
1154 /* Open the connection. */
1155 if (STRINGP (bus))
1156 if (NILP (private))
1157 connection = dbus_connection_open (SSDATA (bus), &derror);
1158 else
1159 connection = dbus_connection_open_private (SSDATA (bus), &derror);
1160
1161 else
1162 if (NILP (private))
1163 connection = dbus_bus_get (EQ (bus, QCdbus_system_bus)
1164 ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION,
1165 &derror);
1166 else
1167 connection = dbus_bus_get_private (EQ (bus, QCdbus_system_bus)
1168 ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION,
1169 &derror);
1170
1171 if (dbus_error_is_set (&derror))
1172 XD_ERROR (derror);
1173
1174 if (connection == NULL)
1175 XD_SIGNAL2 (build_string ("No connection to bus"), bus);
1176
1177 /* If it is not the system or session bus, we must register
1178 ourselves. Otherwise, we have called dbus_bus_get, which has
1179 configured us to exit if the connection closes - we undo this
1180 setting. */
1181 if (STRINGP (bus))
1182 dbus_bus_register (connection, &derror);
1183 else
1184 dbus_connection_set_exit_on_disconnect (connection, FALSE);
1185
1186 if (dbus_error_is_set (&derror))
1187 XD_ERROR (derror);
1188
1189 /* Add the watch functions. We pass also the bus as data, in
1190 order to distinguish between the buses in xd_remove_watch. */
1191 if (!dbus_connection_set_watch_functions (connection,
1192 xd_add_watch,
1193 xd_remove_watch,
1194 xd_toggle_watch,
1195 SYMBOLP (bus)
1196 ? (void *) XSYMBOL (bus)
1197 : (void *) XSTRING (bus),
1198 NULL))
1199 XD_SIGNAL1 (build_string ("Cannot add watch functions"));
1200
1201 /* Add bus to list of registered buses. */
1202 XSETFASTINT (val, (intptr_t) connection);
1203 xd_registered_buses = Fcons (Fcons (bus, val), xd_registered_buses);
1204
1205 /* We do not want to abort. */
5745a7df 1206 xputenv ("DBUS_FATAL_WARNINGS=0");
e518bc71
MA
1207
1208 /* Cleanup. */
1209 dbus_error_free (&derror);
1210 }
0c372655 1211
dcbf5805
MA
1212 /* Return reference counter. */
1213 refcount = xd_get_connection_references (connection);
243e0530 1214 XD_DEBUG_MESSAGE ("Bus %s, Reference counter %"pD"d",
dcbf5805
MA
1215 XD_OBJECT_TO_STRING (bus), refcount);
1216 return make_number (refcount);
058ed861
MA
1217}
1218
033b73e2
MA
1219DEFUN ("dbus-get-unique-name", Fdbus_get_unique_name, Sdbus_get_unique_name,
1220 1, 1, 0,
5125905e 1221 doc: /* Return the unique name of Emacs registered at D-Bus BUS. */)
5842a27b 1222 (Lisp_Object bus)
033b73e2
MA
1223{
1224 DBusConnection *connection;
48f7d213 1225 const char *name;
033b73e2 1226
dcbf5805
MA
1227 /* Check parameter. */
1228 XD_DBUS_VALIDATE_BUS_ADDRESS (bus);
1229
1230 /* Retrieve bus address. */
1231 connection = xd_get_connection_address (bus);
033b73e2
MA
1232
1233 /* Request the name. */
48f7d213 1234 name = dbus_bus_get_unique_name (connection);
033b73e2 1235 if (name == NULL)
1dae9197 1236 XD_SIGNAL1 (build_string ("No unique name available"));
033b73e2
MA
1237
1238 /* Return. */
1239 return build_string (name);
1240}
1241
dcbf5805
MA
1242DEFUN ("dbus-message-internal", Fdbus_message_internal, Sdbus_message_internal,
1243 4, MANY, 0,
1244 doc: /* Send a D-Bus message.
1245This is an internal function, it shall not be used outside dbus.el.
1246
1247The following usages are expected:
1248
1249`dbus-call-method', `dbus-call-method-asynchronously':
1250 \(dbus-message-internal
1251 dbus-message-type-method-call BUS SERVICE PATH INTERFACE METHOD HANDLER
1252 &optional :timeout TIMEOUT &rest ARGS)
1253
1254`dbus-send-signal':
1255 \(dbus-message-internal
1256 dbus-message-type-signal BUS SERVICE PATH INTERFACE SIGNAL &rest ARGS)
1257
1258`dbus-method-return-internal':
1259 \(dbus-message-internal
1260 dbus-message-type-method-return BUS SERVICE SERIAL &rest ARGS)
1261
1262`dbus-method-error-internal':
1263 \(dbus-message-internal
1264 dbus-message-type-error BUS SERVICE SERIAL &rest ARGS)
1265
1266usage: (dbus-message-internal &rest REST) */)
f66c7cf8 1267 (ptrdiff_t nargs, Lisp_Object *args)
033b73e2 1268{
dcbf5805
MA
1269 Lisp_Object message_type, bus, service, handler;
1270 Lisp_Object path = Qnil;
1271 Lisp_Object interface = Qnil;
1272 Lisp_Object member = Qnil;
033b73e2 1273 Lisp_Object result;
dcbf5805 1274 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6;
033b73e2
MA
1275 DBusConnection *connection;
1276 DBusMessage *dmessage;
033b73e2 1277 DBusMessageIter iter;
243e0530
PE
1278 int dtype;
1279 int mtype;
dcbf5805 1280 dbus_uint32_t serial = 0;
3478ec45 1281 unsigned int ui_serial;
90b3fc84 1282 int timeout = -1;
dcbf5805 1283 ptrdiff_t count;
87cf1a39 1284 char signature[DBUS_MAXIMUM_SIGNATURE_LENGTH];
033b73e2 1285
dcbf5805
MA
1286 /* Initialize parameters. */
1287 message_type = args[0];
1288 bus = args[1];
1289 service = args[2];
1290 handler = Qnil;
1291
1292 CHECK_NATNUM (message_type);
243e0530
PE
1293 if (! (DBUS_MESSAGE_TYPE_INVALID < XFASTINT (message_type)
1294 && XFASTINT (message_type) < DBUS_NUM_MESSAGE_TYPES))
dcbf5805 1295 XD_SIGNAL2 (build_string ("Invalid message type"), message_type);
243e0530 1296 mtype = XFASTINT (message_type);
dcbf5805
MA
1297
1298 if ((mtype == DBUS_MESSAGE_TYPE_METHOD_CALL)
1299 || (mtype == DBUS_MESSAGE_TYPE_SIGNAL))
1300 {
1301 path = args[3];
1302 interface = args[4];
1303 member = args[5];
1304 if (mtype == DBUS_MESSAGE_TYPE_METHOD_CALL)
1305 handler = args[6];
1306 count = (mtype == DBUS_MESSAGE_TYPE_METHOD_CALL) ? 7 : 6;
1307 }
1308 else /* DBUS_MESSAGE_TYPE_METHOD_RETURN, DBUS_MESSAGE_TYPE_ERROR */
1309 {
ff88beb8 1310 serial = xd_extract_unsigned (args[3], TYPE_MAXIMUM (dbus_uint32_t));
dcbf5805
MA
1311 count = 4;
1312 }
1313
033b73e2 1314 /* Check parameters. */
dcbf5805
MA
1315 XD_DBUS_VALIDATE_BUS_ADDRESS (bus);
1316 XD_DBUS_VALIDATE_BUS_NAME (service);
1317 if (nargs < count)
1318 xsignal2 (Qwrong_number_of_arguments,
1319 Qdbus_message_internal,
1320 make_number (nargs));
1321
1322 if ((mtype == DBUS_MESSAGE_TYPE_METHOD_CALL)
1323 || (mtype == DBUS_MESSAGE_TYPE_SIGNAL))
1324 {
1325 XD_DBUS_VALIDATE_PATH (path);
1326 XD_DBUS_VALIDATE_INTERFACE (interface);
1327 XD_DBUS_VALIDATE_MEMBER (member);
1328 if (!NILP (handler) && (!FUNCTIONP (handler)))
1329 wrong_type_argument (Qinvalid_function, handler);
1330 }
90b3fc84 1331
dcbf5805
MA
1332 /* Protect Lisp variables. */
1333 GCPRO6 (bus, service, path, interface, member, handler);
1334
1335 /* Trace parameters. */
1336 switch (mtype)
033b73e2 1337 {
dcbf5805
MA
1338 case DBUS_MESSAGE_TYPE_METHOD_CALL:
1339 XD_DEBUG_MESSAGE ("%s %s %s %s %s %s %s",
1340 XD_MESSAGE_TYPE_TO_STRING (mtype),
1341 XD_OBJECT_TO_STRING (bus),
1342 XD_OBJECT_TO_STRING (service),
1343 XD_OBJECT_TO_STRING (path),
1344 XD_OBJECT_TO_STRING (interface),
1345 XD_OBJECT_TO_STRING (member),
1346 XD_OBJECT_TO_STRING (handler));
1347 break;
1348 case DBUS_MESSAGE_TYPE_SIGNAL:
1349 XD_DEBUG_MESSAGE ("%s %s %s %s %s %s",
1350 XD_MESSAGE_TYPE_TO_STRING (mtype),
1351 XD_OBJECT_TO_STRING (bus),
1352 XD_OBJECT_TO_STRING (service),
1353 XD_OBJECT_TO_STRING (path),
1354 XD_OBJECT_TO_STRING (interface),
1355 XD_OBJECT_TO_STRING (member));
1356 break;
1357 default: /* DBUS_MESSAGE_TYPE_METHOD_RETURN, DBUS_MESSAGE_TYPE_ERROR */
3478ec45 1358 ui_serial = serial;
dcbf5805
MA
1359 XD_DEBUG_MESSAGE ("%s %s %s %u",
1360 XD_MESSAGE_TYPE_TO_STRING (mtype),
1361 XD_OBJECT_TO_STRING (bus),
1362 XD_OBJECT_TO_STRING (service),
3478ec45 1363 ui_serial);
033b73e2
MA
1364 }
1365
dcbf5805
MA
1366 /* Retrieve bus address. */
1367 connection = xd_get_connection_address (bus);
54371585 1368
dcbf5805
MA
1369 /* Create the D-Bus message. */
1370 dmessage = dbus_message_new (mtype);
033b73e2 1371 if (dmessage == NULL)
dcbf5805
MA
1372 {
1373 UNGCPRO;
1374 XD_SIGNAL1 (build_string ("Unable to create a new message"));
1375 }
1376
1377 if (STRINGP (service))
033b73e2 1378 {
dcbf5805
MA
1379 if (mtype != DBUS_MESSAGE_TYPE_SIGNAL)
1380 /* Set destination. */
8c7a4ac5 1381 {
dcbf5805
MA
1382 if (!dbus_message_set_destination (dmessage, SSDATA (service)))
1383 {
1384 UNGCPRO;
1385 XD_SIGNAL2 (build_string ("Unable to set the destination"),
1386 service);
1387 }
8c7a4ac5 1388 }
dcbf5805 1389
8c7a4ac5 1390 else
dcbf5805 1391 /* Set destination for unicast signals. */
8c7a4ac5 1392 {
dcbf5805 1393 Lisp_Object uname;
033b73e2 1394
dcbf5805
MA
1395 /* If it is the same unique name as we are registered at the
1396 bus or an unknown name, we regard it as broadcast message
1397 due to backward compatibility. */
1398 if (dbus_bus_name_has_owner (connection, SSDATA (service), NULL))
1399 uname = call2 (intern ("dbus-get-name-owner"), bus, service);
1400 else
1401 uname = Qnil;
87cf1a39 1402
dcbf5805
MA
1403 if (STRINGP (uname)
1404 && (strcmp (dbus_bus_get_unique_name (connection), SSDATA (uname))
1405 != 0)
1406 && (!dbus_message_set_destination (dmessage, SSDATA (service))))
1407 {
1408 UNGCPRO;
1409 XD_SIGNAL2 (build_string ("Unable to set signal destination"),
1410 service);
1411 }
1412 }
033b73e2
MA
1413 }
1414
dcbf5805
MA
1415 /* Set message parameters. */
1416 if ((mtype == DBUS_MESSAGE_TYPE_METHOD_CALL)
1417 || (mtype == DBUS_MESSAGE_TYPE_SIGNAL))
033b73e2 1418 {
dcbf5805
MA
1419 if ((!dbus_message_set_path (dmessage, SSDATA (path)))
1420 || (!dbus_message_set_interface (dmessage, SSDATA (interface)))
1421 || (!dbus_message_set_member (dmessage, SSDATA (member))))
2c3a8b27 1422 {
dcbf5805
MA
1423 UNGCPRO;
1424 XD_SIGNAL1 (build_string ("Unable to set the message parameter"));
2c3a8b27 1425 }
033b73e2 1426 }
13ecc6dc 1427
dcbf5805
MA
1428 else /* DBUS_MESSAGE_TYPE_METHOD_RETURN, DBUS_MESSAGE_TYPE_ERROR */
1429 {
1430 if (!dbus_message_set_reply_serial (dmessage, serial))
1431 {
1432 UNGCPRO;
1433 XD_SIGNAL1 (build_string ("Unable to create a return message"));
1434 }
13ecc6dc 1435
dcbf5805
MA
1436 if ((mtype == DBUS_MESSAGE_TYPE_ERROR)
1437 && (!dbus_message_set_error_name (dmessage, DBUS_ERROR_FAILED)))
1438 {
1439 UNGCPRO;
1440 XD_SIGNAL1 (build_string ("Unable to create a error message"));
1441 }
1442 }
90b3fc84
MA
1443
1444 /* Check for timeout parameter. */
dcbf5805 1445 if ((count+2 <= nargs) && (EQ ((args[count]), QCdbus_timeout)))
033b73e2 1446 {
dcbf5805 1447 CHECK_NATNUM (args[count+1]);
42b2a986 1448 timeout = min (XFASTINT (args[count+1]), INT_MAX);
dcbf5805 1449 count = count+2;
033b73e2
MA
1450 }
1451
54371585
MA
1452 /* Initialize parameter list of message. */
1453 dbus_message_iter_init_append (dmessage, &iter);
1454
033b73e2 1455 /* Append parameters to the message. */
dcbf5805 1456 for (; count < nargs; ++count)
033b73e2 1457 {
dcbf5805
MA
1458 dtype = XD_OBJECT_TO_DBUS_TYPE (args[count]);
1459 if (XD_DBUS_TYPE_P (args[count]))
8c7a4ac5 1460 {
dcbf5805
MA
1461 XD_DEBUG_VALID_LISP_OBJECT_P (args[count]);
1462 XD_DEBUG_VALID_LISP_OBJECT_P (args[count+1]);
1463 XD_DEBUG_MESSAGE ("Parameter%"pD"d %s %s", count - 4,
1464 XD_OBJECT_TO_STRING (args[count]),
1465 XD_OBJECT_TO_STRING (args[count+1]));
1466 ++count;
8c7a4ac5
MA
1467 }
1468 else
1469 {
dcbf5805
MA
1470 XD_DEBUG_VALID_LISP_OBJECT_P (args[count]);
1471 XD_DEBUG_MESSAGE ("Parameter%"pD"d %s", count - 4,
1472 XD_OBJECT_TO_STRING (args[count]));
8c7a4ac5 1473 }
033b73e2 1474
abe136ee 1475 /* Check for valid signature. We use DBUS_TYPE_INVALID as
87cf1a39 1476 indication that there is no parent type. */
dcbf5805 1477 xd_signature (signature, dtype, DBUS_TYPE_INVALID, args[count]);
87cf1a39 1478
dcbf5805 1479 xd_append_arg (dtype, args[count], &iter);
033b73e2
MA
1480 }
1481
ca4f31ea
MA
1482 if (!NILP (handler))
1483 {
1484 /* Send the message. The message is just added to the outgoing
1485 message queue. */
1486 if (!dbus_connection_send_with_reply (connection, dmessage,
1487 NULL, timeout))
dcbf5805
MA
1488 {
1489 UNGCPRO;
1490 XD_SIGNAL1 (build_string ("Cannot send message"));
1491 }
033b73e2 1492
f04bb9b2 1493 /* The result is the key in Vdbus_registered_objects_table. */
08686060 1494 serial = dbus_message_get_serial (dmessage);
dcbf5805
MA
1495 result = list3 (QCdbus_registered_serial,
1496 bus, make_fixnum_or_float (serial));
13ecc6dc 1497
ca4f31ea 1498 /* Create a hash table entry. */
f04bb9b2 1499 Fputhash (result, handler, Vdbus_registered_objects_table);
ca4f31ea
MA
1500 }
1501 else
1502 {
1503 /* Send the message. The message is just added to the outgoing
1504 message queue. */
1505 if (!dbus_connection_send (connection, dmessage, NULL))
dcbf5805
MA
1506 {
1507 UNGCPRO;
1508 XD_SIGNAL1 (build_string ("Cannot send message"));
1509 }
13ecc6dc 1510
ca4f31ea
MA
1511 result = Qnil;
1512 }
1513
dcbf5805 1514 XD_DEBUG_MESSAGE ("Message sent: %s", XD_OBJECT_TO_STRING (result));
13ecc6dc
MA
1515
1516 /* Cleanup. */
1517 dbus_message_unref (dmessage);
1518
1519 /* Return the result. */
1520 RETURN_UNGCPRO (result);
1521}
1522
3fad2ad2
J
1523/* Read one queued incoming message of the D-Bus BUS.
1524 BUS is either a Lisp symbol, :system or :session, or a string denoting
1525 the bus address. */
3fad2ad2
J
1526static void
1527xd_read_message_1 (DBusConnection *connection, Lisp_Object bus)
033b73e2 1528{
a31d47c7 1529 Lisp_Object args, key, value;
033b73e2 1530 struct gcpro gcpro1;
15f16c1b 1531 struct input_event event;
033b73e2
MA
1532 DBusMessage *dmessage;
1533 DBusMessageIter iter;
243e0530
PE
1534 int dtype;
1535 int mtype;
30217ff0 1536 dbus_uint32_t serial;
08686060 1537 unsigned int ui_serial;
a8e72f4f 1538 const char *uname, *path, *interface, *member;
39abdd4a 1539
033b73e2
MA
1540 dmessage = dbus_connection_pop_message (connection);
1541
1542 /* Return if there is no queued message. */
1543 if (dmessage == NULL)
3fad2ad2 1544 return;
033b73e2
MA
1545
1546 /* Collect the parameters. */
a31d47c7
MA
1547 args = Qnil;
1548 GCPRO1 (args);
033b73e2 1549
033b73e2 1550 /* Loop over the resulting parameters. Construct a list. */
17bc8f94 1551 if (dbus_message_iter_init (dmessage, &iter))
033b73e2 1552 {
17bc8f94
MA
1553 while ((dtype = dbus_message_iter_get_arg_type (&iter))
1554 != DBUS_TYPE_INVALID)
1555 {
1556 args = Fcons (xd_retrieve_arg (dtype, &iter), args);
1557 dbus_message_iter_next (&iter);
1558 }
1559 /* The arguments are stored in reverse order. Reorder them. */
1560 args = Fnreverse (args);
033b73e2
MA
1561 }
1562
13ecc6dc
MA
1563 /* Read message type, message serial, unique name, object path,
1564 interface and member from the message. */
367ea173 1565 mtype = dbus_message_get_type (dmessage);
08686060 1566 ui_serial = serial =
367ea173
MA
1567 ((mtype == DBUS_MESSAGE_TYPE_METHOD_RETURN)
1568 || (mtype == DBUS_MESSAGE_TYPE_ERROR))
1569 ? dbus_message_get_reply_serial (dmessage)
1570 : dbus_message_get_serial (dmessage);
1571 uname = dbus_message_get_sender (dmessage);
1572 path = dbus_message_get_path (dmessage);
a8e72f4f 1573 interface = dbus_message_get_interface (dmessage);
367ea173 1574 member = dbus_message_get_member (dmessage);
a8e72f4f 1575
30217ff0 1576 XD_DEBUG_MESSAGE ("Event received: %s %u %s %s %s %s %s",
dcbf5805 1577 XD_MESSAGE_TYPE_TO_STRING (mtype),
08686060 1578 ui_serial, uname, path, interface, member,
dcbf5805 1579 XD_OBJECT_TO_STRING (args));
17bc8f94 1580
dcbf5805
MA
1581 if (mtype == DBUS_MESSAGE_TYPE_INVALID)
1582 goto cleanup;
1583
1584 else if ((mtype == DBUS_MESSAGE_TYPE_METHOD_RETURN)
1585 || (mtype == DBUS_MESSAGE_TYPE_ERROR))
13ecc6dc
MA
1586 {
1587 /* Search for a registered function of the message. */
dcbf5805
MA
1588 key = list3 (QCdbus_registered_serial, bus,
1589 make_fixnum_or_float (serial));
f04bb9b2 1590 value = Fgethash (key, Vdbus_registered_objects_table, Qnil);
13ecc6dc
MA
1591
1592 /* There shall be exactly one entry. Construct an event. */
1593 if (NILP (value))
1594 goto cleanup;
1595
1596 /* Remove the entry. */
f04bb9b2 1597 Fremhash (key, Vdbus_registered_objects_table);
13ecc6dc
MA
1598
1599 /* Construct an event. */
1600 EVENT_INIT (event);
1601 event.kind = DBUS_EVENT;
1602 event.frame_or_window = Qnil;
1603 event.arg = Fcons (value, args);
1604 }
a31d47c7 1605
dcbf5805 1606 else /* DBUS_MESSAGE_TYPE_METHOD_CALL, DBUS_MESSAGE_TYPE_SIGNAL. */
a31d47c7 1607 {
f04bb9b2
MA
1608 /* Vdbus_registered_objects_table requires non-nil interface and
1609 member. */
13ecc6dc
MA
1610 if ((interface == NULL) || (member == NULL))
1611 goto cleanup;
1612
1613 /* Search for a registered function of the message. */
dcbf5805
MA
1614 key = list4 ((mtype == DBUS_MESSAGE_TYPE_METHOD_CALL)
1615 ? QCdbus_registered_method
1616 : QCdbus_registered_signal,
1617 bus, build_string (interface), build_string (member));
f04bb9b2 1618 value = Fgethash (key, Vdbus_registered_objects_table, Qnil);
13ecc6dc
MA
1619
1620 /* Loop over the registered functions. Construct an event. */
1621 while (!NILP (value))
a31d47c7 1622 {
13ecc6dc
MA
1623 key = CAR_SAFE (value);
1624 /* key has the structure (UNAME SERVICE PATH HANDLER). */
1625 if (((uname == NULL)
1626 || (NILP (CAR_SAFE (key)))
59d6fe83 1627 || (strcmp (uname, SSDATA (CAR_SAFE (key))) == 0))
13ecc6dc
MA
1628 && ((path == NULL)
1629 || (NILP (CAR_SAFE (CDR_SAFE (CDR_SAFE (key)))))
1630 || (strcmp (path,
59d6fe83 1631 SSDATA (CAR_SAFE (CDR_SAFE (CDR_SAFE (key)))))
13ecc6dc
MA
1632 == 0))
1633 && (!NILP (CAR_SAFE (CDR_SAFE (CDR_SAFE (CDR_SAFE (key)))))))
1634 {
1635 EVENT_INIT (event);
1636 event.kind = DBUS_EVENT;
1637 event.frame_or_window = Qnil;
b4289b64
MA
1638 event.arg
1639 = Fcons (CAR_SAFE (CDR_SAFE (CDR_SAFE (CDR_SAFE (key)))), args);
13ecc6dc
MA
1640 break;
1641 }
1642 value = CDR_SAFE (value);
a31d47c7 1643 }
13ecc6dc
MA
1644
1645 if (NILP (value))
1646 goto cleanup;
a31d47c7 1647 }
033b73e2 1648
13ecc6dc
MA
1649 /* Add type, serial, uname, path, interface and member to the event. */
1650 event.arg = Fcons ((member == NULL ? Qnil : build_string (member)),
1651 event.arg);
1652 event.arg = Fcons ((interface == NULL ? Qnil : build_string (interface)),
1653 event.arg);
1654 event.arg = Fcons ((path == NULL ? Qnil : build_string (path)),
1655 event.arg);
1656 event.arg = Fcons ((uname == NULL ? Qnil : build_string (uname)),
1657 event.arg);
08686060 1658 event.arg = Fcons (make_fixnum_or_float (serial), event.arg);
13ecc6dc
MA
1659 event.arg = Fcons (make_number (mtype), event.arg);
1660
1661 /* Add the bus symbol to the event. */
1662 event.arg = Fcons (bus, event.arg);
1663
1664 /* Store it into the input event queue. */
1665 kbd_buffer_store_event (&event);
1666
dcbf5805 1667 XD_DEBUG_MESSAGE ("Event stored: %s", XD_OBJECT_TO_STRING (event.arg));
13ecc6dc 1668
c1d5ce94 1669 /* Cleanup. */
a8e72f4f 1670 cleanup:
033b73e2 1671 dbus_message_unref (dmessage);
c1d5ce94 1672
3fad2ad2
J
1673 UNGCPRO;
1674}
1675
1676/* Read queued incoming messages of the D-Bus BUS.
1677 BUS is either a Lisp symbol, :system or :session, or a string denoting
1678 the bus address. */
3fad2ad2
J
1679static Lisp_Object
1680xd_read_message (Lisp_Object bus)
1681{
dcbf5805
MA
1682 /* Retrieve bus address. */
1683 DBusConnection *connection = xd_get_connection_address (bus);
3fad2ad2
J
1684
1685 /* Non blocking read of the next available message. */
1686 dbus_connection_read_write (connection, 0);
1687
1688 while (dbus_connection_get_dispatch_status (connection)
1689 != DBUS_DISPATCH_COMPLETE)
1690 xd_read_message_1 (connection, bus);
1691 return Qnil;
033b73e2
MA
1692}
1693
08609ffd
MA
1694/* Callback called when something is ready to read or write. */
1695static void
de1339b0 1696xd_read_queued_messages (int fd, void *data)
033b73e2 1697{
5cb67954 1698 Lisp_Object busp = xd_registered_buses;
08609ffd 1699 Lisp_Object bus = Qnil;
dcbf5805 1700 Lisp_Object key;
96faeb40 1701
08609ffd
MA
1702 /* Find bus related to fd. */
1703 if (data != NULL)
1704 while (!NILP (busp))
1705 {
dcbf5805
MA
1706 key = CAR_SAFE (CAR_SAFE (busp));
1707 if ((SYMBOLP (key) && XSYMBOL (key) == data)
1708 || (STRINGP (key) && XSTRING (key) == data))
1709 bus = key;
08609ffd
MA
1710 busp = CDR_SAFE (busp);
1711 }
1712
5e617bc2 1713 if (NILP (bus))
08609ffd
MA
1714 return;
1715
1716 /* We ignore all Lisp errors during the call. */
0c372655 1717 xd_in_read_queued_messages = 1;
08609ffd 1718 internal_catch (Qdbus_error, xd_read_message, bus);
0c372655 1719 xd_in_read_queued_messages = 0;
033b73e2
MA
1720}
1721
033b73e2
MA
1722\f
1723void
971de7fb 1724syms_of_dbusbind (void)
033b73e2
MA
1725{
1726
cd3520a4 1727 DEFSYM (Qdbus_init_bus, "dbus-init-bus");
058ed861
MA
1728 defsubr (&Sdbus_init_bus);
1729
cd3520a4 1730 DEFSYM (Qdbus_get_unique_name, "dbus-get-unique-name");
033b73e2
MA
1731 defsubr (&Sdbus_get_unique_name);
1732
dcbf5805
MA
1733 DEFSYM (Qdbus_message_internal, "dbus-message-internal");
1734 defsubr (&Sdbus_message_internal);
17bc8f94 1735
cd3520a4 1736 DEFSYM (Qdbus_error, "dbus-error");
033b73e2
MA
1737 Fput (Qdbus_error, Qerror_conditions,
1738 list2 (Qdbus_error, Qerror));
1739 Fput (Qdbus_error, Qerror_message,
2a0213a6 1740 build_pure_c_string ("D-Bus error"));
033b73e2 1741
cd3520a4
JB
1742 DEFSYM (QCdbus_system_bus, ":system");
1743 DEFSYM (QCdbus_session_bus, ":session");
cd3520a4
JB
1744 DEFSYM (QCdbus_timeout, ":timeout");
1745 DEFSYM (QCdbus_type_byte, ":byte");
1746 DEFSYM (QCdbus_type_boolean, ":boolean");
1747 DEFSYM (QCdbus_type_int16, ":int16");
1748 DEFSYM (QCdbus_type_uint16, ":uint16");
1749 DEFSYM (QCdbus_type_int32, ":int32");
1750 DEFSYM (QCdbus_type_uint32, ":uint32");
1751 DEFSYM (QCdbus_type_int64, ":int64");
1752 DEFSYM (QCdbus_type_uint64, ":uint64");
1753 DEFSYM (QCdbus_type_double, ":double");
1754 DEFSYM (QCdbus_type_string, ":string");
1755 DEFSYM (QCdbus_type_object_path, ":object-path");
1756 DEFSYM (QCdbus_type_signature, ":signature");
da1fec2b 1757#ifdef DBUS_TYPE_UNIX_FD
cd3520a4 1758 DEFSYM (QCdbus_type_unix_fd, ":unix-fd");
da1fec2b 1759#endif
cd3520a4
JB
1760 DEFSYM (QCdbus_type_array, ":array");
1761 DEFSYM (QCdbus_type_variant, ":variant");
1762 DEFSYM (QCdbus_type_struct, ":struct");
1763 DEFSYM (QCdbus_type_dict_entry, ":dict-entry");
dcbf5805
MA
1764 DEFSYM (QCdbus_registered_serial, ":serial");
1765 DEFSYM (QCdbus_registered_method, ":method");
1766 DEFSYM (QCdbus_registered_signal, ":signal");
1767
1768 DEFVAR_LISP ("dbus-compiled-version",
1769 Vdbus_compiled_version,
1770 doc: /* The version of D-Bus Emacs is compiled against. */);
1771#ifdef DBUS_VERSION_STRING
2a0213a6 1772 Vdbus_compiled_version = build_pure_c_string (DBUS_VERSION_STRING);
dcbf5805
MA
1773#else
1774 Vdbus_compiled_version = Qnil;
1775#endif
54371585 1776
dcbf5805
MA
1777 DEFVAR_LISP ("dbus-runtime-version",
1778 Vdbus_runtime_version,
1779 doc: /* The version of D-Bus Emacs runs with. */);
1780 {
1781#ifdef DBUS_VERSION
1782 int major, minor, micro;
243e0530 1783 char s[sizeof ".." + 3 * INT_STRLEN_BOUND (int)];
dcbf5805 1784 dbus_get_version (&major, &minor, &micro);
a8290ec3
DA
1785 Vdbus_runtime_version
1786 = make_formatted_string (s, "%d.%d.%d", major, minor, micro);
dcbf5805
MA
1787#else
1788 Vdbus_runtime_version = Qnil;
1789#endif
1790 }
1791
1792 DEFVAR_LISP ("dbus-message-type-invalid",
1793 Vdbus_message_type_invalid,
1794 doc: /* This value is never a valid message type. */);
1795 Vdbus_message_type_invalid = make_number (DBUS_MESSAGE_TYPE_INVALID);
1796
1797 DEFVAR_LISP ("dbus-message-type-method-call",
1798 Vdbus_message_type_method_call,
1799 doc: /* Message type of a method call message. */);
1800 Vdbus_message_type_method_call = make_number (DBUS_MESSAGE_TYPE_METHOD_CALL);
1801
1802 DEFVAR_LISP ("dbus-message-type-method-return",
1803 Vdbus_message_type_method_return,
1804 doc: /* Message type of a method return message. */);
1805 Vdbus_message_type_method_return
1806 = make_number (DBUS_MESSAGE_TYPE_METHOD_RETURN);
1807
1808 DEFVAR_LISP ("dbus-message-type-error",
1809 Vdbus_message_type_error,
1810 doc: /* Message type of an error reply message. */);
1811 Vdbus_message_type_error = make_number (DBUS_MESSAGE_TYPE_ERROR);
1812
1813 DEFVAR_LISP ("dbus-message-type-signal",
1814 Vdbus_message_type_signal,
1815 doc: /* Message type of a signal message. */);
1816 Vdbus_message_type_signal = make_number (DBUS_MESSAGE_TYPE_SIGNAL);
0c372655 1817
f04bb9b2 1818 DEFVAR_LISP ("dbus-registered-objects-table",
29208e82 1819 Vdbus_registered_objects_table,
39abdd4a 1820 doc: /* Hash table of registered functions for D-Bus.
0c372655 1821
f04bb9b2
MA
1822There are two different uses of the hash table: for accessing
1823registered interfaces properties, targeted by signals or method calls,
1824and for calling handlers in case of non-blocking method call returns.
13ecc6dc 1825
dcbf5805
MA
1826In the first case, the key in the hash table is the list (TYPE BUS
1827INTERFACE MEMBER). TYPE is one of the Lisp symbols `:method',
1828`:signal' or `:property'. BUS is either a Lisp symbol, `:system' or
0c372655
MA
1829`:session', or a string denoting the bus address. INTERFACE is a
1830string which denotes a D-Bus interface, and MEMBER, also a string, is
1831either a method, a signal or a property INTERFACE is offering. All
1832arguments but BUS must not be nil.
a31d47c7 1833
dcbf5805
MA
1834The value in the hash table is a list of quadruple lists \((UNAME
1835SERVICE PATH OBJECT [RULE]) ...). SERVICE is the service name as
1836registered, UNAME is the corresponding unique name. In case of
1837registered methods and properties, UNAME is nil. PATH is the object
1838path of the sending object. All of them can be nil, which means a
1839wildcard then. OBJECT is either the handler to be called when a D-Bus
1840message, which matches the key criteria, arrives (TYPE `:method' and
1841`:signal'), or a cons cell containing the value of the property (TYPE
1842`:property').
13ecc6dc 1843
dcbf5805
MA
1844For entries of type `:signal', there is also a fifth element RULE,
1845which keeps the match string the signal is registered with.
a3de0cbd 1846
dcbf5805 1847In the second case, the key in the hash table is the list (:serial BUS
0c372655
MA
1848SERIAL). BUS is either a Lisp symbol, `:system' or `:session', or a
1849string denoting the bus address. SERIAL is the serial number of the
1850non-blocking method call, a reply is expected. Both arguments must
1851not be nil. The value in the hash table is HANDLER, the function to
1852be called when the D-Bus reply message arrives. */);
1853 {
1854 Lisp_Object args[2];
1855 args[0] = QCtest;
1856 args[1] = Qequal;
1857 Vdbus_registered_objects_table = Fmake_hash_table (2, args);
1858 }
033b73e2 1859
29208e82 1860 DEFVAR_LISP ("dbus-debug", Vdbus_debug,
39abdd4a 1861 doc: /* If non-nil, debug messages of D-Bus bindings are raised. */);
033b73e2
MA
1862#ifdef DBUS_DEBUG
1863 Vdbus_debug = Qt;
a79b0f28
MA
1864 /* We can also set environment variable DBUS_VERBOSE=1 in order to
1865 see more traces. This requires libdbus-1 to be configured with
1866 --enable-verbose-mode. */
033b73e2
MA
1867#else
1868 Vdbus_debug = Qnil;
1869#endif
1870
5cb67954
MA
1871 /* Initialize internal objects. */
1872 xd_registered_buses = Qnil;
1873 staticpro (&xd_registered_buses);
1874
d67b4f80 1875 Fprovide (intern_c_string ("dbusbind"), Qnil);
033b73e2
MA
1876
1877}
1878
1879#endif /* HAVE_DBUS */