incremental
diff --git a/boost-dbus/include/dbus/message.hpp b/boost-dbus/include/dbus/message.hpp
new file mode 100644
index 0000000..aa5e89c
--- /dev/null
+++ b/boost-dbus/include/dbus/message.hpp
@@ -0,0 +1,224 @@
+// Copyright (c) Benjamin Kietzman (github.com/bkietz)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef DBUS_MESSAGE_HPP
+#define DBUS_MESSAGE_HPP
+
+#include <dbus/dbus.h>
+#include <dbus/element.hpp>
+#include <dbus/endpoint.hpp>
+#include <dbus/impl/message_iterator.hpp>
+#include <iostream>
+#include <vector>
+#include <boost/intrusive_ptr.hpp>
+#include <boost/utility/enable_if.hpp>
+
+inline void intrusive_ptr_add_ref(DBusMessage* m) { dbus_message_ref(m); }
+
+inline void intrusive_ptr_release(DBusMessage* m) { dbus_message_unref(m); }
+
+namespace dbus {
+
+class message {
+ boost::intrusive_ptr<DBusMessage> message_;
+
+ public:
+ /// Create a method call message
+ static message new_call(const endpoint& destination,
+ const string& method_name) {
+ return dbus_message_new_method_call(
+ destination.get_process_name().c_str(), destination.get_path().c_str(),
+ destination.get_interface().c_str(), method_name.c_str());
+ }
+
+ /// Create a method return message
+ static message new_return(message& call) {
+ return dbus_message_new_method_return(call);
+ }
+
+ /// Create an error message
+ static message new_error(message& call, const string& error_name,
+ const string& error_message) {
+ return dbus_message_new_error(call, error_name.c_str(),
+ error_message.c_str());
+ }
+
+ /// Create a signal message
+ static message new_signal(const endpoint& origin, const string& signal_name) {
+ return dbus_message_new_signal(origin.get_path().c_str(),
+ origin.get_interface().c_str(),
+ signal_name.c_str());
+ }
+
+ message() {}
+
+ message(DBusMessage* m) : message_(dbus_message_ref(m)) {}
+
+ operator DBusMessage*() { return message_.get(); }
+
+ operator const DBusMessage*() const { return message_.get(); }
+
+ string get_path() const {
+ return sanitize(dbus_message_get_path(message_.get()));
+ }
+
+ string get_interface() const {
+ return sanitize(dbus_message_get_interface(message_.get()));
+ }
+
+ string get_member() const {
+ return sanitize(dbus_message_get_member(message_.get()));
+ }
+
+ string get_type() const {
+ return sanitize(
+ dbus_message_type_to_string(dbus_message_get_type(message_.get())));
+ }
+
+ string get_sender() const {
+ return sanitize(dbus_message_get_sender(message_.get()));
+ }
+
+ string get_destination() const {
+ return sanitize(dbus_message_get_destination(message_.get()));
+ }
+
+ uint32 get_serial() { return dbus_message_get_serial(message_.get()); }
+
+ message& set_serial(uint32 serial) {
+ dbus_message_set_serial(message_.get(), serial);
+ return *this;
+ }
+
+ uint32 get_reply_serial() {
+ return dbus_message_get_reply_serial(message_.get());
+ }
+
+ message& set_reply_serial(uint32 reply_serial) {
+ dbus_message_set_reply_serial(message_.get(), reply_serial);
+ return *this;
+ }
+
+ struct packer {
+ impl::message_iterator iter_;
+ packer(message& m) { impl::message_iterator::init_append(m, iter_); }
+ template <typename Element>
+ packer& pack(const Element& e) {
+ return *this << e;
+ }
+ };
+ struct unpacker {
+ impl::message_iterator iter_;
+ unpacker(message& m) { impl::message_iterator::init(m, iter_); }
+
+ template <typename Element>
+ unpacker& unpack(Element& e) {
+ return *this >> e;
+ }
+ };
+
+ template <typename Element>
+ packer pack(const Element& e) {
+ return packer(*this).pack(e);
+ }
+
+ template <typename Element>
+ unpacker unpack(Element& e) {
+ return unpacker(*this).unpack(e);
+ }
+
+ private:
+ static std::string sanitize(const char* str) {
+ return (str == NULL) ? "(null)" : str;
+ }
+};
+
+template <typename Element>
+message::packer operator<<(message m, const Element& e) {
+ return message::packer(m).pack(e);
+}
+
+template <typename Element>
+typename boost::enable_if<is_fixed_type<Element>, message::packer&>::type
+operator<<(message::packer& p, const Element& e) {
+ p.iter_.append_basic(element<Element>::code, &e);
+ return p;
+}
+
+inline message::packer& operator<<(message::packer& p, const char* c) {
+ p.iter_.append_basic(element<string>::code, &c);
+ return p;
+}
+
+inline message::packer& operator<<(message::packer& p, const string& e) {
+ const char* c = e.c_str();
+ return p << c;
+}
+
+template <typename Element>
+message::unpacker operator>>(message m, Element& e) {
+ return message::unpacker(m).unpack(e);
+}
+
+template <typename Element>
+typename boost::enable_if<is_fixed_type<Element>, message::unpacker&>::type
+operator>>(message::unpacker& u, Element& e) {
+ u.iter_.get_basic(&e);
+ u.iter_.next();
+ return u;
+}
+
+inline message::unpacker& operator>>(message::unpacker& u, string& s) {
+ const char* c;
+ u.iter_.get_basic(&c);
+ s.assign(c);
+ u.iter_.next();
+ return u;
+}
+
+template <typename Element>
+inline message::unpacker& operator>>(message::unpacker& u,
+ std::vector<Element>& s) {
+ static_assert(std::is_same<Element, std::string>::value,
+ "only std::vector<std::string> is implemented for now");
+ impl::message_iterator sub;
+ u.iter_.recurse(sub);
+
+ const char* c;
+ while (sub.has_next()) {
+ sub.get_basic(&c);
+ s.emplace_back(c);
+ sub.next();
+ }
+
+ // TODO(ed)
+ // Make this generic for all types. The below code is close, but there's
+ // template issues and things I don't understand;
+ /*
+ auto e = message::unpacker(sub);
+ while (sub.has_next()) {
+ s.emplace_back();
+ Element& element = s.back();
+ e.unpack(element);
+ }
+*/
+ return u;
+}
+
+inline std::ostream& operator<<(std::ostream& os, const message& m) {
+ os << "type='" << m.get_type() << "',"
+ << "sender='" << m.get_sender() << "',"
+ << "interface='" << m.get_interface() << "',"
+ << "member='" << m.get_member() << "',"
+ << "path='" << m.get_path() << "',"
+ << "destination='" << m.get_destination() << "'";
+ return os;
+}
+
+} // namespace dbus
+
+#include <dbus/impl/message_iterator.ipp>
+
+#endif // DBUS_MESSAGE_HPP