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