dbus_bytestream/
message.rs

1//! Functions for creating and modifying messages to send across the message bus.
2use std::ops::DerefMut;
3use std::cell::RefCell;
4
5use dbus_serialize::types::{Path,Variant,Value,BasicValue,Signature};
6
7use marshal::{Marshal,pad_to_multiple};
8use demarshal::{demarshal,DemarshalError};
9
10#[derive(Debug,Default,PartialEq,Eq)]
11pub struct MessageType(pub u8);
12pub const MESSAGE_TYPE_INVALID : MessageType        = MessageType(0);
13pub const MESSAGE_TYPE_METHOD_CALL : MessageType    = MessageType(1);
14pub const MESSAGE_TYPE_METHOD_RETURN : MessageType  = MessageType(2);
15pub const MESSAGE_TYPE_ERROR : MessageType          = MessageType(3);
16pub const MESSAGE_TYPE_SIGNAL : MessageType         = MessageType(4);
17
18pub const HEADER_FIELD_INVALID : u8     = 0;
19pub const HEADER_FIELD_PATH: u8         = 1;
20pub const HEADER_FIELD_INTERFACE: u8    = 2;
21pub const HEADER_FIELD_MEMBER: u8       = 3;
22pub const HEADER_FIELD_ERROR_NAME: u8   = 4;
23pub const HEADER_FIELD_REPLY_SERIAL: u8 = 5;
24pub const HEADER_FIELD_DESTINATION: u8  = 6;
25pub const HEADER_FIELD_SENDER: u8       = 7;
26pub const HEADER_FIELD_SIGNATURE: u8    = 8;
27
28pub const FLAGS_NO_REPLY_EXPECTED : u8  = 1;
29
30#[derive(Debug)]
31pub struct HeaderField (
32    pub u8,
33    pub Variant
34);
35
36impl Marshal for HeaderField {
37    fn dbus_encode(&self, buf: &mut Vec<u8>) -> usize {
38        pad_to_multiple(buf, 8);
39        let start_len = buf.len();
40        let code = self.0 as u8;
41        code.dbus_encode(buf);
42        self.1.dbus_encode(buf);
43        buf.len() - start_len
44    }
45    fn get_type(&self) -> String {
46        "(yv)".to_owned()
47    }
48}
49
50/// Represents a received message from the message bus
51#[derive(Debug,Default)]
52pub struct Message {
53    pub big_endian: bool,
54    pub message_type: MessageType,
55    pub flags: u8,
56    pub version: u8,
57    pub serial: u32,
58    pub headers: Vec<HeaderField>,
59    pub body: Vec<u8>,
60
61    body_cache: RefCell<Option<Result<Option<Vec<Value>>, DemarshalError>>>
62}
63
64impl Marshal for Message {
65    fn dbus_encode (&self, buf: &mut Vec<u8>) -> usize {
66        let endian = if self.big_endian { 'B' as u8 } else { 'l' as u8 };
67        endian.dbus_encode(buf);
68        self.message_type.0.dbus_encode(buf);
69        self.flags.dbus_encode(buf);
70        self.version.dbus_encode(buf);
71        let len : u32 = self.body.len() as u32;
72        len.dbus_encode(buf);
73        self.serial.dbus_encode(buf);
74        self.headers.dbus_encode(buf);
75        pad_to_multiple(buf, 8);
76        0
77    }
78
79    fn get_type (&self) -> String {
80        panic!("Don't do that.")
81    }
82}
83
84/// Create a Message for a D-Bus method call.  Once a Message is created, arguments
85/// can be added with Message.add_arg
86pub fn create_method_call (dest: &str, path: &str, iface: &str, method: &str) -> Message {
87    Message {
88        big_endian: false,
89        message_type: MESSAGE_TYPE_METHOD_CALL,
90        flags: 0,
91        version: 1,
92        serial: 0,
93        headers: Vec::new(),
94        body: Vec::new(),
95
96        body_cache: RefCell::new(None),
97    }.add_header(HEADER_FIELD_DESTINATION,
98                 Variant::new(Value::from(dest), "s"))
99     .add_header(HEADER_FIELD_PATH,
100                 Variant::new(Value::BasicValue(BasicValue::ObjectPath(Path(path.to_owned()))), "o"))
101     .add_header(HEADER_FIELD_INTERFACE,
102                 Variant::new(Value::from(iface), "s"))
103     .add_header(HEADER_FIELD_MEMBER,
104                 Variant::new(Value::from(method), "s"))
105}
106
107/// Create a Message for a D-Bus method return.  Once created, return values can be added
108/// with Message.add_arg
109pub fn create_method_return(reply_serial: u32) -> Message {
110    Message {
111        big_endian: false,
112        message_type: MESSAGE_TYPE_METHOD_RETURN,
113        flags: 0,
114        version: 1,
115        serial: 0,
116        headers: Vec::new(),
117        body: Vec::new(),
118
119        body_cache: RefCell::new(None),
120    }.add_header(HEADER_FIELD_REPLY_SERIAL,
121                 Variant::new(Value::from(reply_serial), "u"))
122}
123
124/// Create a Message for a D-Bus error.  Once created, return values can be added
125/// with Message.add_arg
126pub fn create_error(error_name: &str, reply_serial: u32) -> Message {
127    Message {
128        big_endian: false,
129        message_type: MESSAGE_TYPE_ERROR,
130        flags: 0,
131        version: 1,
132        serial: 0,
133        headers: Vec::new(),
134        body: Vec::new(),
135
136        body_cache: RefCell::new(None),
137    }.add_header(HEADER_FIELD_REPLY_SERIAL,
138                 Variant::new(Value::from(reply_serial), "u"))
139     .add_header(HEADER_FIELD_ERROR_NAME,
140                 Variant::new(Value::from(error_name), "s"))
141}
142
143/// Create a Message for a D-Bus signal.  Once created, return values can be added
144/// with Message.add_arg
145pub fn create_signal(path: &str, interface: &str, member: &str) -> Message {
146    Message {
147        big_endian: false,
148        message_type: MESSAGE_TYPE_SIGNAL,
149        flags: 0,
150        version: 1,
151        serial: 0,
152        headers: Vec::new(),
153        body: Vec::new(),
154
155        body_cache: RefCell::new(None),
156    }.add_header(HEADER_FIELD_PATH,
157                 Variant::new(Value::BasicValue(BasicValue::ObjectPath(Path(path.to_owned()))), "o"))
158     .add_header(HEADER_FIELD_INTERFACE,
159                 Variant::new(Value::from(interface), "s"))
160     .add_header(HEADER_FIELD_MEMBER,
161                 Variant::new(Value::from(member), "s"))
162}
163
164impl Message {
165    /// Add the given argument to the Message.  Accepts anything that implements the Marshal
166    /// trait, which is most basic types, as well as the general-purpose
167    /// dbus_serialize::types::Value enum.
168    ///
169    /// Note that these calls can be chained together to add multiple arguments, see the example
170    ///
171    /// # Examples
172    /// ```
173    /// dbus_bytestream::message::create_method_call("foo", "/bar", "baz", "bloop")
174    ///     .add_arg(&1)
175    ///     .add_arg(&"string");
176    /// ```
177    pub fn add_arg(mut self, arg: &Marshal) -> Message {
178        if let None = self.get_header(HEADER_FIELD_SIGNATURE) {
179            let value = Value::BasicValue(BasicValue::Signature(Signature("".to_owned())));
180            let variant = Variant::new(value, "g");
181            self = self.add_header(HEADER_FIELD_SIGNATURE, variant);
182        };
183        {
184            let b : &mut Box<Value> = &mut self.get_header_mut(HEADER_FIELD_SIGNATURE).unwrap().object;
185            let val : &mut Value = b.deref_mut();
186            match *val {
187                Value::BasicValue(BasicValue::Signature(ref mut s)) => s.0.push_str(&arg.get_type()),
188                _ => panic!("Garbage in signature field")
189            };
190        }
191        arg.dbus_encode(&mut self.body);
192        self
193    }
194
195    pub fn get_header(&self, name: u8) -> Option<&Variant> {
196        self.headers.iter().position(|x| { x.0 == name })
197            .map(|idx| &self.headers[idx].1)
198    }
199
200    pub fn get_header_mut(&mut self, name: u8) -> Option<&mut Variant> {
201        match self.headers.iter().position(|x| { x.0 == name }) {
202            Some(idx) => Some(&mut self.headers[idx].1),
203            _ => None
204        }
205    }
206
207    pub fn add_header(mut self, name: u8, val: Variant) -> Message {
208        self.headers.push(HeaderField (name, val));
209        self
210    }
211
212    /// Get the sequence of Values from out of a Message.  Returns None if the message doesn't have
213    /// a body.
214    pub fn get_body(&self) -> Result<Option<Vec<Value>>,DemarshalError> {
215        if self.body.is_empty() {
216            return Ok(None);
217        }
218        let cached = self.body_cache.borrow().is_some();
219        if !cached {
220            // Get the signature out of the headers
221            let v = match self.headers.iter().position(|x| { x.0 == HEADER_FIELD_SIGNATURE }) {
222                Some(idx) => &self.headers[idx].1,
223                None => return Ok(None)
224            };
225
226            let sigval = match *v.object {
227                Value::BasicValue(BasicValue::Signature(ref x)) => x,
228                _ => return Ok(None)
229            };
230
231            let mut body = self.body.clone();
232            let mut sig = "(".to_owned() + &sigval.0 + ")";
233            let mut offset = 0;
234            *self.body_cache.borrow_mut() = Some((|| {
235                match try!(demarshal(&mut body, &mut offset, &mut sig)) {
236                    Value::Struct(x) => Ok(Some(x.objects)),
237                    x => panic!("Didn't get a struct: {:?}", x)
238                }
239            })());
240        }
241        self.body_cache.borrow().as_ref().unwrap().clone()
242    }
243}
244
245#[test]
246fn test_msg () {
247    create_method_call("foo", "bar", "baz", "floob")
248        .add_arg(&1)
249        .add_arg(&2);
250}