+(defun dbus-introspect-xml (bus service path)
+ "Return the introspection data of SERVICE in D-Bus BUS at object path PATH.
+The data are a parsed list. The root object is a \"node\",
+representing the object path PATH. The root object can contain
+\"interface\" and further \"node\" objects."
+ ;; We don't want to raise errors.
+ (xml-node-name
+ (ignore-errors
+ (with-temp-buffer
+ (insert (dbus-introspect bus service path))
+ (xml-parse-region (point-min) (point-max))))))
+
+(defun dbus-introspect-get-attribute (object attribute)
+ "Return the ATTRIBUTE value of D-Bus introspection OBJECT.
+ATTRIBUTE must be a string according to the attribute names in
+the D-Bus specification."
+ (xml-get-attribute-or-nil object (intern attribute)))
+
+(defun dbus-introspect-get-node-names (bus service path)
+ "Return all node names of SERVICE in D-Bus BUS at object path PATH.
+It returns a list of strings. The node names stand for further
+object paths of the D-Bus service."
+ (let ((object (dbus-introspect-xml bus service path))
+ result)
+ (dolist (elt (xml-get-children object 'node) result)
+ (add-to-list
+ 'result (dbus-introspect-get-attribute elt "name") 'append))))
+
+(defun dbus-introspect-get-all-nodes (bus service path)
+ "Return all node names of SERVICE in D-Bus BUS at object path PATH.
+It returns a list of strings, which are further object paths of SERVICE."
+ (let ((result (list path)))
+ (dolist (elt
+ (dbus-introspect-get-node-names bus service path)
+ result)
+ (setq elt (expand-file-name elt path))
+ (setq result
+ (append result (dbus-introspect-get-all-nodes bus service elt))))))
+
+(defun dbus-introspect-get-interface-names (bus service path)
+ "Return all interface names of SERVICE in D-Bus BUS at object path PATH.
+It returns a list of strings.
+
+There will be always the default interface
+\"org.freedesktop.DBus.Introspectable\". Another default
+interface is \"org.freedesktop.DBus.Properties\". If present,
+\"interface\" objects can also have \"property\" objects as
+children, beside \"method\" and \"signal\" objects."
+ (let ((object (dbus-introspect-xml bus service path))
+ result)
+ (dolist (elt (xml-get-children object 'interface) result)
+ (add-to-list
+ 'result (dbus-introspect-get-attribute elt "name") 'append))))
+
+(defun dbus-introspect-get-interface (bus service path interface)
+ "Return the INTERFACE of SERVICE in D-Bus BUS at object path PATH.
+The return value is an XML object. INTERFACE must be a string,
+element of the list returned by
+`dbus-introspect-get-interface-names'. The resulting
+\"interface\" object can contain \"method\", \"signal\",
+\"property\" and \"annotation\" children."
+ (let ((elt (xml-get-children
+ (dbus-introspect-xml bus service path) 'interface)))
+ (while (and elt
+ (not (string-equal
+ interface
+ (dbus-introspect-get-attribute (car elt) "name"))))
+ (setq elt (cdr elt)))
+ (car elt)))
+
+(defun dbus-introspect-get-method-names (bus service path interface)
+ "Return a list of strings of all method names of INTERFACE.
+SERVICE is a service of D-Bus BUS at object path PATH."
+ (let ((object (dbus-introspect-get-interface bus service path interface))
+ result)
+ (dolist (elt (xml-get-children object 'method) result)
+ (add-to-list
+ 'result (dbus-introspect-get-attribute elt "name") 'append))))
+
+(defun dbus-introspect-get-method (bus service path interface method)
+ "Return method METHOD of interface INTERFACE as XML object.
+It must be located at SERVICE in D-Bus BUS at object path PATH.
+METHOD must be a string, element of the list returned by
+`dbus-introspect-get-method-names'. The resulting \"method\"
+object can contain \"arg\" and \"annotation\" children."
+ (let ((elt (xml-get-children
+ (dbus-introspect-get-interface bus service path interface)
+ 'method)))
+ (while (and elt
+ (not (string-equal
+ method (dbus-introspect-get-attribute (car elt) "name"))))
+ (setq elt (cdr elt)))
+ (car elt)))
+
+(defun dbus-introspect-get-signal-names (bus service path interface)
+ "Return a list of strings of all signal names of INTERFACE.
+SERVICE is a service of D-Bus BUS at object path PATH."
+ (let ((object (dbus-introspect-get-interface bus service path interface))
+ result)
+ (dolist (elt (xml-get-children object 'signal) result)
+ (add-to-list
+ 'result (dbus-introspect-get-attribute elt "name") 'append))))
+
+(defun dbus-introspect-get-signal (bus service path interface signal)
+ "Return signal SIGNAL of interface INTERFACE as XML object.
+It must be located at SERVICE in D-Bus BUS at object path PATH.
+SIGNAL must be a string, element of the list returned by
+`dbus-introspect-get-signal-names'. The resulting \"signal\"
+object can contain \"arg\" and \"annotation\" children."
+ (let ((elt (xml-get-children
+ (dbus-introspect-get-interface bus service path interface)
+ 'signal)))
+ (while (and elt
+ (not (string-equal
+ signal (dbus-introspect-get-attribute (car elt) "name"))))
+ (setq elt (cdr elt)))
+ (car elt)))
+
+(defun dbus-introspect-get-property-names (bus service path interface)
+ "Return a list of strings of all property names of INTERFACE.
+SERVICE is a service of D-Bus BUS at object path PATH."
+ (let ((object (dbus-introspect-get-interface bus service path interface))
+ result)
+ (dolist (elt (xml-get-children object 'property) result)
+ (add-to-list
+ 'result (dbus-introspect-get-attribute elt "name") 'append))))
+
+(defun dbus-introspect-get-property (bus service path interface property)
+ "This function returns PROPERTY of INTERFACE as XML object.
+It must be located at SERVICE in D-Bus BUS at object path PATH.
+PROPERTY must be a string, element of the list returned by
+`dbus-introspect-get-property-names'. The resulting PROPERTY
+object can contain \"annotation\" children."
+ (let ((elt (xml-get-children
+ (dbus-introspect-get-interface bus service path interface)
+ 'property)))
+ (while (and elt
+ (not (string-equal
+ property
+ (dbus-introspect-get-attribute (car elt) "name"))))
+ (setq elt (cdr elt)))
+ (car elt)))
+
+(defun dbus-introspect-get-annotation-names
+ (bus service path interface &optional name)
+ "Return all annotation names as list of strings.
+If NAME is `nil', the annotations are children of INTERFACE,
+otherwise NAME must be a \"method\", \"signal\", or \"property\"
+object, where the annotations belong to."
+ (let ((object
+ (if name
+ (or (dbus-introspect-get-method bus service path interface name)
+ (dbus-introspect-get-signal bus service path interface name)
+ (dbus-introspect-get-property bus service path interface name))
+ (dbus-introspect-get-interface bus service path interface)))
+ result)
+ (dolist (elt (xml-get-children object 'annotation) result)
+ (add-to-list
+ 'result (dbus-introspect-get-attribute elt "name") 'append))))
+
+(defun dbus-introspect-get-annotation
+ (bus service path interface name annotation)
+ "Return ANNOTATION as XML object.
+If NAME is `nil', ANNOTATION is a child of INTERFACE, otherwise
+NAME must be the name of a \"method\", \"signal\", or
+\"property\" object, where the ANNOTATION belongs to."
+ (let ((elt (xml-get-children
+ (if name
+ (or (dbus-introspect-get-method
+ bus service path interface name)
+ (dbus-introspect-get-signal
+ bus service path interface name)
+ (dbus-introspect-get-property
+ bus service path interface name))
+ (dbus-introspect-get-interface bus service path interface))
+ 'annotation)))
+ (while (and elt
+ (not (string-equal
+ annotation
+ (dbus-introspect-get-attribute (car elt) "name"))))
+ (setq elt (cdr elt)))
+ (car elt)))
+
+(defun dbus-introspect-get-argument-names (bus service path interface name)
+ "Return a list of all argument names as list of strings.
+NAME must be a \"method\" or \"signal\" object.
+
+Argument names are optional, the function can return `nil'
+therefore, even if the method or signal has arguments."
+ (let ((object
+ (or (dbus-introspect-get-method bus service path interface name)
+ (dbus-introspect-get-signal bus service path interface name)))
+ result)
+ (dolist (elt (xml-get-children object 'arg) result)
+ (add-to-list
+ 'result (dbus-introspect-get-attribute elt "name") 'append))))
+
+(defun dbus-introspect-get-argument (bus service path interface name arg)
+ "Return argument ARG as XML object.
+NAME must be a \"method\" or \"signal\" object. ARG must be a
+string, element of the list returned by `dbus-introspect-get-argument-names'."
+ (let ((elt (xml-get-children
+ (or (dbus-introspect-get-method bus service path interface name)
+ (dbus-introspect-get-signal bus service path interface name))
+ 'arg)))
+ (while (and elt
+ (not (string-equal
+ arg (dbus-introspect-get-attribute (car elt) "name"))))
+ (setq elt (cdr elt)))
+ (car elt)))
+
+(defun dbus-introspect-get-signature
+ (bus service path interface name &optional direction)
+ "Return signature of a `method' or `signal', represented by NAME, as string.
+If NAME is a `method', DIRECTION can be either \"in\" or \"out\".
+If DIRECTION is `nil', \"in\" is assumed.
+
+If NAME is a `signal', and DIRECTION is non-`nil', DIRECTION must
+be \"out\"."
+ ;; For methods, we use "in" as default direction.
+ (let ((object (or (dbus-introspect-get-method
+ bus service path interface name)
+ (dbus-introspect-get-signal
+ bus service path interface name))))
+ (when (and (string-equal
+ "method" (dbus-introspect-get-attribute object "name"))
+ (not (stringp direction)))
+ (setq direction "in"))
+ ;; In signals, no direction is given.
+ (when (string-equal "signal" (dbus-introspect-get-attribute object "name"))
+ (setq direction nil))
+ ;; Collect the signatures.
+ (mapconcat
+ '(lambda (x)
+ (let ((arg (dbus-introspect-get-argument
+ bus service path interface name x)))
+ (if (or (not (stringp direction))
+ (string-equal
+ direction
+ (dbus-introspect-get-attribute arg "direction")))
+ (dbus-introspect-get-attribute arg "type")
+ "")))
+ (dbus-introspect-get-argument-names bus service path interface name)
+ "")))