Fcitx
matchrule.cpp
1 /*
2  * SPDX-FileCopyrightText: 2017-2017 CSSlayer <wengxt@gmail.com>
3  *
4  * SPDX-License-Identifier: LGPL-2.1-or-later
5  *
6  */
7 
8 #include "matchrule.h"
9 #include <cstddef>
10 #include <memory>
11 #include <string>
12 #include <utility>
13 #include <vector>
14 #include "../macros.h"
15 #include "../stringutils.h"
16 #include "message.h"
17 #include "utils_p.h"
18 
19 namespace fcitx::dbus {
20 
21 static const char nullArray[] = {'\0', '\0'};
22 
23 const std::string MatchRule::nullArg{nullArray, nullArray + 1};
24 
26 public:
27  MatchRulePrivate(MessageType type, std::string service,
28  std::string destination, std::string path,
29  std::string interface, std::string name,
30  std::vector<std::string> argumentMatch, bool eavesdrop)
31  : type_(type), service_(std::move(service)),
32  destination_(std::move(destination)), path_(std::move(path)),
33  interface_(std::move(interface)), name_(std::move(name)),
34  argumentMatch_(std::move(argumentMatch)), eavesdrop_(eavesdrop),
35  rule_(buildRule()) {}
36 
37  FCITX_INLINE_DEFINE_DEFAULT_DTOR_COPY_AND_MOVE_WITHOUT_SPEC(
39 
40  MessageType type_;
41  std::string service_;
42  std::string destination_;
43  std::string path_;
44  std::string interface_;
45  std::string name_;
46  std::vector<std::string> argumentMatch_;
47  bool eavesdrop_ = false;
48  std::string rule_;
49 
50  std::string buildRule() const {
51  std::string result;
52  switch (type_) {
53  case MessageType::Signal:
54  result = "type='signal',";
55  break;
56  case MessageType::MethodCall:
57  result = "type='method_call',";
58  break;
59  case MessageType::Reply:
60  result = "type='method_return',";
61  break;
62  case MessageType::Error:
63  result = "type='error',";
64  break;
65  default:
66  break;
67  }
68  if (!service_.empty()) {
69  result += stringutils::concat("sender='", service_, "',");
70  }
71  if (!destination_.empty()) {
72  result += stringutils::concat("destination='", destination_, "',");
73  }
74  if (!path_.empty()) {
75  result += stringutils::concat("path='", path_, "',");
76  }
77  if (!interface_.empty()) {
78  result += stringutils::concat("interface='", interface_, "',");
79  }
80  if (!name_.empty()) {
81  result += stringutils::concat("member='", name_, "',");
82  }
83  for (size_t i = 0; i < argumentMatch_.size(); i++) {
84  if (argumentMatch_[i] == MatchRule::nullArg) {
85  continue;
86  }
87  result +=
88  stringutils::concat("arg", i, "='", argumentMatch_[i], "',");
89  }
90  if (eavesdrop_) {
91  result += "eavesdrop='true',";
92  }
93  // remove trailing comma.
94  result.pop_back();
95  return result;
96  }
97 
98  bool check(Message &message, const std::string &alterName) const {
99 
100  if (!service_.empty() && service_ != message.sender() &&
101  alterName != message.sender()) {
102  return false;
103  }
104  if (!path_.empty() && path_ != message.path()) {
105  return false;
106  }
107  if (!interface_.empty() && interface_ != message.interface()) {
108  return false;
109  }
110  if (!name_.empty() && name_ != message.member()) {
111  return false;
112  }
113  if (!argumentMatch_.empty()) {
114  auto sig = message.signature();
115  auto args = splitDBusSignature(sig);
116  for (size_t i = 0; i < argumentMatch_.size(); i++) {
117  if (argumentMatch_[i] == MatchRule::nullArg) {
118  if (i < args.size()) {
119  message.skip();
120  }
121  continue;
122  }
123  if (i >= args.size() || args[i] != "s") {
124  return false;
125  }
126  std::string arg;
127  if (message >> arg) {
128  if (arg != argumentMatch_[i]) {
129  return false;
130  }
131  } else {
132  return false;
133  }
134  }
135  }
136  return true;
137  }
138 };
139 
140 MatchRule::MatchRule(std::string service, std::string path,
141  std::string interface, std::string name,
142  std::vector<std::string> argumentMatch)
143  : MatchRule(MessageType::Signal, std::move(service), "", std::move(path),
144  std::move(interface), std::move(name), std::move(argumentMatch),
145  false) {}
146 
147 MatchRule::MatchRule(MessageType type, std::string service,
148  std::string destination, std::string path,
149  std::string interface, std::string name,
150  std::vector<std::string> argumentMatch, bool eavesdrop)
151  : d_ptr(std::make_unique<MatchRulePrivate>(
152  type, std::move(service), std::move(destination), std::move(path),
153  std::move(interface), std::move(name), std::move(argumentMatch),
154  eavesdrop)) {}
155 
156 FCITX_DEFINE_DPTR_COPY_AND_DEFAULT_DTOR_AND_MOVE(MatchRule);
157 
158 const std::string &MatchRule::service() const noexcept {
159  FCITX_D();
160  return d->service_;
161 }
162 const std::string &MatchRule::destination() const noexcept {
163  FCITX_D();
164  return d->destination_;
165 }
166 
167 const std::string &MatchRule::path() const noexcept {
168  FCITX_D();
169  return d->path_;
170 }
171 
172 const std::string &MatchRule::interface() const noexcept {
173  FCITX_D();
174  return d->interface_;
175 }
176 
177 const std::string &MatchRule::name() const noexcept {
178  FCITX_D();
179  return d->name_;
180 }
181 
182 const std::vector<std::string> &MatchRule::argumentMatch() const noexcept {
183  FCITX_D();
184  return d->argumentMatch_;
185 }
186 
187 const std::string &MatchRule::rule() const noexcept {
188  FCITX_D();
189  return d->rule_;
190 }
191 
192 bool MatchRule::eavesdrop() const noexcept {
193  FCITX_D();
194  return d->eavesdrop_;
195 }
196 
197 bool MatchRule::check(Message &message, const std::string &alterName) const {
198  FCITX_D();
199  auto result = d->check(message, alterName);
200  message.rewind();
201  return result;
202 }
203 
204 } // namespace fcitx::dbus
Basic DBus type of a DBus message.
Definition: message.h:224
std::string path() const
Return the path of the message.
Definition: message.cpp:128
A dbus matching rule to be used with add match.
Definition: matchrule.h:36
void rewind()
Rewind the message to the beginning.
Definition: message.cpp:234
API for DBus message.
std::string sender() const
Return the sender of the message.
Definition: message.cpp:92
std::string member() const
Return the member of the message.
Definition: message.cpp:101
std::string interface() const
Return the interface of the message.
Definition: message.cpp:110
API for DBus matching rule.
void skip()
Skip the next data.
Definition: message.cpp:239
std::string signature() const
Return the signature of the message.
Definition: message.cpp:119