1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-06 06:20:55 -08:00

Make D-Bus properties type safe

* doc/misc/dbus.texi (Properties and Annotations):
Precise dbus-get-property and dbus-set-property.
(Type Conversion): Explain :byte and :boolean type conversion.
(Errors and Events): dbus-ignore-errors returns nil when there is
a D-Bus error.  Remove dbus-show-dbus-errors.

* etc/NEWS: Some D-Bus relevant changes.

* lisp/net/dbus.el (dbus-show-dbus-errors): Remove.
(dbus-ignore-errors): Replay implamentation without that variable.
(dbus-check-arguments): New defun.
(dbus-list-activatable-names, dbus-list-names)
(dbus-list-queued-owners, dbus-get-name-owner, dbus-introspect)
(dbus-get-all-properties, dbus-get-all-managed-objects): Don't debug.
(dbus-get-property, dbus-set-property): Propagate errors.
(dbus-register-property): Check for valid VALUE.
(dbus-property-handler): Simplify.

* src/dbusbind.c (Fdbus_message_internal): Adapt docstring.
Handle DBUS_MESSAGE_TYPE_INVALID.

* test/lisp/net/dbus-tests.el (dbus-show-dbus-errors): Don't declare.
(dbus-test06-register-property)
(dbus-test06-register-property-emits-signal): Adapt tests.
This commit is contained in:
Michael Albinus 2020-09-20 16:44:17 +02:00
parent 209dfa11a4
commit f8624fb834
5 changed files with 201 additions and 186 deletions

View file

@ -732,8 +732,8 @@ A @var{property} value can be retrieved by the function
@defun dbus-get-property bus service path interface property @defun dbus-get-property bus service path interface property
This function returns the value of @var{property} of @var{interface}. This function returns the value of @var{property} of @var{interface}.
It will be checked at @var{bus}, @var{service}, @var{path}. The It will be checked at @var{bus}, @var{service}, @var{path}. The
result can be any valid D-Bus value, or @code{nil} if there is no result can be any valid D-Bus value. If there is no @var{property},
@var{property}. Example: or @var{property} cannot be read, an error is raised. Example:
@lisp @lisp
(dbus-get-property (dbus-get-property
@ -749,7 +749,7 @@ This function sets the value of @var{property} of @var{interface} to
@var{value}. It will be checked at @var{bus}, @var{service}, @var{value}. It will be checked at @var{bus}, @var{service},
@var{path}. @var{value} can be preceded by a @var{type} symbol. When @var{path}. @var{value} can be preceded by a @var{type} symbol. When
the value is successfully set, this function returns @var{value}. the value is successfully set, this function returns @var{value}.
Otherwise, it returns @code{nil}. Example: Example:
@lisp @lisp
(dbus-set-property (dbus-set-property
@ -761,10 +761,11 @@ Otherwise, it returns @code{nil}. Example:
@end defun @end defun
@defun dbus-get-all-properties bus service path interface @defun dbus-get-all-properties bus service path interface
This function returns all properties of @var{interface}. It will be This function returns all readable properties of @var{interface}. It
checked at @var{bus}, @var{service}, @var{path}. The result is a list will be checked at @var{bus}, @var{service}, @var{path}. The result
of cons. Every cons contains the name of the property, and its value. is a list of cons cells. Every cons cell contains the name of the
If there are no properties, @code{nil} is returned. Example: property, and its value. If there are no properties, @code{nil} is
returned. Example:
@lisp @lisp
(dbus-get-all-properties (dbus-get-all-properties
@ -782,9 +783,9 @@ If there are no properties, @code{nil} is returned. Example:
@defun dbus-get-all-managed-objects bus service path @defun dbus-get-all-managed-objects bus service path
This function returns all objects at @var{bus}, @var{service}, This function returns all objects at @var{bus}, @var{service},
@var{path}, and the children of @var{path}. The result is a list of @var{path}, and the children of @var{path}. The result is a list of
objects. Every object is a cons of an existing path name, and the objects. Every object is a cons cell of an existing path name, and
list of available interface objects. An interface object is another the list of available interface objects. An interface object is
cons, whose car is the interface name and cdr is the list of another cons, whose car is the interface name and cdr is the list of
properties as returned by @code{dbus-get-all-properties} for that path properties as returned by @code{dbus-get-all-properties} for that path
and interface. Example: and interface. Example:
@ -1031,6 +1032,12 @@ represented outside this range are stripped off. For example,
@code{:byte ?\C-x} or @code{:byte ?\M-\C-x}. Signed and unsigned @code{:byte ?\C-x} or @code{:byte ?\M-\C-x}. Signed and unsigned
integer D-Bus types expect a corresponding integer value. integer D-Bus types expect a corresponding integer value.
All basic D-Bus types based on a number are truncated to their type
range. For example, @code{:byte 1025} is equal to @code{:byte 1}.
If typed explicitly, a non-@code{nil} boolean value like
{@code{:boolean 'symbol} is handled like @code{t} or @code{:boolean t}.
A D-Bus compound type is always represented as a list. The @sc{car} A D-Bus compound type is always represented as a list. The @sc{car}
of this list can be the type symbol @code{:array}, @code{:variant}, of this list can be the type symbol @code{:array}, @code{:variant},
@code{:struct} or @code{:dict-entry}, which would result in a @code{:struct} or @code{:dict-entry}, which would result in a
@ -1955,8 +1962,9 @@ appended to the @code{dbus-error}.
@defspec dbus-ignore-errors forms@dots{} @defspec dbus-ignore-errors forms@dots{}
This executes @var{forms} exactly like a @code{progn}, except that This executes @var{forms} exactly like a @code{progn}, except that
@code{dbus-error} errors are ignored during the @var{forms}. These @code{dbus-error} errors are ignored during the @var{forms} (the macro
errors can be made visible when @code{dbus-debug} is set to @code{t}. returns @code{nil} then). These errors can be made visible when
@code{dbus-debug} is set to non-@code{nil}.
@end defspec @end defspec
Incoming D-Bus messages are handled as Emacs events, @pxref{Misc Incoming D-Bus messages are handled as Emacs events, @pxref{Misc
@ -2035,11 +2043,10 @@ This function returns the member name of the D-Bus object @var{event}
is coming from. It is either a signal name or a method name. is coming from. It is either a signal name or a method name.
@end defun @end defun
@vindex dbus-show-dbus-errors D-Bus errors are not propagated during event handling, because it is
D-Bus error messages are not propagated during event handling, because usually not desired. D-Bus errors in events can be made visible by
it is usually not desired. D-Bus errors in events can be made visible setting the variable @code{dbus-debug} to non-@code{nil}. They can
by setting the user option @code{dbus-show-dbus-errors} to also be handled by a hook function.
non-@code{nil}. They can also be handled by a hook function.
@defvar dbus-event-error-functions @defvar dbus-event-error-functions
This hook variable keeps a list of functions, which are called when a This hook variable keeps a list of functions, which are called when a

View file

@ -375,7 +375,7 @@ tags to be considered as well.
** Gnus ** Gnus
+++ +++
*** New variable 'gnus-global-groups'. *** New user option 'gnus-global-groups'.
Gnus handles private groups differently from public (i.e., NNTP-like) Gnus handles private groups differently from public (i.e., NNTP-like)
groups. Most importantly, Gnus doesn't download external images from groups. Most importantly, Gnus doesn't download external images from
mail-like groups. This can be overridden by putting group names in mail-like groups. This can be overridden by putting group names in
@ -389,8 +389,8 @@ You can now score based on the relative age of an article with the new
+++ +++
*** User-defined scoring is now possible. *** User-defined scoring is now possible.
The new type is 'score-fn'. More information in The new type is 'score-fn'. More information in the Gnus manual node
(Gnus)Score File Format. "(gnus) Score File Format".
+++ +++
*** New backend 'nnselect'. *** New backend 'nnselect'.
@ -1045,7 +1045,7 @@ whose default value is 5.
*** New user option 'reveal-auto-hide'. *** New user option 'reveal-auto-hide'.
If non-nil (the default), revealed text is automatically hidden when If non-nil (the default), revealed text is automatically hidden when
point leaves the text. If nil, the text is not hidden again. Instead point leaves the text. If nil, the text is not hidden again. Instead
`M-x reveal-hide-revealed' can be used to hide all the revealed text. 'M-x reveal-hide-revealed' can be used to hide all the revealed text.
+++ +++
*** New user options to control the look of line/column numbers in the mode line. *** New user options to control the look of line/column numbers in the mode line.
@ -1205,7 +1205,7 @@ The old names are now obsolete.
+++ +++
*** Property values can be typed explicitly. *** Property values can be typed explicitly.
'dbus-register-property' and 'dbus-set-property' accept now optional 'dbus-register-property' and 'dbus-set-property' accept now optional
type symbols. type symbols. Both functions propagate D-Bus errors.
+++ +++
*** Registered properties can have the new access type ':write'. *** Registered properties can have the new access type ':write'.
@ -1215,9 +1215,7 @@ type symbols.
+++ +++
*** D-Bus errors, which have been converted from incoming D-Bus error *** D-Bus errors, which have been converted from incoming D-Bus error
messages, contain the error name of that message now. They can be messages, contain the error name of that message now.
made visible by setting user variable 'dbus-show-dbus-errors' to
non-nil, even if protected by 'dbus-ignore-errors' otherwise.
--- ---
*** D-Bus events keep the type information of their arguments. *** D-Bus events keep the type information of their arguments.
@ -1557,7 +1555,7 @@ non-nil value. Please report any bugs you find while using the native
image API via 'M-x report-emacs-bug'. image API via 'M-x report-emacs-bug'.
--- ---
** The variable 'make-pointer-invisible' is now honored on macOS. ** The user option 'make-pointer-invisible' is now honored on macOS.
---------------------------------------------------------------------- ----------------------------------------------------------------------

View file

@ -162,11 +162,6 @@ See URL `https://dbus.freedesktop.org/doc/dbus-specification.html#standard-inter
:link '(custom-manual "(dbus)Top") :link '(custom-manual "(dbus)Top")
:version "28.1") :version "28.1")
(defcustom dbus-show-dbus-errors nil
"Propagate incoming D-Bus error messages."
:version "28.1"
:type 'boolean)
(defconst dbus-error-dbus "org.freedesktop.DBus.Error" (defconst dbus-error-dbus "org.freedesktop.DBus.Error"
"The namespace for default error names. "The namespace for default error names.
See /usr/include/dbus-1.0/dbus/dbus-protocol.h.") See /usr/include/dbus-1.0/dbus/dbus-protocol.h.")
@ -225,17 +220,11 @@ shall be subdirectories of this path.")
(defmacro dbus-ignore-errors (&rest body) (defmacro dbus-ignore-errors (&rest body)
"Execute BODY; signal D-Bus error when `dbus-debug' is non-nil. "Execute BODY; signal D-Bus error when `dbus-debug' is non-nil.
Signals also D-Bus error when `dbus-show-dbus-errors' is non-nil Otherwise, return result of last form in BODY, or all other errors."
and a D-Bus error message has arrived. Otherwise, return result
of last form in BODY, or all other errors."
(declare (indent 0) (debug t)) (declare (indent 0) (debug t))
`(condition-case err `(condition-case err
(progn ,@body) (progn ,@body)
(dbus-error (dbus-error (when dbus-debug (signal (car err) (cdr err))))))
(when (or dbus-debug
(and dbus-show-dbus-errors
(= dbus-message-type-error (nth 2 last-input-event))))
(signal (car err) (cdr err))))))
(defvar dbus-event-error-functions '(dbus-notice-synchronous-call-errors) (defvar dbus-event-error-functions '(dbus-notice-synchronous-call-errors)
"Functions to be called when a D-Bus error happens in the event handler. "Functions to be called when a D-Bus error happens in the event handler.
@ -548,6 +537,21 @@ This is an internal function, it shall not be used outside dbus.el."
(apply #'dbus-message-internal dbus-message-type-error (apply #'dbus-message-internal dbus-message-type-error
bus service serial error-name args)) bus service serial error-name args))
(defun dbus-check-arguments (bus service &rest args)
"Check arguments ARGS by side effect.
BUS, SERVICE and ARGS have the same format as in `dbus-call-method'.
Any wrong argument triggers a D-Bus error. Otherwise, return t.
This is an internal function, it shall not be used outside dbus.el."
(or (featurep 'dbusbind)
(signal 'dbus-error (list "Emacs not compiled with dbus support")))
(or (memq bus '(:system :session)) (stringp bus)
(signal 'wrong-type-argument (list 'keywordp bus)))
(or (stringp service)
(signal 'wrong-type-argument (list 'stringp service)))
(apply #'dbus-message-internal dbus-message-type-invalid bus service args))
;;; Hash table of registered functions. ;;; Hash table of registered functions.
@ -1200,10 +1204,11 @@ function signals a `dbus-error' if the event is not well formed."
BUS defaults to `:system' when nil or omitted. The result is a BUS defaults to `:system' when nil or omitted. The result is a
list of strings, which is nil when there are no activatable list of strings, which is nil when there are no activatable
service names at all." service names at all."
(let (dbus-debug)
(dbus-ignore-errors (dbus-ignore-errors
(dbus-call-method (dbus-call-method
(or bus :system) dbus-service-dbus (or bus :system) dbus-service-dbus
dbus-path-dbus dbus-interface-dbus "ListActivatableNames"))) dbus-path-dbus dbus-interface-dbus "ListActivatableNames"))))
(defun dbus-list-names (bus) (defun dbus-list-names (bus)
"Return the service names registered at D-Bus BUS. "Return the service names registered at D-Bus BUS.
@ -1211,9 +1216,10 @@ The result is a list of strings, which is nil when there are no
registered service names at all. Well known names are strings registered service names at all. Well known names are strings
like \"org.freedesktop.DBus\". Names starting with \":\" are like \"org.freedesktop.DBus\". Names starting with \":\" are
unique names for services." unique names for services."
(let (dbus-debug)
(dbus-ignore-errors (dbus-ignore-errors
(dbus-call-method (dbus-call-method
bus dbus-service-dbus dbus-path-dbus dbus-interface-dbus "ListNames"))) bus dbus-service-dbus dbus-path-dbus dbus-interface-dbus "ListNames"))))
(defun dbus-list-known-names (bus) (defun dbus-list-known-names (bus)
"Retrieve all services which correspond to a known name in BUS. "Retrieve all services which correspond to a known name in BUS.
@ -1226,18 +1232,20 @@ A service has a known name if it doesn't start with \":\"."
"Return the unique names registered at D-Bus BUS and queued for SERVICE. "Return the unique names registered at D-Bus BUS and queued for SERVICE.
The result is a list of strings, or nil when there are no queued The result is a list of strings, or nil when there are no queued
name owner service names at all." name owner service names at all."
(let (dbus-debug)
(dbus-ignore-errors (dbus-ignore-errors
(dbus-call-method (dbus-call-method
bus dbus-service-dbus dbus-path-dbus bus dbus-service-dbus dbus-path-dbus
dbus-interface-dbus "ListQueuedOwners" service))) dbus-interface-dbus "ListQueuedOwners" service))))
(defun dbus-get-name-owner (bus service) (defun dbus-get-name-owner (bus service)
"Return the name owner of SERVICE registered at D-Bus BUS. "Return the name owner of SERVICE registered at D-Bus BUS.
The result is either a string, or nil if there is no name owner." The result is either a string, or nil if there is no name owner."
(let (dbus-debug)
(dbus-ignore-errors (dbus-ignore-errors
(dbus-call-method (dbus-call-method
bus dbus-service-dbus dbus-path-dbus bus dbus-service-dbus dbus-path-dbus
dbus-interface-dbus "GetNameOwner" service))) dbus-interface-dbus "GetNameOwner" service))))
(defun dbus-ping (bus service &optional timeout) (defun dbus-ping (bus service &optional timeout)
"Check whether SERVICE is registered for D-Bus BUS. "Check whether SERVICE is registered for D-Bus BUS.
@ -1307,10 +1315,11 @@ and PATH must be a valid object path. The last two parameters
are strings. The result, the introspection data, is a string in are strings. The result, the introspection data, is a string in
XML format." XML format."
;; We don't want to raise errors. ;; We don't want to raise errors.
(let (dbus-debug)
(dbus-ignore-errors (dbus-ignore-errors
(dbus-call-method (dbus-call-method
bus service path dbus-interface-introspectable "Introspect" bus service path dbus-interface-introspectable "Introspect"
:timeout 1000))) :timeout 1000))))
(defalias 'dbus--parse-xml-buffer (defalias 'dbus--parse-xml-buffer
(if (libxml-available-p) (if (libxml-available-p)
@ -1512,12 +1521,11 @@ If NAME is a `signal' or a `property', DIRECTION is ignored."
"Return the value of PROPERTY of INTERFACE. "Return the value of PROPERTY of INTERFACE.
It will be checked at BUS, SERVICE, PATH. The result can be any It will be checked at BUS, SERVICE, PATH. The result can be any
valid D-Bus value, or nil if there is no PROPERTY, or PROPERTY cannot be read." valid D-Bus value, or nil if there is no PROPERTY, or PROPERTY cannot be read."
(dbus-ignore-errors
;; "Get" returns a variant, so we must use the `car'. ;; "Get" returns a variant, so we must use the `car'.
(car (car
(dbus-call-method (dbus-call-method
bus service path dbus-interface-properties bus service path dbus-interface-properties
"Get" :timeout 500 interface property)))) "Get" :timeout 500 interface property)))
(defun dbus-set-property (bus service path interface property &rest args) (defun dbus-set-property (bus service path interface property &rest args)
"Set value of PROPERTY of INTERFACE to VALUE. "Set value of PROPERTY of INTERFACE to VALUE.
@ -1527,26 +1535,30 @@ property's access type is not `:write', return VALUE. Otherwise,
return nil. return nil.
\(dbus-set-property BUS SERVICE PATH INTERFACE PROPERTY [TYPE] VALUE)" \(dbus-set-property BUS SERVICE PATH INTERFACE PROPERTY [TYPE] VALUE)"
(dbus-ignore-errors
;; "Set" requires a variant. ;; "Set" requires a variant.
(dbus-call-method (dbus-call-method
bus service path dbus-interface-properties bus service path dbus-interface-properties
"Set" :timeout 500 interface property (cons :variant args)) "Set" :timeout 500 interface property (cons :variant args))
;; Return VALUE. ;; Return VALUE.
(or (dbus-get-property bus service path interface property) (condition-case err
(if (keywordp (car args)) (cadr args) (car args))))) (dbus-get-property bus service path interface property)
(dbus-error
(if (string-equal dbus-error-access-denied (cadr err))
(car args)
(signal (car err) (cdr err))))))
(defun dbus-get-all-properties (bus service path interface) (defun dbus-get-all-properties (bus service path interface)
"Return all properties of INTERFACE at BUS, SERVICE, PATH. "Return all properties of INTERFACE at BUS, SERVICE, PATH.
The result is a list of entries. Every entry is a cons of the The result is a list of entries. Every entry is a cons of the
name of the property, and its value. If there are no properties, name of the property, and its value. If there are no properties,
nil is returned." nil is returned."
(let (dbus-debug)
(dbus-ignore-errors (dbus-ignore-errors
;; "GetAll" returns "a{sv}". ;; "GetAll" returns "a{sv}".
(mapcar (lambda (dict) (mapcar (lambda (dict)
(cons (car dict) (caadr dict))) (cons (car dict) (caadr dict)))
(dbus-call-method bus service path dbus-interface-properties (dbus-call-method bus service path dbus-interface-properties
"GetAll" :timeout 500 interface)))) "GetAll" :timeout 500 interface)))))
(defun dbus-get-this-registered-property (bus _service path interface property) (defun dbus-get-this-registered-property (bus _service path interface property)
"Return PROPERTY entry of `dbus-registered-objects-table'. "Return PROPERTY entry of `dbus-registered-objects-table'.
@ -1631,6 +1643,7 @@ clients from discovering the still incomplete interface.
(setq value (list type value))) (setq value (list type value)))
(setq value (if (member (car value) dbus-compound-types) (setq value (if (member (car value) dbus-compound-types)
(list :variant value) (cons :variant value))) (list :variant value) (cons :variant value)))
(dbus-check-arguments bus service value)
;; Add handlers for the three property-related methods. ;; Add handlers for the three property-related methods.
(dbus-register-method (dbus-register-method
@ -1647,19 +1660,6 @@ clients from discovering the still incomplete interface.
(unless (or dont-register-service (member service (dbus-list-names bus))) (unless (or dont-register-service (member service (dbus-list-names bus)))
(dbus-register-service bus service)) (dbus-register-service bus service))
;; Send the PropertiesChanged signal.
(when emits-signal
(dbus-send-signal
bus service path dbus-interface-properties "PropertiesChanged"
;; changed_properties.
(if (eq access :write)
'(:array: :signature "{sv}")
`(:array (:dict-entry ,property ,value)))
;; invalidated_properties.
(if (eq access :write)
`(:array ,property)
'(:array))))
;; Create a hash table entry. We use nil for the unique name, ;; Create a hash table entry. We use nil for the unique name,
;; because the property might be accessed from anybody. ;; because the property might be accessed from anybody.
(let ((key (list :property bus interface property)) (let ((key (list :property bus interface property))
@ -1670,6 +1670,14 @@ clients from discovering the still incomplete interface.
bus service path interface property)))) bus service path interface property))))
(puthash key val dbus-registered-objects-table) (puthash key val dbus-registered-objects-table)
;; Set or Get the property, in order to validate the property's
;; value and to send the PropertiesChanged signal.
(when (member service (dbus-list-names bus))
(if (eq access :read)
(dbus-get-property bus service path interface property)
(apply
#'dbus-set-property bus service path interface property (cdr value))))
;; Return the object. ;; Return the object.
(list key (list service path))))) (list key (list service path)))))
@ -1704,7 +1712,7 @@ It will be registered for all objects created by `dbus-register-property'."
;; "Set" needs the third typed argument from `last-input-event'. ;; "Set" needs the third typed argument from `last-input-event'.
((string-equal method "Set") ((string-equal method "Set")
(let* ((value (nth 11 last-input-event)) (let* ((value (dbus-flatten-types (nth 11 last-input-event)))
(entry (dbus-get-this-registered-property (entry (dbus-get-this-registered-property
bus service path interface property)) bus service path interface property))
(object (car (last (car entry))))) (object (car (last (car entry)))))
@ -1721,8 +1729,7 @@ It will be registered for all objects created by `dbus-register-property'."
(cons (append (cons (append
(butlast (car entry)) (butlast (car entry))
;; Reuse ACCESS and EMITS-SIGNAL. ;; Reuse ACCESS and EMITS-SIGNAL.
(list (append (butlast object) (list (append (butlast object) (list value))))
(list (dbus-flatten-types value)))))
(dbus-get-other-registered-properties (dbus-get-other-registered-properties
bus service path interface property)) bus service path interface property))
dbus-registered-objects-table) dbus-registered-objects-table)
@ -1733,7 +1740,7 @@ It will be registered for all objects created by `dbus-register-property'."
;; changed_properties. ;; changed_properties.
(if (eq :write (car object)) (if (eq :write (car object))
'(:array: :signature "{sv}") '(:array: :signature "{sv}")
`(:array (:dict-entry ,property (:variant ,value)))) `(:array (:dict-entry ,property ,value)))
;; invalidated_properties. ;; invalidated_properties.
(if (eq :write (car object)) (if (eq :write (car object))
`(:array ,property) `(:array ,property)
@ -1804,10 +1811,11 @@ and \"org.freedesktop.DBus.Properties.GetAll\", which is slow."
(let ((result (let ((result
;; Direct call. Fails, if the target does not support the ;; Direct call. Fails, if the target does not support the
;; object manager interface. ;; object manager interface.
(let (dbus-debug)
(dbus-ignore-errors (dbus-ignore-errors
(dbus-call-method (dbus-call-method
bus service path dbus-interface-objectmanager bus service path dbus-interface-objectmanager
"GetManagedObjects" :timeout 1000)))) "GetManagedObjects" :timeout 1000)))))
(if result (if result
;; Massage the returned structure. ;; Massage the returned structure.

View file

@ -1269,6 +1269,10 @@ The following usages are expected:
(dbus-message-internal (dbus-message-internal
dbus-message-type-error BUS SERVICE SERIAL ERROR-NAME &rest ARGS) dbus-message-type-error BUS SERVICE SERIAL ERROR-NAME &rest ARGS)
`dbus-check-arguments': (does not send a message)
(dbus-message-internal
dbus-message-type-invalid BUS SERVICE &rest ARGS)
usage: (dbus-message-internal &rest REST) */) usage: (dbus-message-internal &rest REST) */)
(ptrdiff_t nargs, Lisp_Object *args) (ptrdiff_t nargs, Lisp_Object *args)
{ {
@ -1286,7 +1290,7 @@ usage: (dbus-message-internal &rest REST) */)
dbus_uint32_t serial = 0; dbus_uint32_t serial = 0;
unsigned int ui_serial; unsigned int ui_serial;
int timeout = -1; int timeout = -1;
ptrdiff_t count; ptrdiff_t count, count0;
char signature[DBUS_MAXIMUM_SIGNATURE_LENGTH]; char signature[DBUS_MAXIMUM_SIGNATURE_LENGTH];
/* Initialize parameters. */ /* Initialize parameters. */
@ -1296,7 +1300,7 @@ usage: (dbus-message-internal &rest REST) */)
handler = Qnil; handler = Qnil;
CHECK_FIXNAT (message_type); CHECK_FIXNAT (message_type);
if (! (DBUS_MESSAGE_TYPE_INVALID < XFIXNAT (message_type) if (! (DBUS_MESSAGE_TYPE_INVALID <= XFIXNAT (message_type)
&& XFIXNAT (message_type) < DBUS_NUM_MESSAGE_TYPES)) && XFIXNAT (message_type) < DBUS_NUM_MESSAGE_TYPES))
XD_SIGNAL2 (build_string ("Invalid message type"), message_type); XD_SIGNAL2 (build_string ("Invalid message type"), message_type);
mtype = XFIXNAT (message_type); mtype = XFIXNAT (message_type);
@ -1311,13 +1315,16 @@ usage: (dbus-message-internal &rest REST) */)
handler = args[6]; handler = args[6];
count = (mtype == DBUS_MESSAGE_TYPE_METHOD_CALL) ? 7 : 6; count = (mtype == DBUS_MESSAGE_TYPE_METHOD_CALL) ? 7 : 6;
} }
else /* DBUS_MESSAGE_TYPE_METHOD_RETURN, DBUS_MESSAGE_TYPE_ERROR */ else if ((mtype == DBUS_MESSAGE_TYPE_METHOD_RETURN)
|| (mtype == DBUS_MESSAGE_TYPE_ERROR))
{ {
serial = xd_extract_unsigned (args[3], TYPE_MAXIMUM (dbus_uint32_t)); serial = xd_extract_unsigned (args[3], TYPE_MAXIMUM (dbus_uint32_t));
if (mtype == DBUS_MESSAGE_TYPE_ERROR) if (mtype == DBUS_MESSAGE_TYPE_ERROR)
error_name = args[4]; error_name = args[4];
count = (mtype == DBUS_MESSAGE_TYPE_ERROR) ? 5 : 4; count = (mtype == DBUS_MESSAGE_TYPE_ERROR) ? 5 : 4;
} }
else /* DBUS_MESSAGE_TYPE_INVALID */
count = 3;
/* Check parameters. */ /* Check parameters. */
XD_DBUS_VALIDATE_BUS_ADDRESS (bus); XD_DBUS_VALIDATE_BUS_ADDRESS (bus);
@ -1367,7 +1374,7 @@ usage: (dbus-message-internal &rest REST) */)
XD_OBJECT_TO_STRING (service), XD_OBJECT_TO_STRING (service),
ui_serial); ui_serial);
break; break;
default: /* DBUS_MESSAGE_TYPE_ERROR */ case DBUS_MESSAGE_TYPE_ERROR:
ui_serial = serial; ui_serial = serial;
XD_DEBUG_MESSAGE ("%s %s %s %u %s", XD_DEBUG_MESSAGE ("%s %s %s %u %s",
XD_MESSAGE_TYPE_TO_STRING (mtype), XD_MESSAGE_TYPE_TO_STRING (mtype),
@ -1375,17 +1382,25 @@ usage: (dbus-message-internal &rest REST) */)
XD_OBJECT_TO_STRING (service), XD_OBJECT_TO_STRING (service),
ui_serial, ui_serial,
XD_OBJECT_TO_STRING (error_name)); XD_OBJECT_TO_STRING (error_name));
break;
default: /* DBUS_MESSAGE_TYPE_INVALID */
XD_DEBUG_MESSAGE ("%s %s %s",
XD_MESSAGE_TYPE_TO_STRING (mtype),
XD_OBJECT_TO_STRING (bus),
XD_OBJECT_TO_STRING (service));
} }
/* Retrieve bus address. */ /* Retrieve bus address. */
connection = xd_get_connection_address (bus); connection = xd_get_connection_address (bus);
/* Create the D-Bus message. */ /* Create the D-Bus message. Since DBUS_MESSAGE_TYPE_INVALID is not
dmessage = dbus_message_new (mtype); a valid message type, we mockup it with DBUS_MESSAGE_TYPE_SIGNAL. */
dmessage = dbus_message_new
((mtype == DBUS_MESSAGE_TYPE_INVALID) ? DBUS_MESSAGE_TYPE_SIGNAL : mtype);
if (dmessage == NULL) if (dmessage == NULL)
XD_SIGNAL1 (build_string ("Unable to create a new message")); XD_SIGNAL1 (build_string ("Unable to create a new message"));
if (STRINGP (service)) if ((STRINGP (service)) && (mtype != DBUS_MESSAGE_TYPE_INVALID))
{ {
if (mtype != DBUS_MESSAGE_TYPE_SIGNAL) if (mtype != DBUS_MESSAGE_TYPE_SIGNAL)
/* Set destination. */ /* Set destination. */
@ -1427,7 +1442,8 @@ usage: (dbus-message-internal &rest REST) */)
XD_SIGNAL1 (build_string ("Unable to set the message parameter")); XD_SIGNAL1 (build_string ("Unable to set the message parameter"));
} }
else /* DBUS_MESSAGE_TYPE_METHOD_RETURN, DBUS_MESSAGE_TYPE_ERROR */ else if ((mtype == DBUS_MESSAGE_TYPE_METHOD_RETURN)
|| (mtype == DBUS_MESSAGE_TYPE_ERROR))
{ {
if (!dbus_message_set_reply_serial (dmessage, serial)) if (!dbus_message_set_reply_serial (dmessage, serial))
XD_SIGNAL1 (build_string ("Unable to create a return message")); XD_SIGNAL1 (build_string ("Unable to create a return message"));
@ -1449,6 +1465,7 @@ usage: (dbus-message-internal &rest REST) */)
dbus_message_iter_init_append (dmessage, &iter); dbus_message_iter_init_append (dmessage, &iter);
/* Append parameters to the message. */ /* Append parameters to the message. */
count0 = count - 1;
for (; count < nargs; ++count) for (; count < nargs; ++count)
{ {
dtype = XD_OBJECT_TO_DBUS_TYPE (args[count]); dtype = XD_OBJECT_TO_DBUS_TYPE (args[count]);
@ -1456,15 +1473,17 @@ usage: (dbus-message-internal &rest REST) */)
{ {
XD_DEBUG_VALID_LISP_OBJECT_P (args[count]); XD_DEBUG_VALID_LISP_OBJECT_P (args[count]);
XD_DEBUG_VALID_LISP_OBJECT_P (args[count+1]); XD_DEBUG_VALID_LISP_OBJECT_P (args[count+1]);
XD_DEBUG_MESSAGE ("Parameter%"pD"d %s %s", count - 4, XD_DEBUG_MESSAGE ("Parameter%"pD"d: %s Parameter%"pD"d: %s",
count - count0,
XD_OBJECT_TO_STRING (args[count]), XD_OBJECT_TO_STRING (args[count]),
count + 1 - count0,
XD_OBJECT_TO_STRING (args[count+1])); XD_OBJECT_TO_STRING (args[count+1]));
++count; ++count;
} }
else else
{ {
XD_DEBUG_VALID_LISP_OBJECT_P (args[count]); XD_DEBUG_VALID_LISP_OBJECT_P (args[count]);
XD_DEBUG_MESSAGE ("Parameter%"pD"d %s", count - 4, XD_DEBUG_MESSAGE ("Parameter%"pD"d: %s", count - count0,
XD_OBJECT_TO_STRING (args[count])); XD_OBJECT_TO_STRING (args[count]));
} }
@ -1475,7 +1494,10 @@ usage: (dbus-message-internal &rest REST) */)
xd_append_arg (dtype, args[count], &iter); xd_append_arg (dtype, args[count], &iter);
} }
if (!NILP (handler)) if (mtype == DBUS_MESSAGE_TYPE_INVALID)
result = Qt;
else if (!NILP (handler))
{ {
/* Send the message. The message is just added to the outgoing /* Send the message. The message is just added to the outgoing
message queue. */ message queue. */
@ -1500,6 +1522,7 @@ usage: (dbus-message-internal &rest REST) */)
result = Qnil; result = Qnil;
} }
if (mtype != DBUS_MESSAGE_TYPE_INVALID)
XD_DEBUG_MESSAGE ("Message sent: %s", XD_OBJECT_TO_STRING (result)); XD_DEBUG_MESSAGE ("Message sent: %s", XD_OBJECT_TO_STRING (result));
/* Cleanup. */ /* Cleanup. */
@ -1548,7 +1571,7 @@ xd_read_message_1 (DBusConnection *connection, Lisp_Object bus)
} }
/* Read message type, message serial, unique name, object path, /* Read message type, message serial, unique name, object path,
interface and member from the message. */ interface, member and error name from the message. */
mtype = dbus_message_get_type (dmessage); mtype = dbus_message_get_type (dmessage);
ui_serial = serial = ui_serial = serial =
((mtype == DBUS_MESSAGE_TYPE_METHOD_RETURN) ((mtype == DBUS_MESSAGE_TYPE_METHOD_RETURN)
@ -1590,7 +1613,8 @@ xd_read_message_1 (DBusConnection *connection, Lisp_Object bus)
event.arg = event.arg =
Fcons (value, Fcons (value,
(mtype == DBUS_MESSAGE_TYPE_ERROR) (mtype == DBUS_MESSAGE_TYPE_ERROR)
? Fcons (list2 (QCstring, build_string (error_name)), args) : args); ? Fcons (list2 (QCstring, build_string (error_name)), args)
: args);
} }
else /* DBUS_MESSAGE_TYPE_METHOD_CALL, DBUS_MESSAGE_TYPE_SIGNAL. */ else /* DBUS_MESSAGE_TYPE_METHOD_CALL, DBUS_MESSAGE_TYPE_SIGNAL. */

View file

@ -25,8 +25,6 @@
(defvar dbus-debug nil) (defvar dbus-debug nil)
(declare-function dbus-get-unique-name "dbusbind.c" (bus)) (declare-function dbus-get-unique-name "dbusbind.c" (bus))
(setq dbus-show-dbus-errors nil)
(defconst dbus--test-enabled-session-bus (defconst dbus--test-enabled-session-bus
(and (featurep 'dbusbind) (and (featurep 'dbusbind)
(dbus-ignore-errors (dbus-get-unique-name :session))) (dbus-ignore-errors (dbus-get-unique-name :session)))
@ -383,11 +381,6 @@ This includes initialization and closing the bus."
"foo")) "foo"))
;; Due to `:read' access type, we don't get a proper reply ;; Due to `:read' access type, we don't get a proper reply
;; from `dbus-set-property'. ;; from `dbus-set-property'.
(should-not
(dbus-set-property
:session dbus--test-service dbus--test-path
dbus--test-interface property1 "foofoo"))
(let ((dbus-show-dbus-errors t))
(should (should
(equal (equal
(butlast (butlast
@ -395,7 +388,7 @@ This includes initialization and closing the bus."
(dbus-set-property (dbus-set-property
:session dbus--test-service dbus--test-path :session dbus--test-service dbus--test-path
dbus--test-interface property1 "foofoo"))) dbus--test-interface property1 "foofoo")))
`(dbus-error ,dbus-error-property-read-only)))) `(dbus-error ,dbus-error-property-read-only)))
(should (should
(string-equal (string-equal
(dbus-get-property (dbus-get-property
@ -413,11 +406,6 @@ This includes initialization and closing the bus."
(,dbus--test-service ,dbus--test-path)))) (,dbus--test-service ,dbus--test-path))))
;; Due to `:write' access type, we don't get a proper reply ;; Due to `:write' access type, we don't get a proper reply
;; from `dbus-get-property'. ;; from `dbus-get-property'.
(should-not
(dbus-get-property
:session dbus--test-service dbus--test-path
dbus--test-interface property2))
(let ((dbus-show-dbus-errors t))
(should (should
(equal (equal
(butlast (butlast
@ -425,17 +413,22 @@ This includes initialization and closing the bus."
(dbus-get-property (dbus-get-property
:session dbus--test-service dbus--test-path :session dbus--test-service dbus--test-path
dbus--test-interface property2))) dbus--test-interface property2)))
`(dbus-error ,dbus-error-access-denied)))) `(dbus-error ,dbus-error-access-denied)))
(should (should
(string-equal (string-equal
(dbus-set-property (dbus-set-property
:session dbus--test-service dbus--test-path :session dbus--test-service dbus--test-path
dbus--test-interface property2 "barbar") dbus--test-interface property2 "barbar")
"barbar")) "barbar"))
(should-not ;; Due to `:write' access type. ;; Still `:write' access type.
(should
(equal
(butlast
(should-error
(dbus-get-property (dbus-get-property
:session dbus--test-service dbus--test-path :session dbus--test-service dbus--test-path
dbus--test-interface property2)) dbus--test-interface property2)))
`(dbus-error ,dbus-error-access-denied)))
;; `:readwrite' property, typed value (Bug#43252). ;; `:readwrite' property, typed value (Bug#43252).
(should (should
@ -465,11 +458,6 @@ This includes initialization and closing the bus."
"/baz/baz")) "/baz/baz"))
;; Not registered property. ;; Not registered property.
(should-not
(dbus-get-property
:session dbus--test-service dbus--test-path
dbus--test-interface property4))
(let ((dbus-show-dbus-errors t))
(should (should
(equal (equal
(butlast (butlast
@ -477,12 +465,7 @@ This includes initialization and closing the bus."
(dbus-get-property (dbus-get-property
:session dbus--test-service dbus--test-path :session dbus--test-service dbus--test-path
dbus--test-interface property4))) dbus--test-interface property4)))
`(dbus-error ,dbus-error-unknown-property)))) `(dbus-error ,dbus-error-unknown-property)))
(should-not
(dbus-set-property
:session dbus--test-service dbus--test-path
dbus--test-interface property4 "foobarbaz"))
(let ((dbus-show-dbus-errors t))
(should (should
(equal (equal
(butlast (butlast
@ -490,7 +473,7 @@ This includes initialization and closing the bus."
(dbus-set-property (dbus-set-property
:session dbus--test-service dbus--test-path :session dbus--test-service dbus--test-path
dbus--test-interface property4 "foobarbaz"))) dbus--test-interface property4 "foobarbaz")))
`(dbus-error ,dbus-error-unknown-property)))) `(dbus-error ,dbus-error-unknown-property)))
;; `dbus-get-all-properties'. We cannot retrieve a value for ;; `dbus-get-all-properties'. We cannot retrieve a value for
;; the property with `:write' access type. ;; the property with `:write' access type.
@ -516,11 +499,6 @@ This includes initialization and closing the bus."
;; Unregister property. ;; Unregister property.
(should (dbus-unregister-object registered)) (should (dbus-unregister-object registered))
(should-not (dbus-unregister-object registered)) (should-not (dbus-unregister-object registered))
(should-not
(dbus-get-property
:session dbus--test-service dbus--test-path
dbus--test-interface property1))
(let ((dbus-show-dbus-errors t))
(should (should
(equal (equal
(butlast (butlast
@ -528,7 +506,7 @@ This includes initialization and closing the bus."
(dbus-get-property (dbus-get-property
:session dbus--test-service dbus--test-path :session dbus--test-service dbus--test-path
dbus--test-interface property1))) dbus--test-interface property1)))
`(dbus-error ,dbus-error-unknown-property))))) `(dbus-error ,dbus-error-unknown-property))))
;; Cleanup. ;; Cleanup.
(dbus-unregister-service :session dbus--test-service))) (dbus-unregister-service :session dbus--test-service)))
@ -745,7 +723,7 @@ This includes initialization and closing the bus."
(read-event nil nil 0.1))) (read-event nil nil 0.1)))
(should (should
(equal (equal
dbus--test-signal-received `(((,property ((((1) (2) (3)))))) ()))) dbus--test-signal-received `(((,property ((1 2 3)))) ())))
(should (should
(equal (equal