incremental
diff --git a/boost-dbus/include/dbus/connection.hpp b/boost-dbus/include/dbus/connection.hpp
new file mode 100644
index 0000000..a7185a5
--- /dev/null
+++ b/boost-dbus/include/dbus/connection.hpp
@@ -0,0 +1,130 @@
+// 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_CONNECTION_HPP
+#define DBUS_CONNECTION_HPP
+
+#include <dbus/connection_service.hpp>
+#include <dbus/element.hpp>
+#include <dbus/message.hpp>
+#include <chrono>
+#include <string>
+#include <boost/asio.hpp>
+
+namespace dbus {
+
+class filter;
+class match;
+
+/// Root D-Bus IO object
+/**
+ * A connection to a bus, through which messages may be sent or received.
+ */
+class connection : public boost::asio::basic_io_object<connection_service> {
+ public:
+ /// Open a connection to a specified address.
+ /**
+ * @param io_service The io_service object that the connection will use to
+ * wire D-Bus for asynchronous operation.
+ *
+ * @param address The address of the bus to connect to.
+ *
+ * @throws boost::system::system_error When opening the connection failed.
+ */
+ connection(boost::asio::io_service& io, const string& address)
+ : basic_io_object<connection_service>(io) {
+ this->get_service().open(this->get_implementation(), address);
+ }
+
+ /// Open a connection to a well-known bus.
+ /**
+ * D-Bus connections are usually opened to well-known buses like the
+ * system or session bus.
+ *
+ * @param bus The well-known bus to connect to.
+ *
+ * @throws boost::system::system_error When opening the connection failed.
+ */
+ // TODO: change this unsigned to an enumeration
+ connection(boost::asio::io_service& io, const int bus)
+ : basic_io_object<connection_service>(io) {
+ this->get_service().open(this->get_implementation(), bus);
+ }
+
+ /// Send a message.
+ /**
+ * @param m The message to send.
+ *
+ * @return The reply received.
+ *
+ * @throws boost::system::system_error When the response timed out or
+ * there was some other error.
+ */
+ message send(message& m) {
+ return this->get_service().send(this->get_implementation(), m);
+ }
+
+ /// Send a message.
+ /**
+ * @param m The message to send.
+ *
+ * @param t Time to wait for a reply. Passing 0 as the timeout means
+ * that you wish to ignore the reply. (Or catch it later somehow...)
+ *
+ * @return The reply received.
+ *
+ * @throws boost::system::system_error When the response timed out (if
+ * timeout was not 0), or there was some other error.
+ */
+ template <typename Duration>
+ message send(message& m, const Duration& t) {
+ return this->get_service().send(this->get_implementation(), m, t);
+ }
+
+ /// Send a message asynchronously.
+ /**
+ * @param m The message to send.
+ *
+ * @param handler Handler for the reply.
+ *
+ * @return Asynchronous result
+ */
+ template <typename MessageHandler>
+ inline BOOST_ASIO_INITFN_RESULT_TYPE(MessageHandler,
+ void(boost::system::error_code, message))
+ async_send(message& m, BOOST_ASIO_MOVE_ARG(MessageHandler) handler) {
+ return this->get_service().async_send(
+ this->get_implementation(), m,
+ BOOST_ASIO_MOVE_CAST(MessageHandler)(handler));
+ }
+
+ /// Create a new match.
+ void new_match(match& m) {
+ this->get_service().new_match(this->get_implementation(), m);
+ }
+
+ /// Destroy a match.
+ void delete_match(match& m) {
+ this->get_service().delete_match(this->get_implementation(), m);
+ }
+
+ /// Create a new filter.
+ void new_filter(filter& f) {
+ this->get_service().new_filter(this->get_implementation(), f);
+ }
+
+ /// Destroy a filter.
+ void delete_filter(filter& f) {
+ this->get_service().delete_filter(this->get_implementation(), f);
+ }
+
+ // FIXME the only way around this I see is to expose start() here, which seems
+ // ugly
+ friend class filter;
+};
+
+} // namespace dbus
+
+#endif // DBUS_CONNECTION_HPP
diff --git a/boost-dbus/include/dbus/connection_service.hpp b/boost-dbus/include/dbus/connection_service.hpp
new file mode 100644
index 0000000..28318c6
--- /dev/null
+++ b/boost-dbus/include/dbus/connection_service.hpp
@@ -0,0 +1,105 @@
+// 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_CONNECTION_SERVICE_HPP
+#define DBUS_CONNECTION_SERVICE_HPP
+
+#include <boost/asio.hpp>
+#include <boost/asio/io_service.hpp>
+
+#include <dbus/detail/async_send_op.hpp>
+#include <dbus/element.hpp>
+#include <dbus/error.hpp>
+#include <dbus/message.hpp>
+
+#include <dbus/impl/connection.ipp>
+
+namespace dbus {
+namespace bus {
+static const int session = DBUS_BUS_SESSION;
+static const int system = DBUS_BUS_SYSTEM;
+static const int starter = DBUS_BUS_STARTER;
+} // namespace bus
+
+class filter;
+class match;
+class connection;
+
+class connection_service : public boost::asio::detail::service_base<connection_service> {
+ public:
+ typedef impl::connection implementation_type;
+
+ inline explicit connection_service(boost::asio::io_service& io)
+ : boost::asio::detail::service_base<connection_service>(io) {}
+
+ inline void construct(implementation_type& impl) {}
+
+ inline void destroy(implementation_type& impl) {}
+
+ inline void shutdown_service() {
+ // TODO is there anything that needs shutting down?
+ }
+
+ inline void open(implementation_type& impl, const string& address) {
+ boost::asio::io_service& io = this->get_io_service();
+
+ impl.open(io, address);
+ }
+
+ inline void open(implementation_type& impl, const int bus = bus::system) {
+ boost::asio::io_service& io = this->get_io_service();
+
+ impl.open(io, bus);
+ }
+
+ inline message send(implementation_type& impl, message& m) {
+ return impl.send_with_reply_and_block(m);
+ }
+
+ template <typename Duration>
+ inline message send(implementation_type& impl, message& m, const Duration& timeout) {
+ if (timeout == Duration::zero()) {
+ // TODO this can return false if it failed
+ impl.send(m);
+ return message();
+ } else {
+ return impl.send_with_reply_and_block(
+ m, std::chrono::milliseconds(timeout).count());
+ }
+ }
+
+ template <typename MessageHandler>
+ inline BOOST_ASIO_INITFN_RESULT_TYPE(MessageHandler,
+ void(boost::system::error_code, message))
+ async_send(implementation_type& impl, message& m,
+ BOOST_ASIO_MOVE_ARG(MessageHandler) handler) {
+ // begin asynchronous operation
+ impl.start(this->get_io_service());
+
+ boost::asio::detail::async_result_init<
+ MessageHandler, void(boost::system::error_code, message)>
+ init(BOOST_ASIO_MOVE_CAST(MessageHandler)(handler));
+ detail::async_send_op<typename boost::asio::handler_type<
+ MessageHandler, void(boost::system::error_code, message)>::type>(
+ this->get_io_service(),
+ BOOST_ASIO_MOVE_CAST(MessageHandler)(init.handler))(impl, m);
+
+ return init.result.get();
+ }
+
+ private:
+ friend connection;
+ inline void new_match(implementation_type& impl, match& m);
+
+ inline void delete_match(implementation_type& impl, match& m);
+
+ inline void new_filter(implementation_type& impl, filter& f);
+
+ inline void delete_filter(implementation_type& impl, filter& f);
+};
+
+} // namespace dbus
+
+#endif // DBUS_CONNECTION_SERVICE_HPP
diff --git a/boost-dbus/include/dbus/detail/async_send_op.hpp b/boost-dbus/include/dbus/detail/async_send_op.hpp
new file mode 100644
index 0000000..996a4e7
--- /dev/null
+++ b/boost-dbus/include/dbus/detail/async_send_op.hpp
@@ -0,0 +1,78 @@
+// 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_ASYNC_SEND_OP_HPP
+#define DBUS_ASYNC_SEND_OP_HPP
+
+#include <boost/scoped_ptr.hpp>
+
+#include <dbus/dbus.h>
+#include <dbus/error.hpp>
+#include <dbus/message.hpp>
+
+#include <dbus/impl/connection.ipp>
+
+namespace dbus {
+namespace detail {
+
+template <typename MessageHandler>
+struct async_send_op {
+ boost::asio::io_service& io_;
+ message message_;
+ MessageHandler handler_;
+ async_send_op(boost::asio::io_service& io,BOOST_ASIO_MOVE_ARG(MessageHandler) handler);
+ static void callback(DBusPendingCall* p, void* userdata); // for C API
+ void operator()(impl::connection& c, message& m); // initiate operation
+ void operator()(); // bound completion handler form
+};
+
+template <typename MessageHandler>
+async_send_op<MessageHandler>::async_send_op(boost::asio::io_service& io,BOOST_ASIO_MOVE_ARG(MessageHandler)handler)
+ : io_(io), handler_(BOOST_ASIO_MOVE_CAST(MessageHandler)(handler)) {}
+
+template <typename MessageHandler>
+void async_send_op<MessageHandler>::operator()(impl::connection& c,
+ message& m) {
+ DBusPendingCall* p;
+ c.send_with_reply(m, &p, -1);
+
+ // We have to throw this onto the heap so that the
+ // C API can store it as `void *userdata`
+ async_send_op* op =
+ new async_send_op(BOOST_ASIO_MOVE_CAST(async_send_op)(*this));
+
+ dbus_pending_call_set_notify(p, &callback, op, NULL);
+
+ // FIXME Race condition: another thread might have
+ // processed the pending call's reply before a notify
+ // function could be set. If so, the notify function
+ // will never trigger, so it must be called manually:
+ if (dbus_pending_call_get_completed(p)) {
+ // TODO: does this work, or might it call the notify
+ // function too many times? Might have to use steal_reply
+ // callback(p, op);
+ }
+}
+
+template <typename MessageHandler>
+void async_send_op<MessageHandler>::callback(DBusPendingCall* p,
+ void* userdata) {
+ boost::scoped_ptr<async_send_op> op(static_cast<async_send_op*>(userdata));
+
+ op->message_ = dbus_pending_call_steal_reply(p);
+ dbus_pending_call_unref(p);
+
+ op->io_.post(BOOST_ASIO_MOVE_CAST(async_send_op)(*op));
+}
+
+template <typename MessageHandler>
+void async_send_op<MessageHandler>::operator()() {
+ handler_(error(message_).error_code(), message_);
+}
+
+} // namespace detail
+} // namespace dbus
+
+#endif // DBUS_ASYNC_SEND_OP_HPP
diff --git a/boost-dbus/include/dbus/detail/queue.hpp b/boost-dbus/include/dbus/detail/queue.hpp
new file mode 100644
index 0000000..c435af3
--- /dev/null
+++ b/boost-dbus/include/dbus/detail/queue.hpp
@@ -0,0 +1,98 @@
+// 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_QUEUE_HPP
+#define DBUS_QUEUE_HPP
+
+#include <deque>
+#include <functional>
+#include <boost/asio.hpp>
+#include <boost/asio/detail/mutex.hpp>
+
+namespace dbus {
+namespace detail {
+
+template <typename Message>
+class queue {
+ public:
+ typedef ::boost::asio::detail::mutex mutex_type;
+ typedef Message message_type;
+ typedef std::function<void(boost::system::error_code, Message)> handler_type;
+
+ private:
+ boost::asio::io_service& io;
+ mutex_type mutex;
+ std::deque<message_type> messages;
+ std::deque<handler_type> handlers;
+
+ public:
+ queue(boost::asio::io_service& io_service) : io(io_service) {}
+
+ private:
+ class closure {
+ handler_type handler_;
+ message_type message_;
+ boost::system::error_code error_;
+
+ public:
+ void operator()() { handler_(error_, message_); }
+ closure(BOOST_ASIO_MOVE_ARG(handler_type) h, Message m,
+ boost::system::error_code e = boost::system::error_code())
+ : handler_(h), message_(m), error_(e) {}
+ };
+
+ public:
+ void push(message_type m) {
+ mutex_type::scoped_lock lock(mutex);
+ if (handlers.empty())
+ messages.push_back(m);
+ else {
+ handler_type h = handlers.front();
+ handlers.pop_front();
+
+ lock.unlock();
+
+ io.post(closure(BOOST_ASIO_MOVE_CAST(handler_type)(h), m));
+ }
+ }
+
+ template <typename MessageHandler>
+ inline BOOST_ASIO_INITFN_RESULT_TYPE(MessageHandler,
+ void(boost::system::error_code,
+ message_type))
+ async_pop(BOOST_ASIO_MOVE_ARG(MessageHandler) h) {
+ typedef ::boost::asio::detail::async_result_init<
+ MessageHandler, void(boost::system::error_code, message_type)>
+ init_type;
+
+ mutex_type::scoped_lock lock(mutex);
+ if (messages.empty()) {
+ init_type init(BOOST_ASIO_MOVE_CAST(MessageHandler)(h));
+
+ handlers.push_back(init.handler);
+
+ lock.unlock();
+
+ return init.result.get();
+
+ } else {
+ message_type m = messages.front();
+ messages.pop_front();
+
+ lock.unlock();
+
+ init_type init(BOOST_ASIO_MOVE_CAST(MessageHandler)(h));
+
+ io.post(closure(BOOST_ASIO_MOVE_CAST(handler_type)(init.handler), m));
+
+ return init.result.get();
+ }
+ }
+};
+
+} // namespace detail
+} // namespace dbus
+
+#endif // DBUS_QUEUE_HPP
diff --git a/boost-dbus/include/dbus/detail/watch_timeout.hpp b/boost-dbus/include/dbus/detail/watch_timeout.hpp
new file mode 100644
index 0000000..ef2e708
--- /dev/null
+++ b/boost-dbus/include/dbus/detail/watch_timeout.hpp
@@ -0,0 +1,151 @@
+// 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_WATCH_TIMEOUT_HPP
+#define DBUS_WATCH_TIMEOUT_HPP
+
+#include <dbus/dbus.h>
+#include <boost/asio/generic/stream_protocol.hpp>
+#include <boost/asio/steady_timer.hpp>
+
+#include <chrono>
+
+namespace dbus {
+namespace detail {
+
+static void watch_toggled(DBusWatch *dbus_watch, void *data);
+struct watch_handler {
+ DBusWatchFlags flags;
+ DBusWatch *dbus_watch;
+ watch_handler(DBusWatchFlags f, DBusWatch *w) : flags(f), dbus_watch(w) {}
+ void operator()(boost::system::error_code ec, size_t) {
+ if (ec) return;
+ dbus_watch_handle(dbus_watch, flags);
+
+ boost::asio::generic::stream_protocol::socket &socket = *static_cast<boost::asio::generic::stream_protocol::socket *>(
+ dbus_watch_get_data(dbus_watch));
+
+ watch_toggled(dbus_watch, &socket.get_io_service());
+ }
+};
+static void watch_toggled(DBusWatch *dbus_watch, void *data) {
+ boost::asio::generic::stream_protocol::socket &socket =
+ *static_cast<boost::asio::generic::stream_protocol::socket *>(dbus_watch_get_data(dbus_watch));
+
+ if (dbus_watch_get_enabled(dbus_watch)) {
+ if (dbus_watch_get_flags(dbus_watch) & DBUS_WATCH_READABLE)
+ socket.async_read_some(boost::asio::null_buffers(),
+ watch_handler(DBUS_WATCH_READABLE, dbus_watch));
+
+ if (dbus_watch_get_flags(dbus_watch) & DBUS_WATCH_WRITABLE)
+ socket.async_write_some(boost::asio::null_buffers(),
+ watch_handler(DBUS_WATCH_WRITABLE, dbus_watch));
+
+ } else {
+ socket.cancel();
+ }
+}
+
+static dbus_bool_t add_watch(DBusWatch *dbus_watch, void *data) {
+ if (!dbus_watch_get_enabled(dbus_watch)) return TRUE;
+
+ boost::asio::io_service &io = *static_cast<boost::asio::io_service *>(data);
+
+ int fd = dbus_watch_get_unix_fd(dbus_watch);
+
+ if (fd == -1)
+ // socket based watches
+ fd = dbus_watch_get_socket(dbus_watch);
+
+ boost::asio::generic::stream_protocol::socket &socket = *new boost::asio::generic::stream_protocol::socket(io);
+
+ socket.assign(boost::asio::generic::stream_protocol(0, 0), fd);
+
+ dbus_watch_set_data(dbus_watch, &socket, NULL);
+
+ watch_toggled(dbus_watch, &io);
+ return TRUE;
+}
+
+static void remove_watch(DBusWatch *dbus_watch, void *data) {
+ delete static_cast<boost::asio::generic::stream_protocol::socket *>(
+ dbus_watch_get_data(dbus_watch));
+}
+
+struct timeout_handler {
+ DBusTimeout *dbus_timeout;
+ timeout_handler(DBusTimeout *t) : dbus_timeout(t) {}
+ void operator()(boost::system::error_code ec) {
+ if (ec) return;
+ dbus_timeout_handle(dbus_timeout);
+ }
+};
+
+static void timeout_toggled(DBusTimeout *dbus_timeout, void *data) {
+ boost::asio::steady_timer &timer =
+ *static_cast<boost::asio::steady_timer *>(dbus_timeout_get_data(dbus_timeout));
+
+ if (dbus_timeout_get_enabled(dbus_timeout)) {
+ boost::asio::steady_timer::duration interval =
+ std::chrono::milliseconds(dbus_timeout_get_interval(dbus_timeout));
+ timer.expires_from_now(interval);
+ timer.cancel();
+ timer.async_wait(timeout_handler(dbus_timeout));
+ } else {
+ timer.cancel();
+ }
+}
+
+static dbus_bool_t add_timeout(DBusTimeout *dbus_timeout, void *data) {
+ if (!dbus_timeout_get_enabled(dbus_timeout)) return TRUE;
+
+ boost::asio::io_service &io = *static_cast<boost::asio::io_service *>(data);
+
+ boost::asio::steady_timer &timer = *new boost::asio::steady_timer(io);
+
+ dbus_timeout_set_data(dbus_timeout, &timer, NULL);
+
+ timeout_toggled(dbus_timeout, &io);
+ return TRUE;
+}
+
+static void remove_timeout(DBusTimeout *dbus_timeout, void *data) {
+ delete static_cast<boost::asio::steady_timer *>(dbus_timeout_get_data(dbus_timeout));
+}
+
+struct dispatch_handler {
+ boost::asio::io_service &io;
+ DBusConnection *conn;
+ dispatch_handler(boost::asio::io_service &i, DBusConnection *c)
+ : io(i), conn(c) {}
+ void operator()() {
+ if (dbus_connection_dispatch(conn) == DBUS_DISPATCH_DATA_REMAINS)
+ io.post(dispatch_handler(io, conn));
+ }
+};
+
+static void dispatch_status(DBusConnection *conn, DBusDispatchStatus new_status,
+ void *data) {
+ boost::asio::io_service &io = *static_cast<boost::asio::io_service *>(data);
+ if (new_status == DBUS_DISPATCH_DATA_REMAINS)
+ io.post(dispatch_handler(io, conn));
+}
+
+static void set_watch_timeout_dispatch_functions(DBusConnection *conn,
+ boost::asio::io_service &io) {
+ dbus_connection_set_watch_functions(conn, &add_watch, &remove_watch,
+ &watch_toggled, &io, NULL);
+
+ dbus_connection_set_timeout_functions(conn, &add_timeout, &remove_timeout,
+ &timeout_toggled, &io, NULL);
+
+ dbus_connection_set_dispatch_status_function(conn, &dispatch_status, &io,
+ NULL);
+}
+
+} // namespace detail
+} // namespace dbus
+
+#endif // DBUS_WATCH_TIMEOUT_HPP
diff --git a/boost-dbus/include/dbus/element.hpp b/boost-dbus/include/dbus/element.hpp
new file mode 100644
index 0000000..276b593
--- /dev/null
+++ b/boost-dbus/include/dbus/element.hpp
@@ -0,0 +1,182 @@
+// 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_ELEMENT_HPP
+#define DBUS_ELEMENT_HPP
+
+#include <dbus/dbus.h>
+#include <string>
+#include <boost/cstdint.hpp>
+
+namespace dbus {
+
+/// Message elements
+/**
+ * D-Bus Messages are composed of simple elements of one of these types
+ */
+// bool // is this simply valid? It might pack wrong...
+// http://maemo.org/api_refs/5.0/5.0-final/dbus/api/group__DBusTypes.html
+typedef boost::uint8_t byte;
+
+typedef boost::int16_t int16;
+typedef boost::uint16_t uint16;
+typedef boost::int32_t int32;
+typedef boost::uint32_t uint32;
+
+typedef boost::int64_t int64;
+typedef boost::uint64_t uint64;
+// double
+// unix_fd
+
+typedef std::string string;
+struct object_path {
+ string value;
+};
+struct signature {
+ string value;
+};
+
+/// Traits template for message elements
+/**
+ * D-Bus Message elements are identified by unique integer type codes.
+ */
+template <typename InvalidType>
+struct element {
+ static const int code = DBUS_TYPE_INVALID;
+};
+
+template <>
+struct element<bool> {
+ static const int code = DBUS_TYPE_BOOLEAN;
+};
+
+template <>
+struct element<byte> {
+ static const int code = DBUS_TYPE_BYTE;
+};
+
+template <>
+struct element<int16> {
+ static const int code = DBUS_TYPE_INT16;
+};
+
+template <>
+struct element<uint16> {
+ static const int code = DBUS_TYPE_UINT16;
+};
+
+template <>
+struct element<int32> {
+ static const int code = DBUS_TYPE_INT32;
+};
+
+template <>
+struct element<uint32> {
+ static const int code = DBUS_TYPE_UINT32;
+};
+
+template <>
+struct element<int64> {
+ static const int code = DBUS_TYPE_INT64;
+};
+
+template <>
+struct element<uint64> {
+ static const int code = DBUS_TYPE_UINT64;
+};
+
+template <>
+struct element<double> {
+ static const int code = DBUS_TYPE_DOUBLE;
+};
+
+template <>
+struct element<string> {
+ static const int code = DBUS_TYPE_STRING;
+};
+
+template <>
+struct element<object_path> {
+ static const int code = DBUS_TYPE_OBJECT_PATH;
+};
+
+template <>
+struct element<signature> {
+ static const int code = DBUS_TYPE_SIGNATURE;
+};
+
+template <typename InvalidType>
+struct is_fixed_type {
+ static const int value = false;
+};
+
+template <>
+struct is_fixed_type<bool> {
+ static const int value = true;
+};
+
+template <>
+struct is_fixed_type<byte> {
+ static const int value = true;
+};
+
+template <>
+struct is_fixed_type<int16> {
+ static const int value = true;
+};
+
+template <>
+struct is_fixed_type<uint16> {
+ static const int value = true;
+};
+
+template <>
+struct is_fixed_type<int32> {
+ static const int value = true;
+};
+
+template <>
+struct is_fixed_type<uint32> {
+ static const int value = true;
+};
+
+template <>
+struct is_fixed_type<int64> {
+ static const int value = true;
+};
+
+template <>
+struct is_fixed_type<uint64> {
+ static const int value = true;
+};
+
+template <>
+struct is_fixed_type<double> {
+ static const int value = true;
+};
+
+template <typename InvalidType>
+struct is_string_type {
+ static const bool value = false;
+};
+
+template <>
+struct is_string_type<string> {
+ static const bool value = true;
+};
+
+template <>
+struct is_string_type<object_path> {
+ static const bool value = true;
+};
+
+template <>
+struct is_string_type<signature> {
+ static const bool value = true;
+};
+
+} // namespace dbus
+
+#endif // DBUS_ELEMENT_HPP
diff --git a/boost-dbus/include/dbus/endpoint.hpp b/boost-dbus/include/dbus/endpoint.hpp
new file mode 100644
index 0000000..a574e8f
--- /dev/null
+++ b/boost-dbus/include/dbus/endpoint.hpp
@@ -0,0 +1,34 @@
+// 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_ENDPOINT_HPP
+#define DBUS_ENDPOINT_HPP
+
+#include <dbus/dbus.h>
+#include <dbus/element.hpp>
+#include <dbus/message.hpp>
+
+namespace dbus {
+
+class endpoint {
+ string process_name_;
+ string path_;
+ string interface_;
+
+ public:
+ endpoint(const string& process_name, const string& path,
+ const string& interface)
+ : process_name_(process_name), path_(path), interface_(interface) {}
+
+ const string& get_path() const { return path_; }
+
+ const string& get_interface() const { return interface_; }
+
+ const string& get_process_name() const { return process_name_; }
+};
+
+} // namespace dbus
+
+#endif // DBUS_ENDPOINT_HPP
diff --git a/boost-dbus/include/dbus/error.hpp b/boost-dbus/include/dbus/error.hpp
new file mode 100644
index 0000000..3b07c9f
--- /dev/null
+++ b/boost-dbus/include/dbus/error.hpp
@@ -0,0 +1,64 @@
+// 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_ERROR_HPP
+#define DBUS_ERROR_HPP
+
+#include <dbus/dbus.h>
+#include <dbus/element.hpp>
+#include <dbus/message.hpp>
+#include <boost/system/error_code.hpp>
+#include <boost/system/system_error.hpp>
+
+namespace dbus {
+
+class error : public boost::system::error_category {
+ DBusError error_;
+
+ public:
+ error() { dbus_error_init(&error_); }
+
+ error(DBusError *src) {
+ dbus_error_init(&error_);
+ dbus_move_error(src, &error_);
+ }
+
+ error(dbus::message &m) {
+ dbus_error_init(&error_);
+ dbus_set_error_from_message(&error_, m);
+ }
+
+ ~error() { dbus_error_free(&error_); }
+
+ const char *name() const BOOST_SYSTEM_NOEXCEPT { return error_.name; }
+
+ string message(int value) const { return error_.message; }
+
+ bool is_set() const { return dbus_error_is_set(&error_); }
+
+ operator const DBusError *() const { return &error_; }
+
+ operator DBusError *() { return &error_; }
+
+ boost::system::error_code error_code() const;
+ boost::system::system_error system_error() const;
+ void throw_if_set() const;
+};
+
+inline boost::system::error_code error::error_code() const {
+ return boost::system::error_code(is_set(), *this);
+}
+
+inline boost::system::system_error error::system_error() const {
+ return boost::system::system_error(error_code());
+}
+
+inline void error::throw_if_set() const {
+ if (is_set()) throw system_error();
+}
+
+} // namespace dbus
+
+#endif // DBUS_ERROR_HPP
diff --git a/boost-dbus/include/dbus/filter.hpp b/boost-dbus/include/dbus/filter.hpp
new file mode 100644
index 0000000..5d60d33
--- /dev/null
+++ b/boost-dbus/include/dbus/filter.hpp
@@ -0,0 +1,56 @@
+// 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_FILTER_HPP
+#define DBUS_FILTER_HPP
+
+#include <dbus/connection.hpp>
+#include <dbus/detail/queue.hpp>
+#include <dbus/message.hpp>
+#include <functional>
+#include <boost/asio.hpp>
+
+namespace dbus {
+
+/// Represents a filter of incoming messages.
+/**
+ * Filters examine incoming messages, demuxing them to multiple queues.
+ */
+class filter {
+ connection& connection_;
+ std::function<bool(message&)> predicate_;
+ detail::queue<message> queue_;
+
+ public:
+ bool offer(message& m) {
+ bool filtered = predicate_(m);
+ if (filtered) queue_.push(m);
+ return filtered;
+ }
+
+ template <typename MessagePredicate>
+ filter(connection& c, BOOST_ASIO_MOVE_ARG(MessagePredicate) p)
+ : connection_(c),
+ predicate_(BOOST_ASIO_MOVE_CAST(MessagePredicate)(p)),
+ queue_(connection_.get_io_service()) {
+ connection_.new_filter(*this);
+ }
+
+ ~filter() { connection_.delete_filter(*this); }
+
+ template <typename MessageHandler>
+ inline BOOST_ASIO_INITFN_RESULT_TYPE(MessageHandler,
+ void(boost::system::error_code, message))
+ async_dispatch(BOOST_ASIO_MOVE_ARG(MessageHandler) handler) {
+ // begin asynchronous operation
+ connection_.get_implementation().start(connection_.get_io_service());
+
+ return queue_.async_pop(BOOST_ASIO_MOVE_CAST(MessageHandler)(handler));
+ }
+};
+} // namespace dbus
+
+#include <dbus/impl/filter.ipp>
+#endif // DBUS_FILTER_HPP
diff --git a/boost-dbus/include/dbus/impl/connection.ipp b/boost-dbus/include/dbus/impl/connection.ipp
new file mode 100644
index 0000000..24a257d
--- /dev/null
+++ b/boost-dbus/include/dbus/impl/connection.ipp
@@ -0,0 +1,102 @@
+// 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_CONNECTION_IPP
+#define DBUS_CONNECTION_IPP
+
+#include <dbus/dbus.h>
+#include <dbus/detail/watch_timeout.hpp>
+
+#include <boost/atomic.hpp>
+
+namespace dbus {
+namespace impl {
+
+class connection {
+ public:
+ boost::atomic<bool> is_paused;
+ DBusConnection* conn;
+
+ connection() : is_paused(true), conn(NULL) {}
+
+ void open(boost::asio::io_service& io, int bus) {
+ error e;
+ conn = dbus_bus_get_private((DBusBusType)bus, e);
+ e.throw_if_set();
+
+ dbus_connection_set_exit_on_disconnect(conn, false);
+
+ detail::set_watch_timeout_dispatch_functions(conn, io);
+ }
+
+ void open(boost::asio::io_service& io, const string& address) {
+ error e;
+ conn = dbus_connection_open_private(address.c_str(), e);
+ e.throw_if_set();
+
+ dbus_bus_register(conn, e);
+ e.throw_if_set();
+
+ dbus_connection_set_exit_on_disconnect(conn, false);
+
+ detail::set_watch_timeout_dispatch_functions(conn, io);
+ }
+
+ ~connection() {
+ if (conn != NULL) {
+ dbus_connection_close(conn);
+ dbus_connection_unref(conn);
+ }
+ }
+
+ operator DBusConnection*() { return conn; }
+ operator const DBusConnection*() const { return conn; }
+
+ message send_with_reply_and_block(message& m,
+ int timeout_in_milliseconds = -1) {
+ error e;
+ DBusMessage* out = dbus_connection_send_with_reply_and_block(
+ conn, m, timeout_in_milliseconds, e);
+ e.throw_if_set();
+ message reply(out);
+
+ return reply;
+ }
+
+ void send(message& m) {
+ // ignoring message serial for now
+ dbus_connection_send(conn, m, NULL);
+ }
+
+ void send_with_reply(message& m, DBusPendingCall** p,
+ int timeout_in_milliseconds = -1) {
+ dbus_connection_send_with_reply(conn, m, p, timeout_in_milliseconds);
+ }
+
+ // begin asynchronous operation
+ // FIXME should not get io from an argument
+ void start(boost::asio::io_service& io) {
+ bool old_value(true);
+ if (is_paused.compare_exchange_strong(old_value, false)) {
+ // If two threads call connection::async_send()
+ // simultaneously on a paused connection, then
+ // only one will pass the CAS instruction and
+ // only one dispatch_handler will be injected.
+ io.post(detail::dispatch_handler(io, conn));
+ }
+ }
+
+ void cancel(boost::asio::io_service& io) {
+ bool old_value(false);
+ if (is_paused.compare_exchange_strong(old_value, true)) {
+ // TODO
+ }
+ }
+};
+
+} // namespace impl
+} // namespace dbus
+
+#endif // DBUS_CONNECTION_IPP
diff --git a/boost-dbus/include/dbus/impl/filter.ipp b/boost-dbus/include/dbus/impl/filter.ipp
new file mode 100644
index 0000000..a64d6fd
--- /dev/null
+++ b/boost-dbus/include/dbus/impl/filter.ipp
@@ -0,0 +1,39 @@
+// 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_FILTER_IPP
+#define DBUS_FILTER_IPP
+
+namespace dbus {
+namespace impl {
+
+inline DBusHandlerResult filter_callback(DBusConnection* c, DBusMessage* m,
+ void* userdata) {
+ try {
+ filter& f = *static_cast<filter*>(userdata);
+ message m_(m);
+ if (f.offer(m_)) {
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+ } catch (...) {
+ // do not throw in C callbacks. Just don't.
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+} // namespace impl
+
+void connection_service::new_filter(implementation_type& impl, filter& f) {
+ dbus_connection_add_filter(impl, &impl::filter_callback, &f, NULL);
+}
+
+void connection_service::delete_filter(implementation_type& impl, filter& f) {
+ dbus_connection_remove_filter(impl, &impl::filter_callback, &f);
+}
+
+} // namespace dbus
+
+#endif // DBUS_FILTER_IPP
diff --git a/boost-dbus/include/dbus/impl/match.ipp b/boost-dbus/include/dbus/impl/match.ipp
new file mode 100644
index 0000000..9f6a5da
--- /dev/null
+++ b/boost-dbus/include/dbus/impl/match.ipp
@@ -0,0 +1,26 @@
+// 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_MATCH_IPP
+#define DBUS_MATCH_IPP
+
+namespace dbus {
+void connection_service::new_match(implementation_type& impl, match& m) {
+ error e;
+ dbus_bus_add_match(impl, m.get_expression().c_str(), e);
+ e.throw_if_set();
+ // eventually, for complete asynchronicity, this should connect to
+ // org.freedesktop.DBus and call AddMatch
+}
+
+void connection_service::delete_match(implementation_type& impl, match& m) {
+ error e;
+ dbus_bus_remove_match(impl, m.get_expression().c_str(), e);
+ e.throw_if_set();
+}
+
+} // namespace dbus
+
+#endif // DBUS_MATCH_IPP
diff --git a/boost-dbus/include/dbus/impl/message_iterator.hpp b/boost-dbus/include/dbus/impl/message_iterator.hpp
new file mode 100644
index 0000000..44bcf2e
--- /dev/null
+++ b/boost-dbus/include/dbus/impl/message_iterator.hpp
@@ -0,0 +1,50 @@
+// 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_IMPL_MESSAGE_ITERATOR_HPP
+#define DBUS_IMPL_MESSAGE_ITERATOR_HPP
+
+#include <dbus/dbus.h>
+
+namespace dbus {
+
+class message;
+
+namespace impl {
+
+class message_iterator {
+ DBusMessageIter DBusMessageIter_;
+
+ public:
+ // writing
+ static void init_append(message &m, message_iterator &i);
+
+ void append_basic(int code, const void *value);
+
+ void open_container(int code, const char *signature, message_iterator &);
+ void close_container(message_iterator &);
+ void abandon_container(message_iterator &);
+
+ void append_fixed_array(int code, const void *value, int n_elements);
+
+ // reading
+ static bool init(message &m, message_iterator &i);
+
+ bool next();
+ bool has_next();
+ int get_arg_type();
+
+ void get_basic(void *value);
+
+ void recurse(message_iterator &);
+
+ int get_element_type();
+ void get_fixed_array(void *value, int *n_elements);
+};
+
+} // namespace impl
+} // namespace dbus
+
+#endif // DBUS_IMPL_MESSAGE_ITERATOR_HPP
diff --git a/boost-dbus/include/dbus/impl/message_iterator.ipp b/boost-dbus/include/dbus/impl/message_iterator.ipp
new file mode 100644
index 0000000..eb2584f
--- /dev/null
+++ b/boost-dbus/include/dbus/impl/message_iterator.ipp
@@ -0,0 +1,89 @@
+// 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_IMPL_MESSAGE_ITERATOR_IPP
+#define DBUS_IMPL_MESSAGE_ITERATOR_IPP
+
+#include <dbus/impl/message_iterator.hpp>
+
+namespace dbus {
+namespace impl {
+
+inline void message_iterator::init_append(message& m, message_iterator& i)
+{
+ dbus_message_iter_init_append(m, &i.DBusMessageIter_);
+}
+inline void message_iterator::append_basic(int code, const void *value)
+{
+ // returns false if not enough memory- throw bad_alloc
+ dbus_message_iter_append_basic(&DBusMessageIter_, code, value);
+}
+inline void message_iterator::open_container(int code, const char *signature, message_iterator& sub)
+{
+ // returns false if not enough memory- throw bad_alloc
+ dbus_message_iter_open_container(&DBusMessageIter_, code, signature, &sub.DBusMessageIter_);
+}
+
+inline void message_iterator::close_container(message_iterator& sub)
+{
+ // returns false if not enough memory- throw bad_alloc
+ dbus_message_iter_close_container(&DBusMessageIter_, &sub.DBusMessageIter_);
+}
+
+inline void message_iterator::abandon_container(message_iterator& sub)
+{
+ dbus_message_iter_abandon_container(&DBusMessageIter_, &sub.DBusMessageIter_);
+}
+
+inline void message_iterator::append_fixed_array(int code, const void *value, int n_elements)
+{
+ // returns false if not enough memory- throw bad_alloc
+ dbus_message_iter_append_fixed_array(&DBusMessageIter_, code, value, n_elements);
+}
+
+inline bool message_iterator::init(message& m, message_iterator& i)
+{
+ return dbus_message_iter_init(m, &i.DBusMessageIter_);
+}
+
+inline bool message_iterator::next()
+{
+ return dbus_message_iter_next(&DBusMessageIter_);
+}
+
+inline bool message_iterator::has_next()
+{
+ return dbus_message_iter_has_next(&DBusMessageIter_);
+}
+
+inline int message_iterator::get_arg_type()
+{
+ return dbus_message_iter_get_arg_type(&DBusMessageIter_);
+}
+
+inline void message_iterator::get_basic(void *value)
+{
+ dbus_message_iter_get_basic(&DBusMessageIter_, value);
+}
+
+inline void message_iterator::recurse(message_iterator& sub)
+{
+ dbus_message_iter_recurse(&DBusMessageIter_, &sub.DBusMessageIter_);
+}
+
+inline int message_iterator::get_element_type()
+{
+ return dbus_message_iter_get_element_type(&DBusMessageIter_);
+}
+
+inline void message_iterator::get_fixed_array(void *value, int *n_elements)
+{
+ dbus_message_iter_get_fixed_array(&DBusMessageIter_, value, n_elements);
+}
+
+} // namespace impl
+} // namespace dbus
+
+#endif // DBUS_IMPL_MESSAGE_ITERATOR_IPP
diff --git a/boost-dbus/include/dbus/match.hpp b/boost-dbus/include/dbus/match.hpp
new file mode 100644
index 0000000..0488aa0
--- /dev/null
+++ b/boost-dbus/include/dbus/match.hpp
@@ -0,0 +1,46 @@
+// 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_MATCH_HPP
+#define DBUS_MATCH_HPP
+
+#include <string>
+#include <boost/asio.hpp>
+
+#include <dbus/connection.hpp>
+#include <dbus/error.hpp>
+
+namespace dbus {
+
+/// Simple placeholder object for a match rule.
+/**
+ * A match rule determines what messages will be received by this application.
+ *
+ * Each rule will be represented by an instance of match. To remove that rule,
+ * dispose of the object.
+ */
+class match {
+ connection& connection_;
+ std::string expression_;
+
+ public:
+ match(connection& c, BOOST_ASIO_MOVE_ARG(std::string) e)
+ : connection_(c), expression_(BOOST_ASIO_MOVE_CAST(std::string)(e)) {
+ connection_.new_match(*this);
+ }
+
+ ~match() { connection_.delete_match(*this); }
+
+ const std::string& get_expression() const { return expression_; }
+
+ match(match&&) = delete;
+ match& operator=(match&&) = delete;
+};
+
+} // namespace dbus
+
+#include <dbus/impl/match.ipp>
+
+#endif // DBUS_MATCH_HPP
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
diff --git a/boost-dbus/include/dbus/utility.hpp b/boost-dbus/include/dbus/utility.hpp
new file mode 100644
index 0000000..47fad1c
--- /dev/null
+++ b/boost-dbus/include/dbus/utility.hpp
@@ -0,0 +1,39 @@
+// Copyright (c) Ed Tanous
+//
+// 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_UTILITY_HPP
+#define DBUS_UTILITY_HPP
+
+#include <boost/iostreams/stream.hpp>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/xml_parser.hpp>
+
+namespace dbus {
+
+inline void read_dbus_xml_names(std::string& xml_data_in,
+ std::vector<std::string>& values_out) {
+ // populate tree structure pt
+ using boost::property_tree::ptree;
+ ptree pt;
+ std::cout << xml_data_in;
+ std::stringstream ss;
+ ss << xml_data_in;
+ read_xml(ss, pt);
+
+ // traverse node to find other nodes
+ for (const auto& interface : pt.get_child("node")) {
+ if (interface.first == "node") {
+ auto t = interface.second.get<std::string>("<xmlattr>", "default");
+ for (const auto& subnode : interface.second.get_child("<xmlattr>")) {
+ if (subnode.first == "name") {
+ std::string t = subnode.second.get("", "unknown");
+ values_out.push_back(t);
+ }
+ }
+ }
+ }
+}
+}
+#endif // DBUS_UTILITY_HPP
\ No newline at end of file