| 1 | //! Contains structs and traits closely related to D-Bus messages. |
| 2 | |
| 3 | use std::{fmt, ptr}; |
| 4 | use super::{ffi, Error, libc, init_dbus}; |
| 5 | use crate::strings::{BusName, Path, Interface, Member, ErrorName}; |
| 6 | use std::ffi::CStr; |
| 7 | |
| 8 | use super::arg::{Append, AppendAll, IterAppend, ReadAll, Get, Iter, Arg, RefArg, TypeMismatchError}; |
| 9 | |
| 10 | #[derive (Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Hash)] |
| 11 | /// One of the four different message types. |
| 12 | pub enum MessageType { |
| 13 | /// This is a method call D-Bus message |
| 14 | MethodCall = 1, |
| 15 | /// This is a method return Ok D-Bus message, used when the method call message was successfully processed |
| 16 | MethodReturn = 2, |
| 17 | /// This is a method return with error D-Bus message, used when the method call message could not be handled |
| 18 | Error = 3, |
| 19 | /// This is a signal, usually sent to whoever wants to listen |
| 20 | Signal = 4, |
| 21 | } |
| 22 | |
| 23 | impl<'a> TryFrom<&'a str> for MessageType { |
| 24 | type Error = (); |
| 25 | |
| 26 | fn try_from(value: &'a str) -> Result<Self, <crate::message::MessageType as TryFrom<&'a str>>::Error> { |
| 27 | match value { |
| 28 | "error" => Ok(MessageType::Error), |
| 29 | "method_call" => Ok(MessageType::MethodCall), |
| 30 | "method_return" => Ok(MessageType::MethodReturn), |
| 31 | "signal" => Ok(MessageType::Signal), |
| 32 | _ => Err(()) |
| 33 | } |
| 34 | } |
| 35 | } |
| 36 | |
| 37 | mod signalargs; |
| 38 | pub use self::signalargs::SignalArgs; |
| 39 | |
| 40 | mod matchrule; |
| 41 | pub use self::matchrule::MatchRule; |
| 42 | use std::convert::TryFrom; |
| 43 | |
| 44 | mod parser; |
| 45 | pub use self::parser::Error as MatchRuleParserError; |
| 46 | |
| 47 | /// A D-Bus message. A message contains headers - usually destination address, path, interface and member, |
| 48 | /// and a list of arguments. |
| 49 | pub struct Message { |
| 50 | msg: *mut ffi::DBusMessage, |
| 51 | } |
| 52 | |
| 53 | unsafe impl Send for Message {} |
| 54 | |
| 55 | impl Message { |
| 56 | /// Creates a new method call message. |
| 57 | pub fn new_method_call<'d, 'p, 'i, 'm, D, P, I, M>(destination: D, path: P, iface: I, method: M) -> Result<Message, String> |
| 58 | where D: Into<BusName<'d>>, P: Into<Path<'p>>, I: Into<Interface<'i>>, M: Into<Member<'m>> { |
| 59 | init_dbus(); |
| 60 | let (d, p, i, m) = (destination.into(), path.into(), iface.into(), method.into()); |
| 61 | let ptr = unsafe { |
| 62 | ffi::dbus_message_new_method_call(d.as_ptr(), p.as_ptr(), i.as_ptr(), m.as_ptr()) |
| 63 | }; |
| 64 | if ptr.is_null() { Err("D-Bus error: dbus_message_new_method_call failed" .into()) } |
| 65 | else { Ok(Message { msg: ptr}) } |
| 66 | } |
| 67 | |
| 68 | /// Creates a new method call message. |
| 69 | pub fn method_call(destination: &BusName, path: &Path, iface: &Interface, name: &Member) -> Message { |
| 70 | init_dbus(); |
| 71 | let ptr = unsafe { |
| 72 | ffi::dbus_message_new_method_call(destination.as_ptr(), path.as_ptr(), |
| 73 | iface.as_ptr(), name.as_ptr()) |
| 74 | }; |
| 75 | if ptr.is_null() { panic!("D-Bus error: dbus_message_new_method_call failed" ) } |
| 76 | Message { msg: ptr} |
| 77 | } |
| 78 | |
| 79 | /// Creates a new message that is a replica of this message, but without a serial. |
| 80 | /// |
| 81 | /// May fail if out of memory or file descriptors. |
| 82 | pub fn duplicate(&self) -> Result<Self, String> { |
| 83 | let ptr = unsafe { |
| 84 | ffi::dbus_message_copy(self.msg) |
| 85 | }; |
| 86 | if ptr.is_null() { |
| 87 | Err("D-Bus error: dbus_message_copy failed" .into()) |
| 88 | } else { |
| 89 | Ok(Message { msg: ptr }) |
| 90 | } |
| 91 | } |
| 92 | |
| 93 | /// Creates a new method call message. |
| 94 | pub fn call_with_args<'d, 'p, 'i, 'm, A, D, P, I, M>(destination: D, path: P, iface: I, method: M, args: A) -> Message |
| 95 | where D: Into<BusName<'d>>, P: Into<Path<'p>>, I: Into<Interface<'i>>, M: Into<Member<'m>>, A: AppendAll { |
| 96 | let mut msg = Message::method_call(&destination.into(), &path.into(), &iface.into(), &method.into()); |
| 97 | msg.append_all(args); |
| 98 | msg |
| 99 | } |
| 100 | |
| 101 | /// Creates a new signal message. |
| 102 | pub fn new_signal<P, I, M>(path: P, iface: I, name: M) -> Result<Message, String> |
| 103 | where P: Into<String>, I: Into<String>, M: Into<String> { |
| 104 | init_dbus(); |
| 105 | |
| 106 | let p = Path::new(path)?; |
| 107 | let i = Interface::new(iface)?; |
| 108 | let m = Member::new(name)?; |
| 109 | |
| 110 | let ptr = unsafe { |
| 111 | ffi::dbus_message_new_signal(p.as_ptr(), i.as_ptr(), m.as_ptr()) |
| 112 | }; |
| 113 | if ptr.is_null() { Err("D-Bus error: dbus_message_new_signal failed" .into()) } |
| 114 | else { Ok(Message { msg: ptr}) } |
| 115 | } |
| 116 | |
| 117 | /// Creates a new signal message. |
| 118 | pub fn signal(path: &Path, iface: &Interface, name: &Member) -> Message { |
| 119 | init_dbus(); |
| 120 | let ptr = unsafe { |
| 121 | ffi::dbus_message_new_signal(path.as_ptr(), iface.as_ptr(), name.as_ptr()) |
| 122 | }; |
| 123 | if ptr.is_null() { panic!("D-Bus error: dbus_message_new_signal failed" ) } |
| 124 | Message { msg: ptr} |
| 125 | } |
| 126 | |
| 127 | /// Creates a method reply for this method call. |
| 128 | pub fn new_method_return(m: &Message) -> Option<Message> { |
| 129 | let ptr = unsafe { ffi::dbus_message_new_method_return(m.msg) }; |
| 130 | if ptr.is_null() { None } else { Some(Message { msg: ptr} ) } |
| 131 | } |
| 132 | |
| 133 | /// Creates a method return (reply) for this method call. |
| 134 | pub fn method_return(&self) -> Message { |
| 135 | let ptr = unsafe { ffi::dbus_message_new_method_return(self.msg) }; |
| 136 | if ptr.is_null() { panic!("D-Bus error: dbus_message_new_method_return failed" ) } |
| 137 | Message {msg: ptr} |
| 138 | } |
| 139 | |
| 140 | /// Creates a reply for a method call message. |
| 141 | /// |
| 142 | /// Panics if called for a message which is not a method call. |
| 143 | pub fn return_with_args<A: AppendAll>(&self, args: A) -> Message { |
| 144 | let mut m = self.method_return(); |
| 145 | m.append_all(args); |
| 146 | m |
| 147 | } |
| 148 | |
| 149 | /// Creates a new error reply |
| 150 | pub fn error(&self, error_name: &ErrorName, error_message: &CStr) -> Message { |
| 151 | let ptr = unsafe { ffi::dbus_message_new_error(self.msg, error_name.as_ptr(), error_message.as_ptr()) }; |
| 152 | if ptr.is_null() { panic!("D-Bus error: dbus_message_new_error failed" ) } |
| 153 | Message { msg: ptr} |
| 154 | } |
| 155 | |
| 156 | /// Get the MessageItems that make up the message. |
| 157 | /// |
| 158 | /// Note: use `iter_init` or `get1`/`get2`/etc instead for faster access to the arguments. |
| 159 | /// This method is provided for backwards compatibility. |
| 160 | pub fn get_items(&self) -> Vec<crate::arg::messageitem::MessageItem> { |
| 161 | let mut i = self.iter_init(); |
| 162 | let mut v = vec!(); |
| 163 | while let Some(z) = crate::arg::messageitem::MessageItem::get(&mut i) { v.push(z); i.next(); } |
| 164 | v |
| 165 | } |
| 166 | |
| 167 | /// Get the D-Bus serial of a message, if one was specified. |
| 168 | pub fn get_serial(&self) -> Option<u32> { |
| 169 | let x = unsafe { ffi::dbus_message_get_serial(self.msg) }; |
| 170 | if x == 0 { None } else { Some(x) } |
| 171 | } |
| 172 | |
| 173 | /// Get the serial of the message this message is a reply to, if present. |
| 174 | pub fn get_reply_serial(&self) -> Option<u32> { |
| 175 | let s = unsafe { ffi::dbus_message_get_reply_serial(self.msg) }; |
| 176 | if s == 0 { None } else { Some(s) } |
| 177 | } |
| 178 | |
| 179 | /// Returns true if the message does not expect a reply. |
| 180 | pub fn get_no_reply(&self) -> bool { unsafe { ffi::dbus_message_get_no_reply(self.msg) != 0 } } |
| 181 | |
| 182 | /// Set whether or not the message expects a reply. |
| 183 | /// |
| 184 | /// Set to true if you send a method call and do not want a reply. |
| 185 | pub fn set_no_reply(&mut self, v: bool) { |
| 186 | unsafe { ffi::dbus_message_set_no_reply(self.msg, if v { 1 } else { 0 }) } |
| 187 | } |
| 188 | |
| 189 | /// Returns true if the message can cause a service to be auto-started. |
| 190 | pub fn get_auto_start(&self) -> bool { unsafe { ffi::dbus_message_get_auto_start(self.msg) != 0 } } |
| 191 | |
| 192 | /// Sets whether or not the message can cause a service to be auto-started. |
| 193 | /// |
| 194 | /// Defaults to true. |
| 195 | pub fn set_auto_start(&mut self, v: bool) { |
| 196 | unsafe { ffi::dbus_message_set_auto_start(self.msg, if v { 1 } else { 0 }) } |
| 197 | } |
| 198 | |
| 199 | /// Add one or more MessageItems to this Message. |
| 200 | /// |
| 201 | /// Note: using `append1`, `append2` or `append3` might be faster, especially for large arrays. |
| 202 | /// This method is provided for backwards compatibility. |
| 203 | pub fn append_items(&mut self, v: &[crate::arg::messageitem::MessageItem]) { |
| 204 | let mut ia = IterAppend::new(self); |
| 205 | for a in v { a.append_by_ref(&mut ia); } |
| 206 | } |
| 207 | |
| 208 | /// Appends one argument to this message. |
| 209 | /// Use in builder style: e g `m.method_return().append1(7i32)` |
| 210 | pub fn append1<A: Append>(mut self, a: A) -> Self { |
| 211 | { |
| 212 | let mut m = IterAppend::new(&mut self); |
| 213 | m.append(a); |
| 214 | } |
| 215 | self |
| 216 | } |
| 217 | |
| 218 | /// Appends two arguments to this message. |
| 219 | /// Use in builder style: e g `m.method_return().append2(7i32, 6u8)` |
| 220 | pub fn append2<A1: Append, A2: Append>(mut self, a1: A1, a2: A2) -> Self { |
| 221 | { |
| 222 | let mut m = IterAppend::new(&mut self); |
| 223 | m.append(a1); m.append(a2); |
| 224 | } |
| 225 | self |
| 226 | } |
| 227 | |
| 228 | /// Appends three arguments to this message. |
| 229 | /// Use in builder style: e g `m.method_return().append3(7i32, 6u8, true)` |
| 230 | pub fn append3<A1: Append, A2: Append, A3: Append>(mut self, a1: A1, a2: A2, a3: A3) -> Self { |
| 231 | { |
| 232 | let mut m = IterAppend::new(&mut self); |
| 233 | m.append(a1); m.append(a2); m.append(a3); |
| 234 | } |
| 235 | self |
| 236 | } |
| 237 | |
| 238 | /// Appends RefArgs to this message. |
| 239 | /// Use in builder style: e g `m.method_return().append_ref(&[7i32, 6u8, true])` |
| 240 | pub fn append_ref<A: RefArg>(mut self, r: &[A]) -> Self { |
| 241 | { |
| 242 | let mut m = IterAppend::new(&mut self); |
| 243 | for rr in r { |
| 244 | rr.append(&mut m); |
| 245 | } |
| 246 | } |
| 247 | self |
| 248 | } |
| 249 | |
| 250 | /// Appends arguments to a message. |
| 251 | pub fn append_all<A: AppendAll>(&mut self, a: A) { |
| 252 | let mut m = IterAppend::new(self); |
| 253 | a.append(&mut m); |
| 254 | } |
| 255 | |
| 256 | /// Gets the first argument from the message, if that argument is of type G1. |
| 257 | /// Returns None if there are not enough arguments, or if types don't match. |
| 258 | pub fn get1<'a, G1: Get<'a>>(&'a self) -> Option<G1> { |
| 259 | let mut i = Iter::new(&self); |
| 260 | i.get() |
| 261 | } |
| 262 | |
| 263 | /// Gets the first two arguments from the message, if those arguments are of type G1 and G2. |
| 264 | /// Returns None if there are not enough arguments, or if types don't match. |
| 265 | pub fn get2<'a, G1: Get<'a>, G2: Get<'a>>(&'a self) -> (Option<G1>, Option<G2>) { |
| 266 | let mut i = Iter::new(&self); |
| 267 | let g1 = i.get(); |
| 268 | if !i.next() { return (g1, None); } |
| 269 | (g1, i.get()) |
| 270 | } |
| 271 | |
| 272 | /// Gets the first three arguments from the message, if those arguments are of type G1, G2 and G3. |
| 273 | /// Returns None if there are not enough arguments, or if types don't match. |
| 274 | pub fn get3<'a, G1: Get<'a>, G2: Get<'a>, G3: Get<'a>>(&'a self) -> (Option<G1>, Option<G2>, Option<G3>) { |
| 275 | let mut i = Iter::new(&self); |
| 276 | let g1 = i.get(); |
| 277 | if !i.next() { return (g1, None, None) } |
| 278 | let g2 = i.get(); |
| 279 | if !i.next() { return (g1, g2, None) } |
| 280 | (g1, g2, i.get()) |
| 281 | } |
| 282 | |
| 283 | /// Gets the first four arguments from the message, if those arguments are of type G1, G2, G3 and G4. |
| 284 | /// Returns None if there are not enough arguments, or if types don't match. |
| 285 | pub fn get4<'a, G1: Get<'a>, G2: Get<'a>, G3: Get<'a>, G4: Get<'a>>(&'a self) -> (Option<G1>, Option<G2>, Option<G3>, Option<G4>) { |
| 286 | let mut i = Iter::new(&self); |
| 287 | let g1 = i.get(); |
| 288 | if !i.next() { return (g1, None, None, None) } |
| 289 | let g2 = i.get(); |
| 290 | if !i.next() { return (g1, g2, None, None) } |
| 291 | let g3 = i.get(); |
| 292 | if !i.next() { return (g1, g2, g3, None) } |
| 293 | (g1, g2, g3, i.get()) |
| 294 | } |
| 295 | |
| 296 | /// Gets the first five arguments from the message, if those arguments are of type G1, G2, G3 and G4. |
| 297 | /// Returns None if there are not enough arguments, or if types don't match. |
| 298 | /// Note: If you need more than five arguments, use `iter_init` instead. |
| 299 | pub fn get5<'a, G1: Get<'a>, G2: Get<'a>, G3: Get<'a>, G4: Get<'a>, G5: Get<'a>>(&'a self) -> (Option<G1>, Option<G2>, Option<G3>, Option<G4>, Option<G5>) { |
| 300 | let mut i = Iter::new(&self); |
| 301 | let g1 = i.get(); |
| 302 | if !i.next() { return (g1, None, None, None, None) } |
| 303 | let g2 = i.get(); |
| 304 | if !i.next() { return (g1, g2, None, None, None) } |
| 305 | let g3 = i.get(); |
| 306 | if !i.next() { return (g1, g2, g3, None, None) } |
| 307 | let g4 = i.get(); |
| 308 | if !i.next() { return (g1, g2, g3, g4, None) } |
| 309 | (g1, g2, g3, g4, i.get()) |
| 310 | } |
| 311 | |
| 312 | /// Gets the first argument from the message, if that argument is of type G1. |
| 313 | /// |
| 314 | /// Returns a TypeMismatchError if there are not enough arguments, or if types don't match. |
| 315 | pub fn read1<'a, G1: Arg + Get<'a>>(&'a self) -> Result<G1, TypeMismatchError> { |
| 316 | let mut i = Iter::new(&self); |
| 317 | i.read() |
| 318 | } |
| 319 | |
| 320 | /// Gets the first two arguments from the message, if those arguments are of type G1 and G2. |
| 321 | /// |
| 322 | /// Returns a TypeMismatchError if there are not enough arguments, or if types don't match. |
| 323 | pub fn read2<'a, G1: Arg + Get<'a>, G2: Arg + Get<'a>>(&'a self) -> Result<(G1, G2), TypeMismatchError> { |
| 324 | let mut i = Iter::new(&self); |
| 325 | Ok((i.read()?, i.read()?)) |
| 326 | } |
| 327 | |
| 328 | /// Gets the first three arguments from the message, if those arguments are of type G1, G2 and G3. |
| 329 | /// |
| 330 | /// Returns a TypeMismatchError if there are not enough arguments, or if types don't match. |
| 331 | pub fn read3<'a, G1: Arg + Get<'a>, G2: Arg + Get<'a>, G3: Arg + Get<'a>>(&'a self) -> |
| 332 | Result<(G1, G2, G3), TypeMismatchError> { |
| 333 | let mut i = Iter::new(&self); |
| 334 | Ok((i.read()?, i.read()?, i.read()?)) |
| 335 | } |
| 336 | |
| 337 | /// Gets the first four arguments from the message, if those arguments are of type G1, G2, G3 and G4. |
| 338 | /// |
| 339 | /// Returns a TypeMismatchError if there are not enough arguments, or if types don't match. |
| 340 | pub fn read4<'a, G1: Arg + Get<'a>, G2: Arg + Get<'a>, G3: Arg + Get<'a>, G4: Arg + Get<'a>>(&'a self) -> |
| 341 | Result<(G1, G2, G3, G4), TypeMismatchError> { |
| 342 | let mut i = Iter::new(&self); |
| 343 | Ok((i.read()?, i.read()?, i.read()?, i.read()?)) |
| 344 | } |
| 345 | |
| 346 | /// Gets the first five arguments from the message, if those arguments are of type G1, G2, G3, G4 and G5. |
| 347 | /// |
| 348 | /// Returns a TypeMismatchError if there are not enough arguments, or if types don't match. |
| 349 | /// Note: If you need more than five arguments, use `iter_init` instead. |
| 350 | pub fn read5<'a, G1: Arg + Get<'a>, G2: Arg + Get<'a>, G3: Arg + Get<'a>, G4: Arg + Get<'a>, G5: Arg + Get<'a>>(&'a self) -> |
| 351 | Result<(G1, G2, G3, G4, G5), TypeMismatchError> { |
| 352 | let mut i = Iter::new(&self); |
| 353 | Ok((i.read()?, i.read()?, i.read()?, i.read()?, i.read()?)) |
| 354 | } |
| 355 | |
| 356 | /// Gets arguments from a message. |
| 357 | /// |
| 358 | /// If this was an error reply or if types mismatch, an error is returned. |
| 359 | pub fn read_all<R: ReadAll>(&self) -> Result<R, Error> { |
| 360 | self.set_error_from_msg()?; |
| 361 | Ok(R::read(&mut self.iter_init())?) |
| 362 | } |
| 363 | |
| 364 | /// Returns a struct for retreiving the arguments from a message. Supersedes get_items(). |
| 365 | pub fn iter_init(&self) -> Iter { Iter::new(&self) } |
| 366 | |
| 367 | /// Gets the MessageType of the Message. |
| 368 | pub fn msg_type(&self) -> MessageType { |
| 369 | match unsafe { ffi::dbus_message_get_type(self.msg) } { |
| 370 | 1 => MessageType::MethodCall, |
| 371 | 2 => MessageType::MethodReturn, |
| 372 | 3 => MessageType::Error, |
| 373 | 4 => MessageType::Signal, |
| 374 | x => panic!("Invalid message type {}" , x), |
| 375 | } |
| 376 | } |
| 377 | |
| 378 | fn msg_internal_str<'a>(&'a self, c: *const libc::c_char) -> Option<&'a str> { |
| 379 | if c.is_null() { return None }; |
| 380 | let cc = unsafe { CStr::from_ptr(c) }; |
| 381 | std::str::from_utf8(cc.to_bytes_with_nul()).ok() |
| 382 | } |
| 383 | |
| 384 | /// Gets the name of the connection that originated this message. |
| 385 | pub fn sender(&self) -> Option<BusName> { |
| 386 | self.msg_internal_str(unsafe { ffi::dbus_message_get_sender(self.msg) }) |
| 387 | .map(|s| unsafe { BusName::from_slice_unchecked(s) }) |
| 388 | } |
| 389 | |
| 390 | /// Gets the object path this Message is being sent to. |
| 391 | pub fn path(&self) -> Option<Path> { |
| 392 | self.msg_internal_str(unsafe { ffi::dbus_message_get_path(self.msg) }) |
| 393 | .map(|s| unsafe { Path::from_slice_unchecked(s) }) |
| 394 | } |
| 395 | |
| 396 | /// Gets the destination this Message is being sent to. |
| 397 | pub fn destination(&self) -> Option<BusName> { |
| 398 | self.msg_internal_str(unsafe { ffi::dbus_message_get_destination(self.msg) }) |
| 399 | .map(|s| unsafe { BusName::from_slice_unchecked(s) }) |
| 400 | } |
| 401 | |
| 402 | /// Sets the destination of this Message |
| 403 | /// |
| 404 | /// If dest is none, that means broadcast to all relevant destinations. |
| 405 | pub fn set_destination(&mut self, dest: Option<BusName>) { |
| 406 | let c_dest = dest.as_ref().map(|d| d.as_cstr().as_ptr()).unwrap_or(ptr::null()); |
| 407 | assert!(unsafe { ffi::dbus_message_set_destination(self.msg, c_dest) } != 0); |
| 408 | } |
| 409 | |
| 410 | /// Gets the interface this Message is being sent to. |
| 411 | pub fn interface(&self) -> Option<Interface> { |
| 412 | self.msg_internal_str(unsafe { ffi::dbus_message_get_interface(self.msg) }) |
| 413 | .map(|s| unsafe { Interface::from_slice_unchecked(s) }) |
| 414 | } |
| 415 | |
| 416 | /// Gets the interface member being called. |
| 417 | pub fn member(&self) -> Option<Member> { |
| 418 | self.msg_internal_str(unsafe { ffi::dbus_message_get_member(self.msg) }) |
| 419 | .map(|s| unsafe { Member::from_slice_unchecked(s) }) |
| 420 | } |
| 421 | |
| 422 | /// When the remote end returns an error, the message itself is |
| 423 | /// correct but its contents is an error. This method will |
| 424 | /// transform such an error to a D-Bus Error or otherwise return |
| 425 | /// the original message. |
| 426 | pub fn as_result(&mut self) -> Result<&mut Message, Error> { |
| 427 | self.set_error_from_msg().map(|_| self) |
| 428 | } |
| 429 | |
| 430 | pub (crate) fn set_error_from_msg(&self) -> Result<(), Error> { |
| 431 | let mut e = Error::empty(); |
| 432 | if unsafe { ffi::dbus_set_error_from_message(e.get_mut(), self.msg) } != 0 { Err(e) } |
| 433 | else { Ok(()) } |
| 434 | } |
| 435 | |
| 436 | pub (crate) fn ptr(&self) -> *mut ffi::DBusMessage { self.msg } |
| 437 | |
| 438 | pub (crate) fn from_ptr(ptr: *mut ffi::DBusMessage, add_ref: bool) -> Message { |
| 439 | if add_ref { |
| 440 | unsafe { ffi::dbus_message_ref(ptr) }; |
| 441 | } |
| 442 | Message { msg: ptr } |
| 443 | } |
| 444 | |
| 445 | /// Sets serial number manually - mostly for internal use |
| 446 | /// |
| 447 | /// When sending a message, a serial will be automatically assigned, so you don't need to call |
| 448 | /// this method. However, it can be very useful in test code that is supposed to handle a method call. |
| 449 | /// This way, you can create a method call and handle it without sending it to a real D-Bus instance. |
| 450 | pub fn set_serial(&mut self, val: u32) { |
| 451 | unsafe { ffi::dbus_message_set_serial(self.msg, val) }; |
| 452 | } |
| 453 | |
| 454 | /// Marshals a message - mostly for internal use |
| 455 | /// |
| 456 | /// The function f will be called one or more times with bytes to be written somewhere. |
| 457 | /// You should call set_serial to manually set a serial number before calling this function |
| 458 | pub fn marshal<E, F: FnMut(&[u8]) -> Result<(), E>>(&self, mut f: F) -> Result<(), E> { |
| 459 | let mut len = 0; |
| 460 | let mut data = ptr::null_mut(); |
| 461 | if unsafe { ffi::dbus_message_marshal(self.msg, &mut data, &mut len) } == 0 { |
| 462 | panic!("out of memory" ); |
| 463 | } |
| 464 | let s = unsafe { std::slice::from_raw_parts(data as *mut u8 as *const u8, len as usize) }; |
| 465 | let r = f(s); |
| 466 | unsafe { ffi::dbus_free(data as *mut _) }; |
| 467 | r |
| 468 | } |
| 469 | |
| 470 | /// Demarshals a message - mostly for internal use |
| 471 | pub fn demarshal(data: &[u8]) -> Result<Self, Error> { |
| 472 | let mut e = Error::empty(); |
| 473 | let p = unsafe { ffi::dbus_message_demarshal(data.as_ptr() as *const _, data.len() as _, e.get_mut()) }; |
| 474 | if p == ptr::null_mut() { |
| 475 | Err(e) |
| 476 | } else { |
| 477 | Ok(Self::from_ptr(p, false)) |
| 478 | } |
| 479 | } |
| 480 | |
| 481 | /// Returns the size of the message - mostly for internal use |
| 482 | /// |
| 483 | /// Returns Err(()) on protocol errors. Make sure you have at least 16 bytes in the buffer |
| 484 | /// before calling this method. |
| 485 | pub fn demarshal_bytes_needed(data: &[u8]) -> Result<usize, ()> { |
| 486 | const MIN_HEADER: usize = 16; |
| 487 | if data.len() < MIN_HEADER { return Ok(MIN_HEADER); } |
| 488 | let x = unsafe { ffi::dbus_message_demarshal_bytes_needed(data.as_ptr() as *const _, data.len() as _) }; |
| 489 | if x < MIN_HEADER as _ { Err(()) } else { Ok(x as usize) } |
| 490 | } |
| 491 | |
| 492 | } |
| 493 | |
| 494 | impl Drop for Message { |
| 495 | fn drop(&mut self) { |
| 496 | unsafe { |
| 497 | ffi::dbus_message_unref(self.msg); |
| 498 | } |
| 499 | } |
| 500 | } |
| 501 | |
| 502 | impl fmt::Debug for Message { |
| 503 | fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { |
| 504 | let mut x: DebugStruct<'_, '_> = f.debug_struct(name:"Message" ); |
| 505 | x.field(name:"Type" , &self.msg_type()); |
| 506 | // The &&** derefs to a &&str, which implements &dyn Debug |
| 507 | if let Some(ref path: &Path<'_>) = self.path() { x.field(name:"Path" , &&**path); } |
| 508 | if let Some(ref iface: &Interface<'_>) = self.interface() { x.field(name:"Interface" , &&**iface); } |
| 509 | if let Some(ref member: &Member<'_>) = self.member() { x.field(name:"Member" , &&**member); } |
| 510 | if let Some(ref sender: &BusName<'_>) = self.sender() { x.field(name:"Sender" , &&**sender); } |
| 511 | if let Some(ref dest: &BusName<'_>) = self.destination() { x.field(name:"Destination" , &&**dest); } |
| 512 | if let Some(ref serial: &u32) = self.get_serial() { x.field(name:"Serial" , value:serial); } |
| 513 | if let Some(ref rs: &u32) = self.get_reply_serial() { x.field(name:"ReplySerial" , value:rs); } |
| 514 | let mut args: Vec> = vec!(); |
| 515 | let mut iter: Iter<'_> = self.iter_init(); |
| 516 | while let Some(a: Box) = iter.get_refarg() { |
| 517 | args.push(a); |
| 518 | iter.next(); |
| 519 | } |
| 520 | let args2: &[_] = &args; |
| 521 | x.field(name:"Args" , &args2); |
| 522 | x.finish() |
| 523 | } |
| 524 | } |
| 525 | |
| 526 | #[cfg (test)] |
| 527 | mod test { |
| 528 | use crate::{Message}; |
| 529 | use crate::strings::BusName; |
| 530 | |
| 531 | #[test ] |
| 532 | fn set_valid_destination() { |
| 533 | let mut m = Message::new_method_call("org.test.rust" , "/" , "org.test.rust" , "Test" ).unwrap(); |
| 534 | let d = Some(BusName::new(":1.14" ).unwrap()); |
| 535 | m.set_destination(d); |
| 536 | |
| 537 | assert!(!m.get_no_reply()); |
| 538 | m.set_no_reply(true); |
| 539 | assert!(m.get_no_reply()); |
| 540 | } |
| 541 | |
| 542 | #[test ] |
| 543 | fn marshal() { |
| 544 | let mut m = Message::new_method_call("org.freedesktop.DBus" , "/org/freedesktop/DBus" , "org.freedesktop.DBus" , "Hello" ).unwrap(); |
| 545 | m.set_serial(1); |
| 546 | let r = m.marshal(|d| { |
| 547 | let m2 = Message::demarshal(d).unwrap(); |
| 548 | assert_eq!(&*m2.path().unwrap(), "/org/freedesktop/DBus" ); |
| 549 | Err(45) |
| 550 | }); |
| 551 | assert_eq!(45, r.unwrap_err()); |
| 552 | } |
| 553 | } |
| 554 | |