PageRenderTime 45ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 1ms

/lisp/net/dbus.el

http://github.com/davidswelt/aquamacs-emacs
Emacs Lisp | 1823 lines | 1364 code | 253 blank | 206 comment | 48 complexity | 3a3696aa98811d8ce884bc2ca8115055 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.0, GPL-2.0, AGPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. ;;; dbus.el --- Elisp bindings for D-Bus.
  2. ;; Copyright (C) 2007-2016 Free Software Foundation, Inc.
  3. ;; Author: Michael Albinus <michael.albinus@gmx.de>
  4. ;; Keywords: comm, hardware
  5. ;; This file is part of GNU Emacs.
  6. ;; GNU Emacs is free software: you can redistribute it and/or modify
  7. ;; it under the terms of the GNU General Public License as published by
  8. ;; the Free Software Foundation, either version 3 of the License, or
  9. ;; (at your option) any later version.
  10. ;; GNU Emacs is distributed in the hope that it will be useful,
  11. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ;; GNU General Public License for more details.
  14. ;; You should have received a copy of the GNU General Public License
  15. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  16. ;;; Commentary:
  17. ;; This package provides language bindings for the D-Bus API. D-Bus
  18. ;; is a message bus system, a simple way for applications to talk to
  19. ;; one another. See <http://dbus.freedesktop.org/> for details.
  20. ;; Low-level language bindings are implemented in src/dbusbind.c.
  21. ;; D-Bus support in the Emacs core can be disabled with configuration
  22. ;; option "--without-dbus".
  23. ;;; Code:
  24. ;; Declare used subroutines and variables.
  25. (declare-function dbus-message-internal "dbusbind.c")
  26. (declare-function dbus--init-bus "dbusbind.c")
  27. (defvar dbus-message-type-invalid)
  28. (defvar dbus-message-type-method-call)
  29. (defvar dbus-message-type-method-return)
  30. (defvar dbus-message-type-error)
  31. (defvar dbus-message-type-signal)
  32. (defvar dbus-debug)
  33. (defvar dbus-registered-objects-table)
  34. ;; Pacify byte compiler.
  35. (eval-when-compile (require 'cl-lib))
  36. (require 'xml)
  37. (defconst dbus-service-dbus "org.freedesktop.DBus"
  38. "The bus name used to talk to the bus itself.")
  39. (defconst dbus-path-dbus "/org/freedesktop/DBus"
  40. "The object path used to talk to the bus itself.")
  41. (defconst dbus-path-local (concat dbus-path-dbus "/Local")
  42. "The object path used in local/in-process-generated messages.")
  43. ;; Default D-Bus interfaces.
  44. (defconst dbus-interface-dbus "org.freedesktop.DBus"
  45. "The interface exported by the service `dbus-service-dbus'.")
  46. (defconst dbus-interface-peer (concat dbus-interface-dbus ".Peer")
  47. "The interface for peer objects.
  48. See URL `http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-peer'.")
  49. ;; <interface name="org.freedesktop.DBus.Peer">
  50. ;; <method name="Ping">
  51. ;; </method>
  52. ;; <method name="GetMachineId">
  53. ;; <arg name="machine_uuid" type="s" direction="out"/>
  54. ;; </method>
  55. ;; </interface>
  56. (defconst dbus-interface-introspectable
  57. (concat dbus-interface-dbus ".Introspectable")
  58. "The interface supported by introspectable objects.
  59. See URL `http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-introspectable'.")
  60. ;; <interface name="org.freedesktop.DBus.Introspectable">
  61. ;; <method name="Introspect">
  62. ;; <arg name="data" type="s" direction="out"/>
  63. ;; </method>
  64. ;; </interface>
  65. (defconst dbus-interface-properties (concat dbus-interface-dbus ".Properties")
  66. "The interface for property objects.
  67. See URL `http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-properties'.")
  68. ;; <interface name="org.freedesktop.DBus.Properties">
  69. ;; <method name="Get">
  70. ;; <arg name="interface" type="s" direction="in"/>
  71. ;; <arg name="propname" type="s" direction="in"/>
  72. ;; <arg name="value" type="v" direction="out"/>
  73. ;; </method>
  74. ;; <method name="Set">
  75. ;; <arg name="interface" type="s" direction="in"/>
  76. ;; <arg name="propname" type="s" direction="in"/>
  77. ;; <arg name="value" type="v" direction="in"/>
  78. ;; </method>
  79. ;; <method name="GetAll">
  80. ;; <arg name="interface" type="s" direction="in"/>
  81. ;; <arg name="props" type="a{sv}" direction="out"/>
  82. ;; </method>
  83. ;; <signal name="PropertiesChanged">
  84. ;; <arg name="interface" type="s"/>
  85. ;; <arg name="changed_properties" type="a{sv}"/>
  86. ;; <arg name="invalidated_properties" type="as"/>
  87. ;; </signal>
  88. ;; </interface>
  89. (defconst dbus-interface-objectmanager
  90. (concat dbus-interface-dbus ".ObjectManager")
  91. "The object manager interface.
  92. See URL `http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager'.")
  93. ;; <interface name="org.freedesktop.DBus.ObjectManager">
  94. ;; <method name="GetManagedObjects">
  95. ;; <arg name="object_paths_interfaces_and_properties"
  96. ;; type="a{oa{sa{sv}}}" direction="out"/>
  97. ;; </method>
  98. ;; <signal name="InterfacesAdded">
  99. ;; <arg name="object_path" type="o"/>
  100. ;; <arg name="interfaces_and_properties" type="a{sa{sv}}"/>
  101. ;; </signal>
  102. ;; <signal name="InterfacesRemoved">
  103. ;; <arg name="object_path" type="o"/>
  104. ;; <arg name="interfaces" type="as"/>
  105. ;; </signal>
  106. ;; </interface>
  107. (defconst dbus-interface-local (concat dbus-interface-dbus ".Local")
  108. "An interface whose methods can only be invoked by the local implementation.")
  109. ;; <interface name="org.freedesktop.DBus.Local">
  110. ;; <signal name="Disconnected">
  111. ;; <arg name="object_path" type="o"/>
  112. ;; </signal>
  113. ;; </interface>
  114. ;; Emacs defaults.
  115. (defconst dbus-service-emacs "org.gnu.Emacs"
  116. "The well known service name of Emacs.")
  117. (defconst dbus-path-emacs "/org/gnu/Emacs"
  118. "The object path namespace used by Emacs.
  119. All object paths provided by the service `dbus-service-emacs'
  120. shall be subdirectories of this path.")
  121. (defconst dbus-interface-emacs "org.gnu.Emacs"
  122. "The interface namespace used by Emacs.")
  123. ;; D-Bus constants.
  124. (defmacro dbus-ignore-errors (&rest body)
  125. "Execute BODY; signal D-Bus error when `dbus-debug' is non-nil.
  126. Otherwise, return result of last form in BODY, or all other errors."
  127. (declare (indent 0) (debug t))
  128. `(condition-case err
  129. (progn ,@body)
  130. (dbus-error (when dbus-debug (signal (car err) (cdr err))))))
  131. (font-lock-add-keywords 'emacs-lisp-mode '("\\<dbus-ignore-errors\\>"))
  132. (define-obsolete-variable-alias 'dbus-event-error-hooks
  133. 'dbus-event-error-functions "24.3")
  134. (defvar dbus-event-error-functions '(dbus-notice-synchronous-call-errors)
  135. "Functions to be called when a D-Bus error happens in the event handler.
  136. Every function must accept two arguments, the event and the error variable
  137. caught in `condition-case' by `dbus-error'.")
  138. ;;; Basic D-Bus message functions.
  139. (defvar dbus-return-values-table (make-hash-table :test 'equal)
  140. "Hash table for temporary storing arguments of reply messages.
  141. A key in this hash table is a list (:serial BUS SERIAL), like in
  142. `dbus-registered-objects-table'. BUS is either a Lisp symbol,
  143. `:system' or `:session', or a string denoting the bus address.
  144. SERIAL is the serial number of the reply message.
  145. The value of an entry is a cons (STATE . RESULT). STATE can be
  146. either `:pending' (we are still waiting for the result),
  147. `:complete' (the result is available) or `:error' (the reply
  148. message was an error message).")
  149. (defun dbus-call-method-handler (&rest args)
  150. "Handler for reply messages of asynchronous D-Bus message calls.
  151. It calls the function stored in `dbus-registered-objects-table'.
  152. The result will be made available in `dbus-return-values-table'."
  153. (let* ((key (list :serial
  154. (dbus-event-bus-name last-input-event)
  155. (dbus-event-serial-number last-input-event)))
  156. (result (gethash key dbus-return-values-table)))
  157. (when (consp result)
  158. (setcar result :complete)
  159. (setcdr result (if (= (length args) 1) (car args) args)))))
  160. (defun dbus-notice-synchronous-call-errors (ev er)
  161. "Detect errors resulting from pending synchronous calls."
  162. (let* ((key (list :serial
  163. (dbus-event-bus-name ev)
  164. (dbus-event-serial-number ev)))
  165. (result (gethash key dbus-return-values-table)))
  166. (when (consp result)
  167. (setcar result :error)
  168. (setcdr result er))))
  169. (defun dbus-call-method (bus service path interface method &rest args)
  170. "Call METHOD on the D-Bus BUS.
  171. BUS is either a Lisp symbol, `:system' or `:session', or a string
  172. denoting the bus address.
  173. SERVICE is the D-Bus service name to be used. PATH is the D-Bus
  174. object path SERVICE is registered at. INTERFACE is an interface
  175. offered by SERVICE. It must provide METHOD.
  176. If the parameter `:timeout' is given, the following integer TIMEOUT
  177. specifies the maximum number of milliseconds the method call must
  178. return. The default value is 25,000. If the method call doesn't
  179. return in time, a D-Bus error is raised.
  180. All other arguments ARGS are passed to METHOD as arguments. They are
  181. converted into D-Bus types via the following rules:
  182. t and nil => DBUS_TYPE_BOOLEAN
  183. number => DBUS_TYPE_UINT32
  184. integer => DBUS_TYPE_INT32
  185. float => DBUS_TYPE_DOUBLE
  186. string => DBUS_TYPE_STRING
  187. list => DBUS_TYPE_ARRAY
  188. All arguments can be preceded by a type symbol. For details about
  189. type symbols, see Info node `(dbus)Type Conversion'.
  190. `dbus-call-method' returns the resulting values of METHOD as a list of
  191. Lisp objects. The type conversion happens the other direction as for
  192. input arguments. It follows the mapping rules:
  193. DBUS_TYPE_BOOLEAN => t or nil
  194. DBUS_TYPE_BYTE => number
  195. DBUS_TYPE_UINT16 => number
  196. DBUS_TYPE_INT16 => integer
  197. DBUS_TYPE_UINT32 => number or float
  198. DBUS_TYPE_UNIX_FD => number or float
  199. DBUS_TYPE_INT32 => integer or float
  200. DBUS_TYPE_UINT64 => number or float
  201. DBUS_TYPE_INT64 => integer or float
  202. DBUS_TYPE_DOUBLE => float
  203. DBUS_TYPE_STRING => string
  204. DBUS_TYPE_OBJECT_PATH => string
  205. DBUS_TYPE_SIGNATURE => string
  206. DBUS_TYPE_ARRAY => list
  207. DBUS_TYPE_VARIANT => list
  208. DBUS_TYPE_STRUCT => list
  209. DBUS_TYPE_DICT_ENTRY => list
  210. Example:
  211. \(dbus-call-method
  212. :session \"org.gnome.seahorse\" \"/org/gnome/seahorse/keys/openpgp\"
  213. \"org.gnome.seahorse.Keys\" \"GetKeyField\"
  214. \"openpgp:657984B8C7A966DD\" \"simple-name\")
  215. => (t (\"Philip R. Zimmermann\"))
  216. If the result of the METHOD call is just one value, the converted Lisp
  217. object is returned instead of a list containing this single Lisp object.
  218. \(dbus-call-method
  219. :system \"org.freedesktop.Hal\" \"/org/freedesktop/Hal/devices/computer\"
  220. \"org.freedesktop.Hal.Device\" \"GetPropertyString\"
  221. \"system.kernel.machine\")
  222. => \"i686\""
  223. (or (featurep 'dbusbind)
  224. (signal 'dbus-error (list "Emacs not compiled with dbus support")))
  225. (or (memq bus '(:system :session)) (stringp bus)
  226. (signal 'wrong-type-argument (list 'keywordp bus)))
  227. (or (stringp service)
  228. (signal 'wrong-type-argument (list 'stringp service)))
  229. (or (stringp path)
  230. (signal 'wrong-type-argument (list 'stringp path)))
  231. (or (stringp interface)
  232. (signal 'wrong-type-argument (list 'stringp interface)))
  233. (or (stringp method)
  234. (signal 'wrong-type-argument (list 'stringp method)))
  235. (let ((timeout (plist-get args :timeout))
  236. (check-interval 0.001)
  237. (key
  238. (apply
  239. 'dbus-message-internal dbus-message-type-method-call
  240. bus service path interface method 'dbus-call-method-handler args))
  241. (result (cons :pending nil)))
  242. ;; Wait until `dbus-call-method-handler' has put the result into
  243. ;; `dbus-return-values-table'. If no timeout is given, use the
  244. ;; default 25". Events which are not from D-Bus must be restored.
  245. ;; `read-event' performs a redisplay. This must be suppressed; it
  246. ;; hurts when reading D-Bus events asynchronously.
  247. ;; Work around bug#16775 by busy-waiting with gradual backoff for
  248. ;; dbus calls to complete. A better approach would involve either
  249. ;; adding arbitrary wait condition support to read-event or
  250. ;; restructuring dbus as a kind of process object. Poll at most
  251. ;; about once per second for completion.
  252. (puthash key result dbus-return-values-table)
  253. (unwind-protect
  254. (progn
  255. (with-timeout ((if timeout (/ timeout 1000.0) 25)
  256. (signal 'dbus-error (list "call timed out")))
  257. (while (eq (car result) :pending)
  258. (let ((event (let ((inhibit-redisplay t) unread-command-events)
  259. (read-event nil nil check-interval))))
  260. (when event
  261. (if (ignore-errors (dbus-check-event event))
  262. (setf result (gethash key dbus-return-values-table))
  263. (setf unread-command-events
  264. (nconc unread-command-events
  265. (cons event nil)))))
  266. (when (< check-interval 1)
  267. (setf check-interval (* check-interval 1.05))))))
  268. (when (eq (car result) :error)
  269. (signal (cadr result) (cddr result)))
  270. (cdr result))
  271. (remhash key dbus-return-values-table))))
  272. ;; `dbus-call-method' works non-blocking now.
  273. (defalias 'dbus-call-method-non-blocking 'dbus-call-method)
  274. (make-obsolete 'dbus-call-method-non-blocking 'dbus-call-method "24.3")
  275. (defun dbus-call-method-asynchronously
  276. (bus service path interface method handler &rest args)
  277. "Call METHOD on the D-Bus BUS asynchronously.
  278. BUS is either a Lisp symbol, `:system' or `:session', or a string
  279. denoting the bus address.
  280. SERVICE is the D-Bus service name to be used. PATH is the D-Bus
  281. object path SERVICE is registered at. INTERFACE is an interface
  282. offered by SERVICE. It must provide METHOD.
  283. HANDLER is a Lisp function, which is called when the corresponding
  284. return message has arrived. If HANDLER is nil, no return message
  285. will be expected.
  286. If the parameter `:timeout' is given, the following integer TIMEOUT
  287. specifies the maximum number of milliseconds the method call must
  288. return. The default value is 25,000. If the method call doesn't
  289. return in time, a D-Bus error is raised.
  290. All other arguments ARGS are passed to METHOD as arguments. They are
  291. converted into D-Bus types via the following rules:
  292. t and nil => DBUS_TYPE_BOOLEAN
  293. number => DBUS_TYPE_UINT32
  294. integer => DBUS_TYPE_INT32
  295. float => DBUS_TYPE_DOUBLE
  296. string => DBUS_TYPE_STRING
  297. list => DBUS_TYPE_ARRAY
  298. All arguments can be preceded by a type symbol. For details about
  299. type symbols, see Info node `(dbus)Type Conversion'.
  300. If HANDLER is a Lisp function, the function returns a key into the
  301. hash table `dbus-registered-objects-table'. The corresponding entry
  302. in the hash table is removed, when the return message has been arrived,
  303. and HANDLER is called.
  304. Example:
  305. \(dbus-call-method-asynchronously
  306. :system \"org.freedesktop.Hal\" \"/org/freedesktop/Hal/devices/computer\"
  307. \"org.freedesktop.Hal.Device\" \"GetPropertyString\" \\='message
  308. \"system.kernel.machine\")
  309. => (:serial :system 2)
  310. -| i686"
  311. (or (featurep 'dbusbind)
  312. (signal 'dbus-error (list "Emacs not compiled with dbus support")))
  313. (or (memq bus '(:system :session)) (stringp bus)
  314. (signal 'wrong-type-argument (list 'keywordp bus)))
  315. (or (stringp service)
  316. (signal 'wrong-type-argument (list 'stringp service)))
  317. (or (stringp path)
  318. (signal 'wrong-type-argument (list 'stringp path)))
  319. (or (stringp interface)
  320. (signal 'wrong-type-argument (list 'stringp interface)))
  321. (or (stringp method)
  322. (signal 'wrong-type-argument (list 'stringp method)))
  323. (or (null handler) (functionp handler)
  324. (signal 'wrong-type-argument (list 'functionp handler)))
  325. (apply 'dbus-message-internal dbus-message-type-method-call
  326. bus service path interface method handler args))
  327. (defun dbus-send-signal (bus service path interface signal &rest args)
  328. "Send signal SIGNAL on the D-Bus BUS.
  329. BUS is either a Lisp symbol, `:system' or `:session', or a string
  330. denoting the bus address. The signal is sent from the D-Bus object
  331. Emacs is registered at BUS.
  332. SERVICE is the D-Bus name SIGNAL is sent to. It can be either a known
  333. name or a unique name. If SERVICE is nil, the signal is sent as
  334. broadcast message. PATH is the D-Bus object path SIGNAL is sent from.
  335. INTERFACE is an interface available at PATH. It must provide signal
  336. SIGNAL.
  337. All other arguments ARGS are passed to SIGNAL as arguments. They are
  338. converted into D-Bus types via the following rules:
  339. t and nil => DBUS_TYPE_BOOLEAN
  340. number => DBUS_TYPE_UINT32
  341. integer => DBUS_TYPE_INT32
  342. float => DBUS_TYPE_DOUBLE
  343. string => DBUS_TYPE_STRING
  344. list => DBUS_TYPE_ARRAY
  345. All arguments can be preceded by a type symbol. For details about
  346. type symbols, see Info node `(dbus)Type Conversion'.
  347. Example:
  348. \(dbus-send-signal
  349. :session nil \"/org/gnu/Emacs\" \"org.gnu.Emacs.FileManager\"
  350. \"FileModified\" \"/home/albinus/.emacs\")"
  351. (or (featurep 'dbusbind)
  352. (signal 'dbus-error (list "Emacs not compiled with dbus support")))
  353. (or (memq bus '(:system :session)) (stringp bus)
  354. (signal 'wrong-type-argument (list 'keywordp bus)))
  355. (or (null service) (stringp service)
  356. (signal 'wrong-type-argument (list 'stringp service)))
  357. (or (stringp path)
  358. (signal 'wrong-type-argument (list 'stringp path)))
  359. (or (stringp interface)
  360. (signal 'wrong-type-argument (list 'stringp interface)))
  361. (or (stringp signal)
  362. (signal 'wrong-type-argument (list 'stringp signal)))
  363. (apply 'dbus-message-internal dbus-message-type-signal
  364. bus service path interface signal args))
  365. (defun dbus-method-return-internal (bus service serial &rest args)
  366. "Return for message SERIAL on the D-Bus BUS.
  367. This is an internal function, it shall not be used outside dbus.el."
  368. (or (featurep 'dbusbind)
  369. (signal 'dbus-error (list "Emacs not compiled with dbus support")))
  370. (or (memq bus '(:system :session)) (stringp bus)
  371. (signal 'wrong-type-argument (list 'keywordp bus)))
  372. (or (stringp service)
  373. (signal 'wrong-type-argument (list 'stringp service)))
  374. (or (natnump serial)
  375. (signal 'wrong-type-argument (list 'natnump serial)))
  376. (apply 'dbus-message-internal dbus-message-type-method-return
  377. bus service serial args))
  378. (defun dbus-method-error-internal (bus service serial &rest args)
  379. "Return error message for message SERIAL on the D-Bus BUS.
  380. This is an internal function, it shall not be used outside dbus.el."
  381. (or (featurep 'dbusbind)
  382. (signal 'dbus-error (list "Emacs not compiled with dbus support")))
  383. (or (memq bus '(:system :session)) (stringp bus)
  384. (signal 'wrong-type-argument (list 'keywordp bus)))
  385. (or (stringp service)
  386. (signal 'wrong-type-argument (list 'stringp service)))
  387. (or (natnump serial)
  388. (signal 'wrong-type-argument (list 'natnump serial)))
  389. (apply 'dbus-message-internal dbus-message-type-error
  390. bus service serial args))
  391. ;;; Hash table of registered functions.
  392. (defun dbus-list-hash-table ()
  393. "Returns all registered member registrations to D-Bus.
  394. The return value is a list, with elements of kind (KEY . VALUE).
  395. See `dbus-registered-objects-table' for a description of the
  396. hash table."
  397. (let (result)
  398. (maphash
  399. (lambda (key value) (add-to-list 'result (cons key value) 'append))
  400. dbus-registered-objects-table)
  401. result))
  402. (defun dbus-setenv (bus variable value)
  403. "Set the value of the BUS environment variable named VARIABLE to VALUE.
  404. BUS is either a Lisp symbol, `:system' or `:session', or a string
  405. denoting the bus address. Both VARIABLE and VALUE should be strings.
  406. Normally, services inherit the environment of the BUS daemon. This
  407. function adds to or modifies that environment when activating services.
  408. Some bus instances, such as `:system', may disable setting the environment."
  409. (dbus-call-method
  410. bus dbus-service-dbus dbus-path-dbus
  411. dbus-interface-dbus "UpdateActivationEnvironment"
  412. `(:array (:dict-entry ,variable ,value))))
  413. (defun dbus-register-service (bus service &rest flags)
  414. "Register known name SERVICE on the D-Bus BUS.
  415. BUS is either a Lisp symbol, `:system' or `:session', or a string
  416. denoting the bus address.
  417. SERVICE is the D-Bus service name that should be registered. It must
  418. be a known name.
  419. FLAGS are keywords, which control how the service name is registered.
  420. The following keywords are recognized:
  421. `:allow-replacement': Allow another service to become the primary
  422. owner if requested.
  423. `:replace-existing': Request to replace the current primary owner.
  424. `:do-not-queue': If we can not become the primary owner do not place
  425. us in the queue.
  426. The function returns a keyword, indicating the result of the
  427. operation. One of the following keywords is returned:
  428. `:primary-owner': Service has become the primary owner of the
  429. requested name.
  430. `:in-queue': Service could not become the primary owner and has been
  431. placed in the queue.
  432. `:exists': Service is already in the queue.
  433. `:already-owner': Service is already the primary owner."
  434. ;; Add Peer handler.
  435. (dbus-register-method
  436. bus service nil dbus-interface-peer "Ping" 'dbus-peer-handler 'dont-register)
  437. ;; Add ObjectManager handler.
  438. (dbus-register-method
  439. bus service nil dbus-interface-objectmanager "GetManagedObjects"
  440. 'dbus-managed-objects-handler 'dont-register)
  441. (let ((arg 0)
  442. reply)
  443. (dolist (flag flags)
  444. (setq arg
  445. (+ arg
  446. (pcase flag
  447. (:allow-replacement 1)
  448. (:replace-existing 2)
  449. (:do-not-queue 4)
  450. (_ (signal 'wrong-type-argument (list flag)))))))
  451. (setq reply (dbus-call-method
  452. bus dbus-service-dbus dbus-path-dbus dbus-interface-dbus
  453. "RequestName" service arg))
  454. (pcase reply
  455. (1 :primary-owner)
  456. (2 :in-queue)
  457. (3 :exists)
  458. (4 :already-owner)
  459. (_ (signal 'dbus-error (list "Could not register service" service))))))
  460. (defun dbus-unregister-service (bus service)
  461. "Unregister all objects related to SERVICE from D-Bus BUS.
  462. BUS is either a Lisp symbol, `:system' or `:session', or a string
  463. denoting the bus address. SERVICE must be a known service name.
  464. The function returns a keyword, indicating the result of the
  465. operation. One of the following keywords is returned:
  466. `:released': We successfully released the service.
  467. `:non-existent': Service name does not exist on this bus.
  468. `:not-owner': We are neither the primary owner nor waiting in the
  469. queue of this service."
  470. (maphash
  471. (lambda (key value)
  472. (unless (equal :serial (car key))
  473. (dolist (elt value)
  474. (ignore-errors
  475. (when (and (equal bus (cadr key)) (string-equal service (cadr elt)))
  476. (unless
  477. (puthash key (delete elt value) dbus-registered-objects-table)
  478. (remhash key dbus-registered-objects-table)))))))
  479. dbus-registered-objects-table)
  480. (let ((reply (dbus-call-method
  481. bus dbus-service-dbus dbus-path-dbus dbus-interface-dbus
  482. "ReleaseName" service)))
  483. (pcase reply
  484. (1 :released)
  485. (2 :non-existent)
  486. (3 :not-owner)
  487. (_ (signal 'dbus-error (list "Could not unregister service" service))))))
  488. (defun dbus-register-signal
  489. (bus service path interface signal handler &rest args)
  490. "Register for a signal on the D-Bus BUS.
  491. BUS is either a Lisp symbol, `:system' or `:session', or a string
  492. denoting the bus address.
  493. SERVICE is the D-Bus service name used by the sending D-Bus object.
  494. It can be either a known name or the unique name of the D-Bus object
  495. sending the signal.
  496. PATH is the D-Bus object path SERVICE is registered. INTERFACE
  497. is an interface offered by SERVICE. It must provide SIGNAL.
  498. HANDLER is a Lisp function to be called when the signal is
  499. received. It must accept as arguments the values SIGNAL is
  500. sending.
  501. SERVICE, PATH, INTERFACE and SIGNAL can be nil. This is
  502. interpreted as a wildcard for the respective argument.
  503. The remaining arguments ARGS can be keywords or keyword string pairs.
  504. The meaning is as follows:
  505. `:argN' STRING:
  506. `:pathN' STRING: This stands for the Nth argument of the
  507. signal. `:pathN' arguments can be used for object path wildcard
  508. matches as specified by D-Bus, while an `:argN' argument
  509. requires an exact match.
  510. `:arg-namespace' STRING: Register for the signals, which first
  511. argument defines the service or interface namespace STRING.
  512. `:path-namespace' STRING: Register for the object path namespace
  513. STRING. All signals sent from an object path, which has STRING as
  514. the preceding string, are matched. This requires PATH to be nil.
  515. `:eavesdrop': Register for unicast signals which are not directed
  516. to the D-Bus object Emacs is registered at D-Bus BUS, if the
  517. security policy of BUS allows this.
  518. Example:
  519. \(defun my-signal-handler (device)
  520. (message \"Device %s added\" device))
  521. \(dbus-register-signal
  522. :system \"org.freedesktop.Hal\" \"/org/freedesktop/Hal/Manager\"
  523. \"org.freedesktop.Hal.Manager\" \"DeviceAdded\" \\='my-signal-handler)
  524. => ((:signal :system \"org.freedesktop.Hal.Manager\" \"DeviceAdded\")
  525. (\"org.freedesktop.Hal\" \"/org/freedesktop/Hal/Manager\" my-signal-handler))
  526. `dbus-register-signal' returns an object, which can be used in
  527. `dbus-unregister-object' for removing the registration."
  528. (let ((counter 0)
  529. (rule "type='signal'")
  530. uname key key1 value)
  531. ;; Retrieve unique name of service. If service is a known name,
  532. ;; we will register for the corresponding unique name, if any.
  533. ;; Signals are sent always with the unique name as sender. Note:
  534. ;; the unique name of `dbus-service-dbus' is that string itself.
  535. (if (and (stringp service)
  536. (not (zerop (length service)))
  537. (not (string-equal service dbus-service-dbus))
  538. (not (string-match "^:" service)))
  539. (setq uname (dbus-get-name-owner bus service))
  540. (setq uname service))
  541. (setq rule (concat rule
  542. (when uname (format ",sender='%s'" uname))
  543. (when interface (format ",interface='%s'" interface))
  544. (when signal (format ",member='%s'" signal))
  545. (when path (format ",path='%s'" path))))
  546. ;; Add arguments to the rule.
  547. (if (or (stringp (car args)) (null (car args)))
  548. ;; As backward compatibility option, we allow just strings.
  549. (dolist (arg args)
  550. (if (stringp arg)
  551. (setq rule (concat rule (format ",arg%d='%s'" counter arg)))
  552. (if arg (signal 'wrong-type-argument (list "Wrong argument" arg))))
  553. (setq counter (1+ counter)))
  554. ;; Parse keywords.
  555. (while args
  556. (setq
  557. key (car args)
  558. rule (concat
  559. rule
  560. (cond
  561. ;; `:arg0' .. `:arg63', `:path0' .. `:path63'.
  562. ((and (keywordp key)
  563. (string-match
  564. "^:\\(arg\\|path\\)\\([[:digit:]]+\\)$"
  565. (symbol-name key)))
  566. (setq counter (match-string 2 (symbol-name key))
  567. args (cdr args)
  568. value (car args))
  569. (unless (and (<= (string-to-number counter) 63)
  570. (stringp value))
  571. (signal 'wrong-type-argument
  572. (list "Wrong argument" key value)))
  573. (format
  574. ",arg%s%s='%s'"
  575. counter
  576. (if (string-equal (match-string 1 (symbol-name key)) "path")
  577. "path" "")
  578. value))
  579. ;; `:arg-namespace', `:path-namespace'.
  580. ((and (keywordp key)
  581. (string-match
  582. "^:\\(arg\\|path\\)-namespace$" (symbol-name key)))
  583. (setq args (cdr args)
  584. value (car args))
  585. (unless (stringp value)
  586. (signal 'wrong-type-argument
  587. (list "Wrong argument" key value)))
  588. (format
  589. ",%s='%s'"
  590. (if (string-equal (match-string 1 (symbol-name key)) "path")
  591. "path_namespace" "arg0namespace")
  592. value))
  593. ;; `:eavesdrop'.
  594. ((eq key :eavesdrop)
  595. ",eavesdrop='true'")
  596. (t (signal 'wrong-type-argument (list "Wrong argument" key)))))
  597. args (cdr args))))
  598. ;; Add the rule to the bus.
  599. (condition-case err
  600. (dbus-call-method
  601. bus dbus-service-dbus dbus-path-dbus dbus-interface-dbus
  602. "AddMatch" rule)
  603. (dbus-error
  604. (if (not (string-match "eavesdrop" rule))
  605. (signal (car err) (cdr err))
  606. ;; The D-Bus spec says we shall fall back to a rule without eavesdrop.
  607. (when dbus-debug (message "Removing eavesdrop from rule %s" rule))
  608. (setq rule (replace-regexp-in-string ",eavesdrop='true'" "" rule))
  609. (dbus-call-method
  610. bus dbus-service-dbus dbus-path-dbus dbus-interface-dbus
  611. "AddMatch" rule))))
  612. (when dbus-debug (message "Matching rule \"%s\" created" rule))
  613. ;; Create a hash table entry.
  614. (setq key (list :signal bus interface signal)
  615. key1 (list uname service path handler rule)
  616. value (gethash key dbus-registered-objects-table))
  617. (unless (member key1 value)
  618. (puthash key (cons key1 value) dbus-registered-objects-table))
  619. ;; Return the object.
  620. (list key (list service path handler))))
  621. (defun dbus-register-method
  622. (bus service path interface method handler &optional dont-register-service)
  623. "Register for method METHOD on the D-Bus BUS.
  624. BUS is either a Lisp symbol, `:system' or `:session', or a string
  625. denoting the bus address.
  626. SERVICE is the D-Bus service name of the D-Bus object METHOD is
  627. registered for. It must be a known name (See discussion of
  628. DONT-REGISTER-SERVICE below).
  629. PATH is the D-Bus object path SERVICE is registered (See discussion of
  630. DONT-REGISTER-SERVICE below). INTERFACE is the interface offered by
  631. SERVICE. It must provide METHOD.
  632. HANDLER is a Lisp function to be called when a method call is
  633. received. It must accept the input arguments of METHOD. The return
  634. value of HANDLER is used for composing the returning D-Bus message.
  635. In case HANDLER shall return a reply message with an empty argument
  636. list, HANDLER must return the symbol `:ignore'.
  637. When DONT-REGISTER-SERVICE is non-nil, the known name SERVICE is not
  638. registered. This means that other D-Bus clients have no way of
  639. noticing the newly registered method. When interfaces are constructed
  640. incrementally by adding single methods or properties at a time,
  641. DONT-REGISTER-SERVICE can be used to prevent other clients from
  642. discovering the still incomplete interface."
  643. ;; Register SERVICE.
  644. (unless (or dont-register-service
  645. (member service (dbus-list-names bus)))
  646. (dbus-register-service bus service))
  647. ;; Create a hash table entry. We use nil for the unique name,
  648. ;; because the method might be called from anybody.
  649. (let* ((key (list :method bus interface method))
  650. (key1 (list nil service path handler))
  651. (value (gethash key dbus-registered-objects-table)))
  652. (unless (member key1 value)
  653. (puthash key (cons key1 value) dbus-registered-objects-table))
  654. ;; Return the object.
  655. (list key (list service path handler))))
  656. (defun dbus-unregister-object (object)
  657. "Unregister OBJECT from D-Bus.
  658. OBJECT must be the result of a preceding `dbus-register-method',
  659. `dbus-register-property' or `dbus-register-signal' call. It
  660. returns t if OBJECT has been unregistered, nil otherwise.
  661. When OBJECT identifies the last method or property, which is
  662. registered for the respective service, Emacs releases its
  663. association to the service from D-Bus."
  664. ;; Check parameter.
  665. (unless (and (consp object) (not (null (car object))) (consp (cdr object)))
  666. (signal 'wrong-type-argument (list 'D-Bus object)))
  667. ;; Find the corresponding entry in the hash table.
  668. (let* ((key (car object))
  669. (type (car key))
  670. (bus (cadr key))
  671. (value (cadr object))
  672. (service (car value))
  673. (entry (gethash key dbus-registered-objects-table))
  674. ret)
  675. ;; key has the structure (TYPE BUS INTERFACE MEMBER).
  676. ;; value has the structure (SERVICE PATH [HANDLER]).
  677. ;; entry has the structure ((UNAME SERVICE PATH MEMBER [RULE]) ...).
  678. ;; MEMBER is either a string (the handler), or a cons cell (a
  679. ;; property value). UNAME and property values are not taken into
  680. ;; account for comparison.
  681. ;; Loop over the registered functions.
  682. (dolist (elt entry)
  683. (when (equal
  684. value
  685. (butlast (cdr elt) (- (length (cdr elt)) (length value))))
  686. (setq ret t)
  687. ;; Compute new hash value. If it is empty, remove it from the
  688. ;; hash table.
  689. (unless (puthash key (delete elt entry) dbus-registered-objects-table)
  690. (remhash key dbus-registered-objects-table))
  691. ;; Remove match rule of signals.
  692. (when (eq type :signal)
  693. (dbus-call-method
  694. bus dbus-service-dbus dbus-path-dbus dbus-interface-dbus
  695. "RemoveMatch" (nth 4 elt)))))
  696. ;; Check, whether there is still a registered function or property
  697. ;; for the given service. If not, unregister the service from the
  698. ;; bus.
  699. (when (and service (memq type '(:method :property))
  700. (not (catch :found
  701. (progn
  702. (maphash
  703. (lambda (k v)
  704. (dolist (e v)
  705. (ignore-errors
  706. (and
  707. ;; Bus.
  708. (equal bus (cadr k))
  709. ;; Service.
  710. (string-equal service (cadr e))
  711. ;; Non-empty object path.
  712. (nth 2 e)
  713. (throw :found t)))))
  714. dbus-registered-objects-table)
  715. nil))))
  716. (dbus-unregister-service bus service))
  717. ;; Return.
  718. ret))
  719. ;;; D-Bus type conversion.
  720. (defun dbus-string-to-byte-array (string)
  721. "Transforms STRING to list (:array :byte c1 :byte c2 ...).
  722. STRING shall be UTF8 coded."
  723. (if (zerop (length string))
  724. '(:array :signature "y")
  725. (let (result)
  726. (dolist (elt (string-to-list string) (append '(:array) result))
  727. (setq result (append result (list :byte elt)))))))
  728. (defun dbus-byte-array-to-string (byte-array &optional multibyte)
  729. "Transforms BYTE-ARRAY into UTF8 coded string.
  730. BYTE-ARRAY must be a list of structure (c1 c2 ...), or a byte
  731. array as produced by `dbus-string-to-byte-array'. The resulting
  732. string is unibyte encoded, unless MULTIBYTE is non-nil."
  733. (apply
  734. (if multibyte 'string 'unibyte-string)
  735. (if (equal byte-array '(:array :signature "y"))
  736. nil
  737. (let (result)
  738. (dolist (elt byte-array result)
  739. (when (characterp elt) (setq result (append result `(,elt)))))))))
  740. (defun dbus-escape-as-identifier (string)
  741. "Escape an arbitrary STRING so it follows the rules for a C identifier.
  742. The escaped string can be used as object path component, interface element
  743. component, bus name component or member name in D-Bus.
  744. The escaping consists of replacing all non-alphanumerics, and the
  745. first character if it's a digit, with an underscore and two
  746. lower-case hex digits:
  747. \"0123abc_xyz\\x01\\xff\" -> \"_30123abc_5fxyz_01_ff\"
  748. i.e. similar to URI encoding, but with \"_\" taking the role of \"%\",
  749. and a smaller allowed set. As a special case, \"\" is escaped to
  750. \"_\".
  751. Returns the escaped string. Algorithm taken from
  752. telepathy-glib's `tp_escape_as_identifier'."
  753. (if (zerop (length string))
  754. "_"
  755. (replace-regexp-in-string
  756. "^[0-9]\\|[^A-Za-z0-9]"
  757. (lambda (x) (format "_%2x" (aref x 0)))
  758. string)))
  759. (defun dbus-unescape-from-identifier (string)
  760. "Retrieve the original string from the encoded STRING as unibyte string.
  761. STRING must have been encoded with `dbus-escape-as-identifier'."
  762. (if (string-equal string "_")
  763. ""
  764. (replace-regexp-in-string
  765. "_.."
  766. (lambda (x) (byte-to-string (string-to-number (substring x 1) 16)))
  767. string)))
  768. ;;; D-Bus events.
  769. (defun dbus-check-event (event)
  770. "Checks whether EVENT is a well formed D-Bus event.
  771. EVENT is a list which starts with symbol `dbus-event':
  772. (dbus-event BUS TYPE SERIAL SERVICE PATH INTERFACE MEMBER HANDLER &rest ARGS)
  773. BUS identifies the D-Bus the message is coming from. It is
  774. either a Lisp symbol, `:system' or `:session', or a string
  775. denoting the bus address. TYPE is the D-Bus message type which
  776. has caused the event, SERIAL is the serial number of the received
  777. D-Bus message. SERVICE and PATH are the unique name and the
  778. object path of the D-Bus object emitting the message. INTERFACE
  779. and MEMBER denote the message which has been sent. HANDLER is
  780. the function which has been registered for this message. ARGS
  781. are the arguments passed to HANDLER, when it is called during
  782. event handling in `dbus-handle-event'.
  783. This function raises a `dbus-error' signal in case the event is
  784. not well formed."
  785. (when dbus-debug (message "DBus-Event %s" event))
  786. (unless (and (listp event)
  787. (eq (car event) 'dbus-event)
  788. ;; Bus symbol.
  789. (or (symbolp (nth 1 event))
  790. (stringp (nth 1 event)))
  791. ;; Type.
  792. (and (natnump (nth 2 event))
  793. (< dbus-message-type-invalid (nth 2 event)))
  794. ;; Serial.
  795. (natnump (nth 3 event))
  796. ;; Service.
  797. (or (= dbus-message-type-method-return (nth 2 event))
  798. (= dbus-message-type-error (nth 2 event))
  799. (or (stringp (nth 4 event))
  800. (null (nth 4 event))))
  801. ;; Object path.
  802. (or (= dbus-message-type-method-return (nth 2 event))
  803. (= dbus-message-type-error (nth 2 event))
  804. (stringp (nth 5 event)))
  805. ;; Interface.
  806. (or (= dbus-message-type-method-return (nth 2 event))
  807. (= dbus-message-type-error (nth 2 event))
  808. (stringp (nth 6 event)))
  809. ;; Member.
  810. (or (= dbus-message-type-method-return (nth 2 event))
  811. (= dbus-message-type-error (nth 2 event))
  812. (stringp (nth 7 event)))
  813. ;; Handler.
  814. (functionp (nth 8 event)))
  815. (signal 'dbus-error (list "Not a valid D-Bus event" event))))
  816. ;;;###autoload
  817. (defun dbus-handle-event (event)
  818. "Handle events from the D-Bus.
  819. EVENT is a D-Bus event, see `dbus-check-event'. HANDLER, being
  820. part of the event, is called with arguments ARGS.
  821. If the HANDLER returns a `dbus-error', it is propagated as return message."
  822. (interactive "e")
  823. (condition-case err
  824. (let (result)
  825. ;; We ignore not well-formed events.
  826. (dbus-check-event event)
  827. ;; Error messages must be propagated.
  828. (when (= dbus-message-type-error (nth 2 event))
  829. (signal 'dbus-error (nthcdr 9 event)))
  830. ;; Apply the handler.
  831. (setq result (apply (nth 8 event) (nthcdr 9 event)))
  832. ;; Return a message when it is a message call.
  833. (when (= dbus-message-type-method-call (nth 2 event))
  834. (dbus-ignore-errors
  835. (if (eq result :ignore)
  836. (dbus-method-return-internal
  837. (nth 1 event) (nth 4 event) (nth 3 event))
  838. (apply 'dbus-method-return-internal
  839. (nth 1 event) (nth 4 event) (nth 3 event)
  840. (if (consp result) result (list result)))))))
  841. ;; Error handling.
  842. (dbus-error
  843. ;; Return an error message when it is a message call.
  844. (when (= dbus-message-type-method-call (nth 2 event))
  845. (dbus-ignore-errors
  846. (dbus-method-error-internal
  847. (nth 1 event) (nth 4 event) (nth 3 event) (cadr err))))
  848. ;; Propagate D-Bus error messages.
  849. (run-hook-with-args 'dbus-event-error-functions event err)
  850. (when dbus-debug
  851. (signal (car err) (cdr err))))))
  852. (defun dbus-event-bus-name (event)
  853. "Return the bus name the event is coming from.
  854. The result is either a Lisp symbol, `:system' or `:session', or a
  855. string denoting the bus address. EVENT is a D-Bus event, see
  856. `dbus-check-event'. This function raises a `dbus-error' signal
  857. in case the event is not well formed."
  858. (dbus-check-event event)
  859. (nth 1 event))
  860. (defun dbus-event-message-type (event)
  861. "Return the message type of the corresponding D-Bus message.
  862. The result is a number. EVENT is a D-Bus event, see
  863. `dbus-check-event'. This function raises a `dbus-error' signal
  864. in case the event is not well formed."
  865. (dbus-check-event event)
  866. (nth 2 event))
  867. (defun dbus-event-serial-number (event)
  868. "Return the serial number of the corresponding D-Bus message.
  869. The result is a number. The serial number is needed for
  870. generating a reply message. EVENT is a D-Bus event, see
  871. `dbus-check-event'. This function raises a `dbus-error' signal
  872. in case the event is not well formed."
  873. (dbus-check-event event)
  874. (nth 3 event))
  875. (defun dbus-event-service-name (event)
  876. "Return the name of the D-Bus object the event is coming from.
  877. The result is a string. EVENT is a D-Bus event, see `dbus-check-event'.
  878. This function raises a `dbus-error' signal in case the event is
  879. not well formed."
  880. (dbus-check-event event)
  881. (nth 4 event))
  882. (defun dbus-event-path-name (event)
  883. "Return the object path of the D-Bus object the event is coming from.
  884. The result is a string. EVENT is a D-Bus event, see `dbus-check-event'.
  885. This function raises a `dbus-error' signal in case the event is
  886. not well formed."
  887. (dbus-check-event event)
  888. (nth 5 event))
  889. (defun dbus-event-interface-name (event)
  890. "Return the interface name of the D-Bus object the event is coming from.
  891. The result is a string. EVENT is a D-Bus event, see `dbus-check-event'.
  892. This function raises a `dbus-error' signal in case the event is
  893. not well formed."
  894. (dbus-check-event event)
  895. (nth 6 event))
  896. (defun dbus-event-member-name (event)
  897. "Return the member name the event is coming from.
  898. It is either a signal name or a method name. The result is a
  899. string. EVENT is a D-Bus event, see `dbus-check-event'. This
  900. function raises a `dbus-error' signal in case the event is not
  901. well formed."
  902. (dbus-check-event event)
  903. (nth 7 event))
  904. ;;; D-Bus registered names.
  905. (defun dbus-list-activatable-names (&optional bus)
  906. "Return the D-Bus service names which can be activated as list.
  907. If BUS is left nil, `:system' is assumed. The result is a list
  908. of strings, which is nil when there are no activatable service
  909. names at all."
  910. (dbus-ignore-errors
  911. (dbus-call-method
  912. (or bus :system) dbus-service-dbus
  913. dbus-path-dbus dbus-interface-dbus "ListActivatableNames")))
  914. (defun dbus-list-names (bus)
  915. "Return the service names registered at D-Bus BUS.
  916. The result is a list of strings, which is nil when there are no
  917. registered service names at all. Well known names are strings
  918. like \"org.freedesktop.DBus\". Names starting with \":\" are
  919. unique names for services."
  920. (dbus-ignore-errors
  921. (dbus-call-method
  922. bus dbus-service-dbus dbus-path-dbus dbus-interface-dbus "ListNames")))
  923. (defun dbus-list-known-names (bus)
  924. "Retrieve all services which correspond to a known name in BUS.
  925. A service has a known name if it doesn't start with \":\"."
  926. (let (result)
  927. (dolist (name (dbus-list-names bus) result)
  928. (unless (string-equal ":" (substring name 0 1))
  929. (add-to-list 'result name 'append)))))
  930. (defun dbus-list-queued-owners (bus service)
  931. "Return the unique names registered at D-Bus BUS and queued for SERVICE.
  932. The result is a list of strings, or nil when there are no
  933. queued name owners service names at all."
  934. (dbus-ignore-errors
  935. (dbus-call-method
  936. bus dbus-service-dbus dbus-path-dbus
  937. dbus-interface-dbus "ListQueuedOwners" service)))
  938. (defun dbus-get-name-owner (bus service)
  939. "Return the name owner of SERVICE registered at D-Bus BUS.
  940. The result is either a string, or nil if there is no name owner."
  941. (dbus-ignore-errors
  942. (dbus-call-method
  943. bus dbus-service-dbus dbus-path-dbus
  944. dbus-interface-dbus "GetNameOwner" service)))
  945. (defun dbus-ping (bus service &optional timeout)
  946. "Check whether SERVICE is registered for D-Bus BUS.
  947. TIMEOUT, a nonnegative integer, specifies the maximum number of
  948. milliseconds `dbus-ping' must return. The default value is 25,000.
  949. Note, that this autoloads SERVICE if it is not running yet. If
  950. it shall be checked whether SERVICE is already running, one shall
  951. apply
  952. (member service \(dbus-list-known-names bus))"
  953. ;; "Ping" raises a D-Bus error if SERVICE does not exist.
  954. ;; Otherwise, it returns silently with nil.
  955. (condition-case nil
  956. (not
  957. (if (natnump timeout)
  958. (dbus-call-method
  959. bus service dbus-path-dbus dbus-interface-peer
  960. "Ping" :timeout timeout)
  961. (dbus-call-method
  962. bus service dbus-path-dbus dbus-interface-peer "Ping")))
  963. (dbus-error nil)))
  964. (defun dbus-peer-handler ()
  965. "Default handler for the \"org.freedesktop.DBus.Peer\" interface.
  966. It will be registered for all objects created by `dbus-register-service'."
  967. (let* ((last-input-event last-input-event)
  968. (method (dbus-event-member-name last-input-event)))
  969. (cond
  970. ;; "Ping" does not return an output parameter.
  971. ((string-equal method "Ping")
  972. :ignore)
  973. ;; "GetMachineId" returns "s".
  974. ((string-equal method "GetMachineId")
  975. (signal
  976. 'dbus-error
  977. (list
  978. (format "%s.GetMachineId not implemented" dbus-interface-peer)))))))
  979. ;;; D-Bus introspection.
  980. (defun dbus-introspect (bus service path)
  981. "Return all interfaces and sub-nodes of SERVICE,
  982. registered at object path PATH at bus BUS.
  983. BUS is either a Lisp symbol, `:system' or `:session', or a string
  984. denoting the bus address. SERVICE must be a known service name,
  985. and PATH must be a valid object path. The last two parameters
  986. are strings. The result, the introspection data, is a string in
  987. XML format."
  988. ;; We don't want to raise errors.
  989. (dbus-ignore-errors
  990. (dbus-call-method
  991. bus service path dbus-interface-introspectable "Introspect"
  992. :timeout 1000)))
  993. (defun dbus-introspect-xml (bus service path)
  994. "Return the introspection data of SERVICE in D-Bus BUS at object path PATH.
  995. The data are a parsed list. The root object is a \"node\",
  996. representing the object path PATH. The root object can contain
  997. \"interface\" and further \"node\" objects."
  998. ;; We don't want to raise errors.
  999. (xml-node-name
  1000. (ignore-errors
  1001. (with-temp-buffer
  1002. (insert (dbus-introspect bus service path))
  1003. (xml-parse-region (point-min) (point-max))))))
  1004. (defun dbus-introspect-get-attribute (object attribute)
  1005. "Return the ATTRIBUTE value of D-Bus introspection OBJECT.
  1006. ATTRIBUTE must be a string according to the attribute names in
  1007. the D-Bus specification."
  1008. (xml-get-attribute-or-nil object (intern attribute)))
  1009. (defun dbus-introspect-get-node-names (bus service path)
  1010. "Return all node names of SERVICE in D-Bus BUS at object path PATH.
  1011. It returns a list of strings. The node names stand for further
  1012. object paths of the D-Bus service."
  1013. (let ((object (dbus-introspect-xml bus service path))
  1014. result)
  1015. (dolist (elt (xml-get-children object 'node) result)
  1016. (add-to-list
  1017. 'result (dbus-introspect-get-attribute elt "name") 'append))))
  1018. (defun dbus-introspect-get-all-nodes (bus service path)
  1019. "Return all node names of SERVICE in D-Bus BUS at object path PATH.
  1020. It returns a list of strings, which are further object paths of SERVICE."
  1021. (let ((result (list path)))
  1022. (dolist (elt
  1023. (dbus-introspect-get-node-names bus service path)
  1024. result)
  1025. (setq elt (expand-file-name elt path))
  1026. (setq result
  1027. (append result (dbus-introspect-get-all-nodes bus service elt))))))
  1028. (defun dbus-introspect-get-interface-names (bus service path)
  1029. "Return all interface names of SERVICE in D-Bus BUS at object path PATH.
  1030. It returns a list of strings.
  1031. There will be always the default interface
  1032. \"org.freedesktop.DBus.Introspectable\". Another default
  1033. interface is \"org.freedesktop.DBus.Properties\". If present,
  1034. \"interface\" objects can also have \"property\" objects as
  1035. children, beside \"method\" and \"signal\" objects."
  1036. (let ((object (dbus-introspect-xml bus service path))
  1037. result)
  1038. (dolist (elt (xml-get-children object 'interface) result)
  1039. (add-to-list
  1040. 'result (dbus-introspect-get-attribute elt "name") 'append))))
  1041. (defun dbus-introspect-get-interface (bus service path interface)
  1042. "Return the INTERFACE of SERVICE in D-Bus BUS at object path PATH.
  1043. The return value is an XML object. INTERFACE must be a string,
  1044. element of the list returned by `dbus-introspect-get-interface-names'.
  1045. The resulting \"interface\" object can contain \"method\", \"signal\",
  1046. \"property\" and \"annotation\" children."
  1047. (let ((elt (xml-get-children
  1048. (dbus-introspect-xml bus service path) 'interface)))
  1049. (while (and elt
  1050. (not (string-equal
  1051. interface
  1052. (dbus-introspect-get-attribute (car elt) "name"))))
  1053. (setq elt (cdr elt)))
  1054. (car elt)))
  1055. (defun dbus-introspect-get-method-names (bus service path interface)
  1056. "Return a list of strings of all method names of INTERFACE.
  1057. SERVICE is a service of D-Bus BUS at object path PATH."
  1058. (let ((object (dbus-introspect-get-interface bus service path interface))
  1059. result)
  1060. (dolist (elt (xml-get-children object 'method) result)
  1061. (add-to-list
  1062. 'result (dbus-introspect-get-attribute elt "name") 'append))))
  1063. (defun dbus-introspect-get-method (bus service path interface method)
  1064. "Return method METHOD of interface INTERFACE as XML object.
  1065. It must be located at SERVICE in D-Bus BUS at object path PATH.
  1066. METHOD must be a string, element of the list returned by
  1067. `dbus-introspect-get-method-names'. The resulting \"method\"
  1068. object can contain \"arg\" and \"annotation\" children."
  1069. (let ((elt (xml-get-children
  1070. (dbus-introspect-get-interface bus service path interface)
  1071. 'method)))
  1072. (while (and elt
  1073. (not (string-equal
  1074. method (dbus-introspect-get-attribute (car elt) "name"))))
  1075. (setq elt (cdr elt)))
  1076. (car elt)))
  1077. (defun dbus-introspect-get-signal-names (bus service path interface)
  1078. "Return a list of strings of all signal names of INTERFACE.
  1079. SERVICE is a service of D-Bus BUS at object path PATH."
  1080. (let ((object (dbus-introspect-get-interface bus service path interface))
  1081. result)
  1082. (dolist (elt (xml-get-children object 'signal) result)
  1083. (add-to-list
  1084. 'result (dbus-introspect-get-attribute elt "name") 'append))))
  1085. (defun dbus-introspect-get-signal (bus service path interface signal)
  1086. "Return signal SIGNAL of interface INTERFACE as XML object.
  1087. It must be located at SERVICE in D-Bus BUS at object path PATH.
  1088. SIGNAL must be a string, element of the list returned by
  1089. `dbus-introspect-get-signal-names'. The resulting \"signal\"
  1090. object can contain \"arg\" and \"annotation\" children."
  1091. (let ((elt (xml-get-children
  1092. (dbus-introspect-get-interface bus service path interface)
  1093. 'signal)))
  1094. (while (and elt
  1095. (not (string-equal
  1096. signal (dbus-introspect-get-attribute (car elt) "name"))))
  1097. (setq elt (cdr elt)))
  1098. (car elt)))
  1099. (defun dbus-introspect-get-property-names (bus service path interface)
  1100. "Return a list of strings of all property names of INTERFACE.
  1101. SERVICE is a service of D-Bus BUS at object path PATH."
  1102. (let ((object (dbus-introspect-get-interface bus service path interface))
  1103. result)
  1104. (dolist (elt (xml-get-children object 'property) result)
  1105. (add-to-list
  1106. 'result (dbus-introspect-get-attribute elt "name") 'append))))
  1107. (defun dbus-introspect-get-property (bus service path interface property)
  1108. "This function returns PROPERTY of INTERFACE as XML object.
  1109. It must be located at SERVICE in D-Bus BUS at object path PATH.
  1110. PROPERTY must be a string, element of the list returned by
  1111. `dbus-introspect-get-property-names'. The resulting PROPERTY
  1112. object can contain \

Large files files are truncated, but you can click here to view the full file