dbus_message_parser/message/header/
header_struct.rs

1use super::{HeaderError, HeaderFields};
2use crate::{
3    message::{Message, MessageFlags, MessageType},
4    value::{Bus, Error, Interface, Member, ObjectPath, Type, Value},
5};
6use std::convert::TryInto;
7
8macro_rules! get_field {
9    ($(#[$meta:meta])* $function:ident, $field:ident, $return:ty $(,$as_ref:ident)?) => {
10        $(#[$meta])*
11        #[inline]
12        pub const fn $function(&self) -> Option<$return> {
13            self.fields.$field$(.$as_ref())?
14        }
15    };
16}
17
18macro_rules! has_field {
19    ($(#[$meta:meta])* $function:ident, $field:ident) => {
20        $(#[$meta])*
21        #[inline]
22        pub const fn $function(&self) -> bool {
23            self.fields.$field.is_some()
24        }
25    };
26}
27
28#[inline]
29fn check_header_fields(
30    message_type: MessageType,
31    fields: &HeaderFields,
32) -> Result<(), HeaderError> {
33    match message_type {
34        MessageType::MethodCall => {
35            if fields.path.is_none() {
36                return Err(HeaderError::MissingPath);
37            }
38
39            if fields.member.is_none() {
40                return Err(HeaderError::MissingMember);
41            }
42        }
43        MessageType::Signal => {
44            if fields.path.is_none() {
45                return Err(HeaderError::MissingPath);
46            }
47
48            if fields.interface.is_none() {
49                return Err(HeaderError::MissingInterface);
50            }
51
52            if fields.member.is_none() {
53                return Err(HeaderError::MissingMember);
54            }
55        }
56        MessageType::Error => {
57            if fields.error_name.is_none() {
58                return Err(HeaderError::MissingErrorName);
59            }
60
61            if fields.reply_serial.is_none() {
62                return Err(HeaderError::MissingReplySerial);
63            }
64        }
65        MessageType::MethodReturn => {
66            if fields.reply_serial.is_none() {
67                return Err(HeaderError::MissingReplySerial);
68            }
69        }
70    }
71    Ok(())
72}
73
74/// This represents a DBus [message header].
75///
76/// [message header]: https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol
77#[derive(Debug, Clone, PartialOrd, PartialEq, Ord, Eq)]
78pub struct Header {
79    pub(crate) is_le: bool,
80    pub(crate) message_type: MessageType,
81    pub(crate) message_flags: MessageFlags,
82    pub(crate) version: u8,
83    pub(crate) serial: u32,
84    pub(crate) fields: HeaderFields,
85}
86
87impl Header {
88    /// Create a [`MessageHeader`] object. It can fail if the required [header fields] are not
89    /// present.
90    ///
91    /// [header fields]: https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-header-fields
92    pub fn new(
93        is_le: bool,
94        message_type: MessageType,
95        message_flags: MessageFlags,
96        version: u8,
97        serial: u32,
98        fields: HeaderFields,
99    ) -> Result<Header, HeaderError> {
100        check_header_fields(message_type, &fields)?;
101
102        let header = Header {
103            is_le,
104            message_type,
105            message_flags,
106            version,
107            serial,
108            fields,
109        };
110
111        Ok(header)
112    }
113
114    /// Get the serial number.
115    #[inline]
116    pub const fn get_serial(&self) -> u32 {
117        self.serial
118    }
119
120    get_field!(
121        /// Get the [`path`], if there is one in the header field.
122        ///
123        /// [`path`]: crate::message::MessageHeaderFields::path
124        get_path,
125        path,
126        &ObjectPath,
127        as_ref
128    );
129
130    has_field!(
131        /// It is true if the message contains a [`path`] in the header fields.
132        ///
133        /// [`path`]: crate::message::MessageHeaderField::path
134        has_path,
135        path
136    );
137
138    get_field!(
139        /// Get the [`interface`], if there is one in the header field.
140        ///
141        /// [`interface`]: crate::message::MessageHeaderFields::interface
142        get_interface,
143        interface,
144        &Interface,
145        as_ref
146    );
147
148    has_field!(
149        /// It is true if the message contains an [`interface`] in the header fields.
150        ///
151        /// [`interface`]: crate::message::MessageHeaderFields::interface
152        has_interface,
153        interface
154    );
155
156    get_field!(
157        /// Get the [`member`], if there is one in the header field.
158        ///
159        /// [`member`]: crate::message::MessageHeaderFields::member
160        get_member,
161        member,
162        &Member,
163        as_ref
164    );
165
166    has_field!(
167        /// It is true if the message contains a [`member`] in the header fields.
168        ///
169        /// [`member`]: crate::message::MessageHeaderFields::member
170        has_member,
171        member
172    );
173
174    get_field!(
175        /// Get the [`error_name`], if there is one in the header field.
176        ///
177        /// [`error_name`]: crate::message::MessageHeaderFields::error_name
178        get_error_name,
179        error_name,
180        &Error,
181        as_ref
182    );
183
184    has_field!(
185        /// It is true if the message contains an [`error_name`] in the header fields.
186        ///
187        /// [`error_name`]: crate::message::MessageHeaderFields::error_name
188        has_error_name,
189        error_name
190    );
191
192    get_field!(
193        /// Get the [`destination`], if there is one in the header field.
194        ///
195        /// [`destination`]: crate::message::MessageHeaderFields::destination
196        get_destination,
197        destination,
198        &Bus,
199        as_ref
200    );
201
202    has_field!(
203        /// It is true if the message contains a [`destination`] in the header fields.
204        ///
205        /// [`destination`]: crate::message::MessageHeaderFields::destination
206        has_destination,
207        destination
208    );
209
210    get_field!(
211        /// Get the [`sender`], if there is one in the header field.
212        ///
213        /// [`sender`]: crate::message::MessageHeaderFields::sender
214        get_sender,
215        sender,
216        &Bus,
217        as_ref
218    );
219
220    has_field!(
221        /// It is true if the message contains a [`sender`] in the header fields.
222        ///
223        /// [`sender`]: crate::message::MessageHeaderFields::sender
224        has_sender,
225        sender
226    );
227
228    get_field!(
229        /// Get the [`reply_serial`], if there is one in the header field.
230        ///
231        /// [`reply_serial`]: crate::message::MessageHeaderFields::reply_serial
232        get_reply_serial,
233        reply_serial,
234        u32
235    );
236
237    has_field!(
238        /// It is true if the message contains a [`reply_serial`] in the header fields.
239        ///
240        /// [`reply_serial`]: crate::message::MessageHeaderFields::reply_serial
241        has_reply_serial,
242        reply_serial
243    );
244
245    /// Get the [`signature`], if there is one in the header field.
246    ///
247    /// [`signature`]: crate::message::MessageHeaderFields::signature
248    #[inline]
249    pub fn get_signature(&self) -> Option<&[Type]> {
250        self.fields.signature.as_deref()
251    }
252
253    has_field!(
254        /// It is true if the message contains a [`signature`] in the header fields.
255        ///
256        /// [`signature`]: crate::message::MessageHeaderFields::signature
257        has_signature,
258        signature
259    );
260
261    #[cfg(target_family = "unix")]
262    get_field!(
263        /// Get the [`unix_fds`], if there is one in the header field.
264        ///
265        /// [`unix_fds`]: crate::message::MessageHeaderFields::unix_fds
266        get_unix_fds,
267        unix_fds,
268        u32
269    );
270
271    #[cfg(target_family = "unix")]
272    has_field!(
273        /// It is true if the message contains a [`unix_fds`] in the header fields.
274        ///
275        /// [`unix_fds`]: crate::message::MessageHeaderFields::unix_fds
276        has_unix_fds,
277        unix_fds
278    );
279
280    /// Create a message return from this [`Message`].
281    /// Only works if this [`Message`] is a [`MethodCall`].
282    ///
283    /// [`Message`]: crate::message::Message
284    /// [`MethodCall`]: crate::message::MessageType::MethodCall
285    pub fn method_return(&self) -> Result<Message, Message> {
286        if let MessageType::MethodCall = self.message_type {
287            let message_type = MessageType::MethodReturn;
288
289            let message_flags = MessageFlags::NO_REPLY_EXPECTED;
290
291            let mut fields = HeaderFields::default();
292
293            if let Some(sender) = self.get_sender() {
294                fields.destination = Some(sender.clone());
295            }
296
297            if let Some(destination) = self.get_destination() {
298                fields.sender = Some(destination.clone());
299            }
300
301            fields.reply_serial = Some(self.get_serial());
302
303            let header = Header {
304                is_le: self.is_le,
305                message_type,
306                message_flags,
307                version: 1,
308                serial: 0,
309                fields,
310            };
311            Ok(Message {
312                header,
313                body: Vec::new(),
314            })
315        } else {
316            Err(self.error(
317                "org.freedesktop.DBus.Error.MessageType".try_into().unwrap(),
318                "Message is not a method call".to_string(),
319            ))
320        }
321    }
322
323    /// Create a unknown property error message from this [`Message`].
324    ///
325    /// [`Message`]: crate::message::Message
326    pub fn unknown_property(&self, property: &str) -> Message {
327        let message = format!("does not have a property {}", property);
328        self.error(
329            "org.freedesktop.DBus.Error.UnknownProperty"
330                .try_into()
331                .unwrap(),
332            message,
333        )
334    }
335
336    /// Create a unknown path error message from this [`Message`].
337    ///
338    /// [`Message`]: crate::message::Message
339    pub fn unknown_path(&self) -> Option<Message> {
340        let path = self.get_path()?;
341        let message = format!("does not have a path {}", path);
342        let msg = self.error(
343            "org.freedesktop.DBus.Error.UnknownPath".try_into().unwrap(),
344            message,
345        );
346        Some(msg)
347    }
348
349    /// Create a unknown interface error message from this [`Message`].
350    ///
351    /// [`Message`]: crate::message::Message
352    pub fn unknown_interface(&self) -> Option<Message> {
353        let interface = self.get_interface()?;
354        let message = format!("does not have an interface {}", interface);
355        let msg = self.error(
356            "org.freedesktop.DBus.Error.UnknownInterface"
357                .try_into()
358                .unwrap(),
359            message,
360        );
361        Some(msg)
362    }
363
364    /// Create a unknown member error message from this [`Message`].
365    ///
366    /// [`Message`]: crate::message::Message
367    pub fn unknown_member(&self) -> Option<Message> {
368        let member = self.get_member()?;
369        let message = format!("does not have a member {}", member);
370        let msg = self.error(
371            "org.freedesktop.DBus.Error.UnknownMember"
372                .try_into()
373                .unwrap(),
374            message,
375        );
376        Some(msg)
377    }
378
379    /// Create an invalid args error message from this [`Message`].
380    ///
381    /// [`Message`]: crate::message::Message
382    pub fn invalid_args(&self, reason: String) -> Message {
383        self.error(
384            "org.freedesktop.DBus.Error.InvalidArgs".try_into().unwrap(),
385            reason,
386        )
387    }
388
389    /// Create an error message from this [`Message`].
390    ///
391    /// [`Message`]: crate::message::Message
392    pub fn error(&self, error: Error, message: String) -> Message {
393        let message_type = MessageType::Error;
394
395        let message_flags = MessageFlags::NO_REPLY_EXPECTED;
396
397        let mut fields = HeaderFields::default();
398
399        if let Some(sender) = self.get_sender() {
400            fields.destination = Some(sender.clone());
401        }
402
403        if let Some(destination) = self.get_destination() {
404            fields.sender = Some(destination.clone());
405        }
406
407        fields.reply_serial = Some(self.get_serial());
408        fields.error_name = Some(error);
409
410        let header = Header {
411            is_le: self.is_le,
412            message_type,
413            message_flags,
414            version: 1,
415            serial: 0,
416            fields,
417        };
418        Message {
419            header,
420            body: vec![Value::String(message)],
421        }
422    }
423
424    /// Get the message type.
425    pub fn get_type(&self) -> MessageType {
426        self.message_type
427    }
428}