1use std::{
4 borrow::Borrow,
5 fmt::{Display, Write},
6 ops::Deref,
7};
8
9use serde::{de, Deserialize, Serialize};
10use zvariant::Structure;
11
12use crate::{
13 message::Type,
14 names::{BusName, InterfaceName, MemberName, UniqueName},
15 zvariant::{ObjectPath, Str, Type as VariantType},
16 Error, Result,
17};
18
19mod builder;
20pub use builder::Builder;
21
22#[derive(Clone, Debug, PartialEq, Eq, Hash, VariantType)]
92#[zvariant(signature = "s")]
93pub struct MatchRule<'m> {
94 pub(crate) msg_type: Option<Type>,
95 pub(crate) sender: Option<BusName<'m>>,
96 pub(crate) interface: Option<InterfaceName<'m>>,
97 pub(crate) member: Option<MemberName<'m>>,
98 pub(crate) path_spec: Option<PathSpec<'m>>,
99 pub(crate) destination: Option<UniqueName<'m>>,
100 pub(crate) args: Vec<(u8, Str<'m>)>,
101 pub(crate) arg_paths: Vec<(u8, ObjectPath<'m>)>,
102 pub(crate) arg0ns: Option<Str<'m>>,
103}
104
105impl<'m> MatchRule<'m> {
106 pub fn builder() -> Builder<'m> {
108 Builder::new()
109 }
110
111 pub fn sender(&self) -> Option<&BusName<'_>> {
113 self.sender.as_ref()
114 }
115
116 pub fn msg_type(&self) -> Option<Type> {
118 self.msg_type
119 }
120
121 pub fn interface(&self) -> Option<&InterfaceName<'_>> {
123 self.interface.as_ref()
124 }
125
126 pub fn member(&self) -> Option<&MemberName<'_>> {
128 self.member.as_ref()
129 }
130
131 pub fn path_spec(&self) -> Option<&PathSpec<'_>> {
133 self.path_spec.as_ref()
134 }
135
136 pub fn destination(&self) -> Option<&UniqueName<'_>> {
138 self.destination.as_ref()
139 }
140
141 pub fn args(&self) -> &[(u8, Str<'_>)] {
143 self.args.as_ref()
144 }
145
146 pub fn arg_paths(&self) -> &[(u8, ObjectPath<'_>)] {
148 self.arg_paths.as_ref()
149 }
150
151 pub fn arg0ns(&self) -> Option<&Str<'m>> {
153 self.arg0ns.as_ref()
154 }
155
156 pub fn to_owned(&self) -> MatchRule<'static> {
158 MatchRule {
159 msg_type: self.msg_type,
160 sender: self.sender.as_ref().map(|s| s.to_owned()),
161 interface: self.interface.as_ref().map(|i| i.to_owned()),
162 member: self.member.as_ref().map(|m| m.to_owned()),
163 path_spec: self.path_spec.as_ref().map(|p| p.to_owned()),
164 destination: self.destination.as_ref().map(|d| d.to_owned()),
165 args: self.args.iter().map(|(i, s)| (*i, s.to_owned())).collect(),
166 arg_paths: self
167 .arg_paths
168 .iter()
169 .map(|(i, p)| (*i, p.to_owned()))
170 .collect(),
171 arg0ns: self.arg0ns.as_ref().map(|a| a.to_owned()),
172 }
173 }
174
175 pub fn into_owned(self) -> MatchRule<'static> {
177 MatchRule {
178 msg_type: self.msg_type,
179 sender: self.sender.map(|s| s.into_owned()),
180 interface: self.interface.map(|i| i.into_owned()),
181 member: self.member.map(|m| m.into_owned()),
182 path_spec: self.path_spec.map(|p| p.into_owned()),
183 destination: self.destination.map(|d| d.into_owned()),
184 args: self
185 .args
186 .into_iter()
187 .map(|(i, s)| (i, s.into_owned()))
188 .collect(),
189 arg_paths: self
190 .arg_paths
191 .into_iter()
192 .map(|(i, p)| (i, p.into_owned()))
193 .collect(),
194 arg0ns: self.arg0ns.map(|a| a.into_owned()),
195 }
196 }
197
198 pub fn matches(&self, msg: &zbus::message::Message) -> Result<bool> {
210 let hdr = msg.header();
211
212 if let Some(msg_type) = self.msg_type() {
214 if msg_type != msg.message_type() {
215 return Ok(false);
216 }
217 }
218
219 if let Some(sender) = self.sender() {
221 match sender {
222 BusName::Unique(name) if Some(name) != hdr.sender() => {
223 return Ok(false);
224 }
225 BusName::Unique(_) => (),
226 BusName::WellKnown(_) => (),
228 }
229 }
230
231 if let Some(interface) = self.interface() {
233 match hdr.interface() {
234 Some(msg_interface) if interface != msg_interface => return Ok(false),
235 Some(_) => (),
236 None => return Ok(false),
237 }
238 }
239
240 if let Some(member) = self.member() {
242 match hdr.member() {
243 Some(msg_member) if member != msg_member => return Ok(false),
244 Some(_) => (),
245 None => return Ok(false),
246 }
247 }
248
249 if let Some(destination) = self.destination() {
251 match hdr.destination() {
252 Some(BusName::Unique(name)) if destination != name => {
253 return Ok(false);
254 }
255 Some(BusName::Unique(_)) | None => (),
256 Some(BusName::WellKnown(_)) => (),
258 };
259 }
260
261 if let Some(path_spec) = self.path_spec() {
263 let msg_path = match hdr.path() {
264 Some(p) => p,
265 None => return Ok(false),
266 };
267 match path_spec {
268 PathSpec::Path(path) if path != msg_path => return Ok(false),
269 PathSpec::PathNamespace(path_ns) if !msg_path.starts_with(path_ns.as_str()) => {
270 return Ok(false);
271 }
272 PathSpec::Path(_) | PathSpec::PathNamespace(_) => (),
273 }
274 }
275
276 if let Some(arg0_ns) = self.arg0ns() {
278 if let Ok(arg0) = msg.body().deserialize_unchecked::<BusName<'_>>() {
279 match arg0.strip_prefix(arg0_ns.as_str()) {
280 None => return Ok(false),
281 Some(s) if !s.is_empty() && !s.starts_with('.') => return Ok(false),
282 _ => (),
283 }
284 } else {
285 return Ok(false);
286 }
287 }
288
289 if self.args().is_empty() && self.arg_paths().is_empty() {
291 return Ok(true);
292 }
293 let body = msg.body();
294 let structure = match body.deserialize::<Structure<'_>>() {
295 Ok(s) => s,
296 Err(_) => return Ok(false),
297 };
298 let args = structure.fields();
299
300 for (i, arg) in self.args() {
301 match args.get(*i as usize) {
302 Some(msg_arg) => match <&str>::try_from(msg_arg) {
303 Ok(msg_arg) if arg != msg_arg => return Ok(false),
304 Ok(_) => (),
305 Err(_) => return Ok(false),
306 },
307 None => return Ok(false),
308 }
309 }
310
311 for (i, path) in self.arg_paths() {
313 match args.get(*i as usize) {
314 Some(msg_arg) => match <ObjectPath<'_>>::try_from(msg_arg) {
315 Ok(msg_arg) if *path != msg_arg => return Ok(false),
316 Ok(_) => (),
317 Err(_) => return Ok(false),
318 },
319 None => return Ok(false),
320 }
321 }
322
323 Ok(true)
324 }
325
326 pub(crate) fn fdo_signal_builder<S>(signal_name: S) -> Builder<'m>
327 where
328 S: TryInto<MemberName<'m>>,
329 S::Error: Into<Error>,
330 {
331 Builder::new()
332 .msg_type(Type::Signal)
333 .sender("org.freedesktop.DBus")
334 .unwrap()
335 .interface("org.freedesktop.DBus")
336 .unwrap()
337 .member(signal_name)
338 .unwrap()
339 }
340}
341
342impl Display for MatchRule<'_> {
343 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
344 let mut first_component = true;
345 if let Some(msg_type) = self.msg_type() {
346 let type_str = match msg_type {
347 Type::Error => "error",
348 Type::MethodCall => "method_call",
349 Type::MethodReturn => "method_return",
350 Type::Signal => "signal",
351 };
352 write_match_rule_string_component(f, "type", type_str, &mut first_component)?;
353 }
354 if let Some(sender) = self.sender() {
355 write_match_rule_string_component(f, "sender", sender, &mut first_component)?;
356 }
357 if let Some(interface) = self.interface() {
358 write_match_rule_string_component(f, "interface", interface, &mut first_component)?;
359 }
360 if let Some(member) = self.member() {
361 write_match_rule_string_component(f, "member", member, &mut first_component)?;
362 }
363 if let Some(destination) = self.destination() {
364 write_match_rule_string_component(f, "destination", destination, &mut first_component)?;
365 }
366 if let Some(path_spec) = self.path_spec() {
367 let (key, value) = match path_spec {
368 PathSpec::Path(path) => ("path", path),
369 PathSpec::PathNamespace(ns) => ("path_namespace", ns),
370 };
371 write_match_rule_string_component(f, key, value, &mut first_component)?;
372 }
373 for (i, arg) in self.args() {
374 write_comma(f, &mut first_component)?;
375 write!(f, "arg{i}='{arg}'")?;
376 }
377 for (i, arg_path) in self.arg_paths() {
378 write_comma(f, &mut first_component)?;
379 write!(f, "arg{i}path='{arg_path}'")?;
380 }
381 if let Some(arg0namespace) = self.arg0ns() {
382 write_comma(f, &mut first_component)?;
383 write!(f, "arg0namespace='{arg0namespace}'")?;
384 }
385
386 Ok(())
387 }
388}
389
390fn write_match_rule_string_component(
391 f: &mut std::fmt::Formatter<'_>,
392 key: &str,
393 value: &str,
394 first_component: &mut bool,
395) -> std::fmt::Result {
396 write_comma(f, first_component)?;
397 f.write_str(key)?;
398 f.write_str("='")?;
399 f.write_str(value)?;
400 f.write_char('\'')?;
401
402 Ok(())
403}
404
405fn write_comma(f: &mut std::fmt::Formatter<'_>, first_component: &mut bool) -> std::fmt::Result {
406 if *first_component {
407 *first_component = false;
408 } else {
409 f.write_char(',')?;
410 }
411
412 Ok(())
413}
414
415impl<'m> TryFrom<&'m str> for MatchRule<'m> {
416 type Error = Error;
417
418 fn try_from(s: &'m str) -> Result<Self> {
419 let components = s.split(',');
420 if components.clone().peekable().peek().is_none() {
421 return Err(Error::InvalidMatchRule);
422 }
423 let mut builder = MatchRule::builder();
424 for component in components {
425 let (key, value) = component.split_once('=').ok_or(Error::InvalidMatchRule)?;
426 if key.is_empty()
427 || value.len() < 2
428 || !value.starts_with('\'')
429 || !value.ends_with('\'')
430 {
431 return Err(Error::InvalidMatchRule);
432 }
433 let value = &value[1..value.len() - 1];
434 builder = match key {
435 "type" => {
436 let msg_type = match value {
437 "error" => Type::Error,
438 "method_call" => Type::MethodCall,
439 "method_return" => Type::MethodReturn,
440 "signal" => Type::Signal,
441 _ => return Err(Error::InvalidMatchRule),
442 };
443 builder.msg_type(msg_type)
444 }
445 "sender" => builder.sender(value)?,
446 "interface" => builder.interface(value)?,
447 "member" => builder.member(value)?,
448 "path" => builder.path(value)?,
449 "path_namespace" => builder.path_namespace(value)?,
450 "destination" => builder.destination(value)?,
451 "arg0namespace" => builder.arg0ns(value)?,
452 key if key.starts_with("arg") => {
453 if let Some(trailing_idx) = key.find("path") {
454 let idx = key[3..trailing_idx]
455 .parse::<u8>()
456 .map_err(|_| Error::InvalidMatchRule)?;
457 builder.arg_path(idx, value)?
458 } else {
459 let idx = key[3..]
460 .parse::<u8>()
461 .map_err(|_| Error::InvalidMatchRule)?;
462 builder.arg(idx, value)?
463 }
464 }
465 _ => return Err(Error::InvalidMatchRule),
466 };
467 }
468
469 Ok(builder.build())
470 }
471}
472
473impl<'de: 'm, 'm> Deserialize<'de> for MatchRule<'m> {
474 fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
475 where
476 D: serde::Deserializer<'de>,
477 {
478 let name = <&str>::deserialize(deserializer)?;
479
480 Self::try_from(name).map_err(|e| de::Error::custom(e.to_string()))
481 }
482}
483
484impl Serialize for MatchRule<'_> {
485 fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
486 where
487 S: serde::Serializer,
488 {
489 serializer.serialize_str(&self.to_string())
490 }
491}
492
493#[derive(Clone, Debug, PartialEq, Eq, Hash)]
495pub enum PathSpec<'m> {
496 Path(ObjectPath<'m>),
497 PathNamespace(ObjectPath<'m>),
498}
499
500impl PathSpec<'_> {
501 fn to_owned(&self) -> PathSpec<'static> {
503 match self {
504 PathSpec::Path(path) => PathSpec::Path(path.to_owned()),
505 PathSpec::PathNamespace(ns) => PathSpec::PathNamespace(ns.to_owned()),
506 }
507 }
508
509 pub fn into_owned(self) -> PathSpec<'static> {
511 match self {
512 PathSpec::Path(path) => PathSpec::Path(path.into_owned()),
513 PathSpec::PathNamespace(ns) => PathSpec::PathNamespace(ns.into_owned()),
514 }
515 }
516}
517
518#[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, VariantType)]
520pub struct OwnedMatchRule(#[serde(borrow)] MatchRule<'static>);
521
522impl OwnedMatchRule {
523 pub fn into_inner(self) -> MatchRule<'static> {
525 self.0
526 }
527
528 pub fn inner(&self) -> &MatchRule<'static> {
530 &self.0
531 }
532}
533
534impl Deref for OwnedMatchRule {
535 type Target = MatchRule<'static>;
536
537 fn deref(&self) -> &Self::Target {
538 &self.0
539 }
540}
541
542impl<'a> Borrow<MatchRule<'a>> for OwnedMatchRule {
543 fn borrow(&self) -> &MatchRule<'a> {
544 &self.0
545 }
546}
547
548impl From<OwnedMatchRule> for MatchRule<'_> {
549 fn from(o: OwnedMatchRule) -> Self {
550 o.into_inner()
551 }
552}
553
554impl<'unowned, 'owned: 'unowned> From<&'owned OwnedMatchRule> for MatchRule<'unowned> {
555 fn from(rule: &'owned OwnedMatchRule) -> Self {
556 rule.inner().clone()
557 }
558}
559
560impl From<MatchRule<'_>> for OwnedMatchRule {
561 fn from(rule: MatchRule<'_>) -> Self {
562 OwnedMatchRule(rule.into_owned())
563 }
564}
565
566impl TryFrom<&'_ str> for OwnedMatchRule {
567 type Error = Error;
568
569 fn try_from(value: &str) -> Result<Self> {
570 Ok(Self::from(MatchRule::try_from(value)?))
571 }
572}
573
574impl<'de> Deserialize<'de> for OwnedMatchRule {
575 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
576 where
577 D: de::Deserializer<'de>,
578 {
579 String::deserialize(deserializer)
580 .and_then(|r| {
581 MatchRule::try_from(r.as_str())
582 .map(|r| r.to_owned())
583 .map_err(|e| de::Error::custom(e.to_string()))
584 })
585 .map(Self)
586 }
587}
588
589impl PartialEq<MatchRule<'_>> for OwnedMatchRule {
590 fn eq(&self, other: &MatchRule<'_>) -> bool {
591 self.0 == *other
592 }
593}