8 #include "../message.h" 17 #include <dbus/dbus-protocol.h> 18 #include <dbus/dbus.h> 19 #include "../../macros.h" 20 #include "../../misc.h" 21 #include "../../unixfd.h" 22 #include "../variant.h" 24 #include "message_p.h" 28 static char toDBusType(Container::Type type) {
31 case Container::Type::Array:
34 case Container::Type::DictEntry:
35 t = DBUS_TYPE_DICT_ENTRY;
37 case Container::Type::Struct:
40 case Container::Type::Variant:
41 t = DBUS_TYPE_VARIANT;
44 throw std::runtime_error(
"invalid container type");
49 Message::Message() : d_ptr(
std::make_unique<MessagePrivate>()) {}
51 FCITX_DEFINE_DEFAULT_DTOR_AND_MOVE(Message)
55 auto *dmsg = dbus_message_new_method_return(d->msg());
59 return MessagePrivate::fromDBusMessage(d->bus_, dmsg,
true,
false);
64 auto *dmsg = dbus_message_new_error(d->msg(), name, message);
68 return MessagePrivate::fromDBusMessage(d->bus_, dmsg,
false,
false);
79 dbus_message_set_destination(d->msg(), dest.c_str());
88 const auto *result = dbus_message_get_destination(d->msg());
89 return result ? result :
"";
97 const auto *sender = dbus_message_get_sender(d->msg());
98 return sender ? sender :
"";
106 const auto *member = dbus_message_get_member(d->msg());
107 return member ? member :
"";
115 const auto *
interface = dbus_message_get_interface(d->msg());
116 return interface ? interface : "";
124 const auto *signature = dbus_message_get_signature(d->msg());
125 return signature ? signature :
"";
130 const auto *path = dbus_message_get_path(d->msg());
131 return path ? path :
"";
137 const auto *err = dbus_message_get_error_name(d->msg());
138 return err ? err :
"";
146 char *message =
nullptr;
147 if (dbus_message_get_args(d->msg(),
nullptr, DBUS_TYPE_STRING, &message,
148 DBUS_TYPE_INVALID)) {
161 int convertTimeout(uint64_t timeout) {
162 int milliTimout = timeout / 1000;
163 if (timeout > 0 && milliTimout == 0) {
165 }
else if (timeout == 0) {
166 milliTimout = DBUS_TIMEOUT_USE_DEFAULT;
173 ScopedDBusError error;
174 auto *bus = d->bus_.get();
178 DBusMessage *reply = dbus_connection_send_with_reply_and_block(
179 bus->conn_.get(), d->msg(), convertTimeout(usec), &error.error());
181 return MessagePrivate::fromDBusError(error.error());
183 return MessagePrivate::fromDBusMessage(bus->watch(), reply,
false,
false);
186 void DBusPendingCallNotifyCallback(DBusPendingCall *reply,
void *userdata) {
187 auto *slot =
static_cast<DBusAsyncCallSlot *
>(userdata);
192 auto msg = MessagePrivate::fromDBusMessage(
193 slot->bus_, dbus_pending_call_steal_reply(reply),
false,
false);
194 slot->callback_(msg);
198 MessageCallback callback) {
200 auto *bus = d->bus_.get();
204 auto slot = std::make_unique<DBusAsyncCallSlot>(std::move(callback));
205 DBusPendingCall *call =
nullptr;
206 if (!dbus_connection_send_with_reply(bus->conn_.get(), d->msg(), &call,
207 convertTimeout(usec))) {
211 dbus_pending_call_set_notify(call, DBusPendingCallNotifyCallback,
212 slot.get(),
nullptr);
214 slot->bus_ = bus->watch();
219 Message::operator bool()
const {
221 return d->msg() && d->lastError_ >= 0;
241 dbus_message_iter_next(d->iterator());
247 UniqueCPtr<char, dbus_free> content;
248 auto container = dbus_message_iter_get_arg_type(d->iterator());
249 if (container == DBUS_TYPE_ARRAY || container == DBUS_TYPE_STRUCT ||
250 container == DBUS_TYPE_VARIANT) {
251 auto *subIter = d->pushReadIterator();
252 content.reset(dbus_message_iter_get_signature(subIter));
256 return {container, content.get()};
258 return {container,
""};
263 auto *bus = d->bus_.get();
265 if (dbus_connection_send(bus->conn_.get(), d->msg(),
nullptr)) {
272 Message &Message::operator<<(
bool b) {
274 dbus_bool_t i = b ? 1 : 0;
276 dbus_message_iter_append_basic(d->iterator(), DBUS_TYPE_BOOLEAN, &i);
280 Message &Message::operator>>(
bool &b) {
283 if (dbus_message_iter_get_arg_type(d->iterator()) == DBUS_TYPE_BOOLEAN) {
284 dbus_message_iter_get_basic(d->iterator(), &i);
286 dbus_message_iter_next(d->iterator());
292 #define _MARSHALL_FUNC(TYPE, TYPE2) \ 293 Message &Message::operator<<(TYPE v) { \ 298 d->lastError_ = !dbus_message_iter_append_basic( \ 299 d->iterator(), DBUS_TYPE_##TYPE2, &v); \ 302 Message &Message::operator>>(TYPE &v) { \ 307 if (dbus_message_iter_get_arg_type(d->iterator()) == \ 308 DBUS_TYPE_##TYPE2) { \ 309 dbus_message_iter_get_basic(d->iterator(), &v); \ 310 dbus_message_iter_next(d->iterator()); \ 312 d->lastError_ = -EINVAL; \ 318 _MARSHALL_FUNC(uint8_t, BYTE)
319 _MARSHALL_FUNC(int16_t, INT16)
320 _MARSHALL_FUNC(uint16_t, UINT16)
321 _MARSHALL_FUNC(int32_t, INT32)
322 _MARSHALL_FUNC(uint32_t, UINT32)
323 _MARSHALL_FUNC(int64_t, INT64)
324 _MARSHALL_FUNC(uint64_t, UINT64)
325 _MARSHALL_FUNC(
double, DOUBLE)
327 Message &Message::operator<<(
const std::string &s) {
332 Message &Message::operator<<(
const char *s) {
338 !dbus_message_iter_append_basic(d->iterator(), DBUS_TYPE_STRING, &s);
342 Message &Message::operator>>(std::string &s) {
349 if (dbus_message_iter_get_arg_type(d->iterator()) == DBUS_TYPE_STRING) {
350 dbus_message_iter_get_basic(d->iterator(), &p);
352 dbus_message_iter_next(d->iterator());
354 d->lastError_ = -EINVAL;
364 const char *c = o.path().c_str();
365 d->lastError_ = !dbus_message_iter_append_basic(d->iterator(),
366 DBUS_TYPE_OBJECT_PATH, &c);
376 if (dbus_message_iter_get_arg_type(d->iterator()) == DBUS_TYPE_STRING) {
377 dbus_message_iter_get_basic(d->iterator(), &p);
379 dbus_message_iter_next(d->iterator());
381 d->lastError_ = -EINVAL;
391 const char *c = s.sig().c_str();
393 !dbus_message_iter_append_basic(d->iterator(), DBUS_TYPE_SIGNATURE, &c);
403 if (dbus_message_iter_get_arg_type(d->iterator()) == DBUS_TYPE_SIGNATURE) {
404 dbus_message_iter_get_basic(d->iterator(), &p);
406 dbus_message_iter_next(d->iterator());
408 d->lastError_ = -EINVAL;
420 dbus_message_iter_append_basic(d->iterator(), DBUS_TYPE_UNIX_FD, &f);
430 if (dbus_message_iter_get_arg_type(d->iterator()) == DBUS_TYPE_UNIX_FD) {
431 dbus_message_iter_get_basic(d->iterator(), &f);
433 dbus_message_iter_next(d->iterator());
435 d->lastError_ = -EINVAL;
445 d->pushWriteIterator(toDBusType(c.type()), c.content().sig());
455 if (dbus_message_iter_get_arg_type(d->iterator()) != toDBusType(c.type())) {
456 d->lastError_ = -EINVAL;
458 DBusMessageIter *subIter = d->pushReadIterator();
460 if (c.type() != Container::Type::DictEntry &&
461 c.type() != Container::Type::Struct) {
462 UniqueCPtr<char, dbus_free> content(
463 dbus_message_iter_get_signature(subIter));
464 if (!content || content.get() != c.content().sig()) {
465 d->lastError_ = -EINVAL;
487 dbus_message_iter_next(d->iterator());
495 if (*
this <<
Container(Container::Type::Variant,
497 v.writeToMessage(*
this);
513 auto type = peekType();
514 if (type.first !=
'v') {
515 d->lastError_ = -EINVAL;
518 if (
auto helper = lookupVariantType(type.second)) {
521 auto data = helper->copy(
nullptr);
522 helper->deserialize(*
this, data.get());
524 variant.setRawData(std::move(data), std::move(helper));
529 dbus_message_iter_next(d->iterator());
bool send()
Send this message.
Helper type for serialization, should not be used directly.
Class wrap around the unix fd.
std::string destination() const
Return the destination of the message.
Basic DBus type of a DBus message.
std::string path() const
Return the path of the message.
String like type object signature 'g'.
Message createError(const char *name, const char *message) const
Create a error reply to this message.
void rewind()
Rewind the message to the beginning.
Helper type for serialization, should not be used directly.
std::string sender() const
Return the sender of the message.
MessageType type() const
Return the message type.
void * nativeHandle() const
Return the low level internal pointer of the message.
std::string member() const
Return the member of the message.
std::pair< char, std::string > peekType()
Check the next type of data in the message.
std::string interface() const
Return the interface of the message.
int fd() const noexcept
Get the internal fd.
void setDestination(const std::string &dest)
Set the destination of the message.
const std::string & signature() const
Return the signature of the data.
std::string errorMessage() const
Return the error message of the message.
Message call(uint64_t usec)
Synchronously call a dbus method with a timeout in microseconds.
void skip()
Skip the next data.
Variant type to be used to box or unbox the dbus variant type.
String like type object path 'o'.
void give(int fd) noexcept
Set a new FD and transfer the ownership to UnixFD.
std::string signature() const
Return the signature of the message.
bool end() const
Check if message reaches end.
void resetError()
Clear serialization error.
std::unique_ptr< Slot > callAsync(uint64_t usec, MessageCallback callback)
Asynchronously call a dbus method with a timeout in microseconds.
std::string errorName() const
Return the error name of the message.