blob: aa5e89c74a9ad9245dc77308994568a508142dc1 [file] [log] [blame]
Ed Tanousc9b55212017-06-12 13:25:51 -07001// Copyright (c) Benjamin Kietzman (github.com/bkietz)
2//
3// Distributed under the Boost Software License, Version 1.0. (See accompanying
4// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5
6#ifndef DBUS_MESSAGE_HPP
7#define DBUS_MESSAGE_HPP
8
9#include <dbus/dbus.h>
10#include <dbus/element.hpp>
11#include <dbus/endpoint.hpp>
12#include <dbus/impl/message_iterator.hpp>
13#include <iostream>
14#include <vector>
15#include <boost/intrusive_ptr.hpp>
16#include <boost/utility/enable_if.hpp>
17
18inline void intrusive_ptr_add_ref(DBusMessage* m) { dbus_message_ref(m); }
19
20inline void intrusive_ptr_release(DBusMessage* m) { dbus_message_unref(m); }
21
22namespace dbus {
23
24class message {
25 boost::intrusive_ptr<DBusMessage> message_;
26
27 public:
28 /// Create a method call message
29 static message new_call(const endpoint& destination,
30 const string& method_name) {
31 return dbus_message_new_method_call(
32 destination.get_process_name().c_str(), destination.get_path().c_str(),
33 destination.get_interface().c_str(), method_name.c_str());
34 }
35
36 /// Create a method return message
37 static message new_return(message& call) {
38 return dbus_message_new_method_return(call);
39 }
40
41 /// Create an error message
42 static message new_error(message& call, const string& error_name,
43 const string& error_message) {
44 return dbus_message_new_error(call, error_name.c_str(),
45 error_message.c_str());
46 }
47
48 /// Create a signal message
49 static message new_signal(const endpoint& origin, const string& signal_name) {
50 return dbus_message_new_signal(origin.get_path().c_str(),
51 origin.get_interface().c_str(),
52 signal_name.c_str());
53 }
54
55 message() {}
56
57 message(DBusMessage* m) : message_(dbus_message_ref(m)) {}
58
59 operator DBusMessage*() { return message_.get(); }
60
61 operator const DBusMessage*() const { return message_.get(); }
62
63 string get_path() const {
64 return sanitize(dbus_message_get_path(message_.get()));
65 }
66
67 string get_interface() const {
68 return sanitize(dbus_message_get_interface(message_.get()));
69 }
70
71 string get_member() const {
72 return sanitize(dbus_message_get_member(message_.get()));
73 }
74
75 string get_type() const {
76 return sanitize(
77 dbus_message_type_to_string(dbus_message_get_type(message_.get())));
78 }
79
80 string get_sender() const {
81 return sanitize(dbus_message_get_sender(message_.get()));
82 }
83
84 string get_destination() const {
85 return sanitize(dbus_message_get_destination(message_.get()));
86 }
87
88 uint32 get_serial() { return dbus_message_get_serial(message_.get()); }
89
90 message& set_serial(uint32 serial) {
91 dbus_message_set_serial(message_.get(), serial);
92 return *this;
93 }
94
95 uint32 get_reply_serial() {
96 return dbus_message_get_reply_serial(message_.get());
97 }
98
99 message& set_reply_serial(uint32 reply_serial) {
100 dbus_message_set_reply_serial(message_.get(), reply_serial);
101 return *this;
102 }
103
104 struct packer {
105 impl::message_iterator iter_;
106 packer(message& m) { impl::message_iterator::init_append(m, iter_); }
107 template <typename Element>
108 packer& pack(const Element& e) {
109 return *this << e;
110 }
111 };
112 struct unpacker {
113 impl::message_iterator iter_;
114 unpacker(message& m) { impl::message_iterator::init(m, iter_); }
115
116 template <typename Element>
117 unpacker& unpack(Element& e) {
118 return *this >> e;
119 }
120 };
121
122 template <typename Element>
123 packer pack(const Element& e) {
124 return packer(*this).pack(e);
125 }
126
127 template <typename Element>
128 unpacker unpack(Element& e) {
129 return unpacker(*this).unpack(e);
130 }
131
132 private:
133 static std::string sanitize(const char* str) {
134 return (str == NULL) ? "(null)" : str;
135 }
136};
137
138template <typename Element>
139message::packer operator<<(message m, const Element& e) {
140 return message::packer(m).pack(e);
141}
142
143template <typename Element>
144typename boost::enable_if<is_fixed_type<Element>, message::packer&>::type
145operator<<(message::packer& p, const Element& e) {
146 p.iter_.append_basic(element<Element>::code, &e);
147 return p;
148}
149
150inline message::packer& operator<<(message::packer& p, const char* c) {
151 p.iter_.append_basic(element<string>::code, &c);
152 return p;
153}
154
155inline message::packer& operator<<(message::packer& p, const string& e) {
156 const char* c = e.c_str();
157 return p << c;
158}
159
160template <typename Element>
161message::unpacker operator>>(message m, Element& e) {
162 return message::unpacker(m).unpack(e);
163}
164
165template <typename Element>
166typename boost::enable_if<is_fixed_type<Element>, message::unpacker&>::type
167operator>>(message::unpacker& u, Element& e) {
168 u.iter_.get_basic(&e);
169 u.iter_.next();
170 return u;
171}
172
173inline message::unpacker& operator>>(message::unpacker& u, string& s) {
174 const char* c;
175 u.iter_.get_basic(&c);
176 s.assign(c);
177 u.iter_.next();
178 return u;
179}
180
181template <typename Element>
182inline message::unpacker& operator>>(message::unpacker& u,
183 std::vector<Element>& s) {
184 static_assert(std::is_same<Element, std::string>::value,
185 "only std::vector<std::string> is implemented for now");
186 impl::message_iterator sub;
187 u.iter_.recurse(sub);
188
189 const char* c;
190 while (sub.has_next()) {
191 sub.get_basic(&c);
192 s.emplace_back(c);
193 sub.next();
194 }
195
196 // TODO(ed)
197 // Make this generic for all types. The below code is close, but there's
198 // template issues and things I don't understand;
199 /*
200 auto e = message::unpacker(sub);
201 while (sub.has_next()) {
202 s.emplace_back();
203 Element& element = s.back();
204 e.unpack(element);
205 }
206*/
207 return u;
208}
209
210inline std::ostream& operator<<(std::ostream& os, const message& m) {
211 os << "type='" << m.get_type() << "',"
212 << "sender='" << m.get_sender() << "',"
213 << "interface='" << m.get_interface() << "',"
214 << "member='" << m.get_member() << "',"
215 << "path='" << m.get_path() << "',"
216 << "destination='" << m.get_destination() << "'";
217 return os;
218}
219
220} // namespace dbus
221
222#include <dbus/impl/message_iterator.ipp>
223
224#endif // DBUS_MESSAGE_HPP