1 // 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 18 inline void intrusive_ptr_add_ref(DBusMessage* m) { dbus_message_ref(m); } 19 20 inline void intrusive_ptr_release(DBusMessage* m) { dbus_message_unref(m); } 21 22 namespace dbus { 23 24 class 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 138 template <typename Element> 139 message::packer operator<<(message m, const Element& e) { 140 return message::packer(m).pack(e); 141 } 142 143 template <typename Element> 144 typename boost::enable_if<is_fixed_type<Element>, message::packer&>::type 145 operator<<(message::packer& p, const Element& e) { 146 p.iter_.append_basic(element<Element>::code, &e); 147 return p; 148 } 149 150 inline message::packer& operator<<(message::packer& p, const char* c) { 151 p.iter_.append_basic(element<string>::code, &c); 152 return p; 153 } 154 155 inline message::packer& operator<<(message::packer& p, const string& e) { 156 const char* c = e.c_str(); 157 return p << c; 158 } 159 160 template <typename Element> 161 message::unpacker operator>>(message m, Element& e) { 162 return message::unpacker(m).unpack(e); 163 } 164 165 template <typename Element> 166 typename boost::enable_if<is_fixed_type<Element>, message::unpacker&>::type 167 operator>>(message::unpacker& u, Element& e) { 168 u.iter_.get_basic(&e); 169 u.iter_.next(); 170 return u; 171 } 172 173 inline 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 181 template <typename Element> 182 inline message::unpacker& operator>>(message::unpacker& u, 183 std::vector<Element>& s) { 184 static_assert(std::is_same<Element, std::string>::value, "only std::vector<std::string> is implemented for now"); 185 impl::message_iterator sub; 186 u.iter_.recurse(sub); 187 188 const char* c; 189 while (sub.has_next()) { 190 sub.get_basic(&c); 191 s.emplace_back(c); 192 sub.next(); 193 } 194 195 // TODO(ed) 196 // Make this generic for all types. The below code is close, but there's 197 // template issues and things I don't understand; 198 /* 199 auto e = message::unpacker(sub); 200 while (sub.has_next()) { 201 s.emplace_back(); 202 Element& element = s.back(); 203 e.unpack(element); 204 } 205 */ 206 return u; 207 } 208 209 inline std::ostream& operator<<(std::ostream& os, const message& m) { 210 os << "type='" << m.get_type() << "'," 211 << "sender='" << m.get_sender() << "'," 212 << "interface='" << m.get_interface() << "'," 213 << "member='" << m.get_member() << "'," 214 << "path='" << m.get_path() << "'," 215 << "destination='" << m.get_destination() << "'"; 216 return os; 217 } 218 219 } // namespace dbus 220 221 #include <dbus/impl/message_iterator.ipp> 222 223 #endif // DBUS_MESSAGE_HPP 224