blob: d7ee196bc6f3bbb23c49776a62a89abea5ffcf5f [file] [log] [blame]
/*
*
* D-Bus++ - C++ bindings for D-Bus
*
* Copyright (C) 2005-2007 Paolo Durante <shackan@gmail.com>
*
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <dbus-c++/message.h>
#include <dbus/dbus.h>
#include <cstdlib>
#include "internalerror.h"
#include "message_p.h"
using namespace DBus;
/*
*/
MessageIter::MessageIter()
: _pvt(new Private), _msg(NULL) {}
MessageIter::MessageIter(Message &msg)
: _pvt(new Private), _msg(&msg) {}
MessageIter::MessageIter(const MessageIter &iter)
: _pvt(new Private(*iter._pvt)), _msg(iter._msg) {}
MessageIter::~MessageIter()
{
delete _pvt;
_pvt = NULL;
_msg = NULL;
}
MessageIter &MessageIter::operator =(const MessageIter &iter)
{
if (this != &iter)
{
*_pvt = *iter._pvt;
_msg = iter._msg;
}
return *this;
}
int MessageIter::type()
{
return dbus_message_iter_get_arg_type(&_pvt->iter);
}
bool MessageIter::at_end()
{
return type() == DBUS_TYPE_INVALID;
}
bool MessageIter::has_next()
{
return dbus_message_iter_has_next(&_pvt->iter);
}
MessageIter &MessageIter::operator ++()
{
dbus_message_iter_next(&_pvt->iter);
return (*this);
}
MessageIter MessageIter::operator ++(int)
{
MessageIter copy(*this);
++(*this);
return copy;
}
bool MessageIter::append_basic(int type_id, void *value)
{
return dbus_message_iter_append_basic(&_pvt->iter, type_id, value);
}
void MessageIter::get_basic(int type_id, void *ptr)
{
if (type() != type_id)
throw ErrorInvalidArgs("type mismatch");
dbus_message_iter_get_basic(&_pvt->iter, ptr);
}
bool MessageIter::append_byte(unsigned char b)
{
return append_basic(DBUS_TYPE_BYTE, &b);
}
unsigned char MessageIter::get_byte()
{
unsigned char b;
get_basic(DBUS_TYPE_BYTE, &b);
return b;
}
bool MessageIter::append_bool(bool b)
{
dbus_bool_t db = b ? TRUE : FALSE;
return append_basic(DBUS_TYPE_BOOLEAN, &db);
}
bool MessageIter::get_bool()
{
dbus_bool_t db;
get_basic(DBUS_TYPE_BOOLEAN, &db);
return db ? true : false;
}
bool MessageIter::append_int16(signed short i)
{
return append_basic(DBUS_TYPE_INT16, &i);
}
signed short MessageIter::get_int16()
{
signed short i;
get_basic(DBUS_TYPE_INT16, &i);
return i;
}
bool MessageIter::append_uint16(unsigned short u)
{
return append_basic(DBUS_TYPE_UINT16, &u);
}
unsigned short MessageIter::get_uint16()
{
unsigned short u;
get_basic(DBUS_TYPE_UINT16, &u);
return u;
}
bool MessageIter::append_int32(signed int i)
{
return append_basic(DBUS_TYPE_INT32, &i);
}
signed int MessageIter::get_int32()
{
signed int i;
get_basic(DBUS_TYPE_INT32, &i);
return i;
}
bool MessageIter::append_uint32(unsigned int u)
{
return append_basic(DBUS_TYPE_UINT32, &u);
}
unsigned int MessageIter::get_uint32()
{
unsigned int u;
get_basic(DBUS_TYPE_UINT32, &u);
return u;
}
signed long long MessageIter::get_int64()
{
signed long long i;
get_basic(DBUS_TYPE_INT64, &i);
return i;
}
bool MessageIter::append_int64(signed long long i)
{
return append_basic(DBUS_TYPE_INT64, &i);
}
unsigned long long MessageIter::get_uint64()
{
unsigned long long u;
get_basic(DBUS_TYPE_UINT64, &u);
return u;
}
bool MessageIter::append_uint64(unsigned long long u)
{
return append_basic(DBUS_TYPE_UINT64, &u);
}
double MessageIter::get_double()
{
double d;
get_basic(DBUS_TYPE_DOUBLE, &d);
return d;
}
bool MessageIter::append_double(double d)
{
return append_basic(DBUS_TYPE_DOUBLE, &d);
}
bool MessageIter::append_string(const char *chars)
{
return append_basic(DBUS_TYPE_STRING, &chars);
}
const char *MessageIter::get_string()
{
char *chars;
get_basic(DBUS_TYPE_STRING, &chars);
return chars;
}
bool MessageIter::append_path(const char *chars)
{
return append_basic(DBUS_TYPE_OBJECT_PATH, &chars);
}
const char *MessageIter::get_path()
{
char *chars;
get_basic(DBUS_TYPE_OBJECT_PATH, &chars);
return chars;
}
bool MessageIter::append_signature(const char *chars)
{
return append_basic(DBUS_TYPE_SIGNATURE, &chars);
}
const char *MessageIter::get_signature()
{
char *chars;
get_basic(DBUS_TYPE_SIGNATURE, &chars);
return chars;
}
bool MessageIter::append_fd(int fd)
{
return append_basic(DBUS_TYPE_UNIX_FD, &fd);
}
int MessageIter::get_fd()
{
int fd;
get_basic(DBUS_TYPE_UNIX_FD, &fd);
return fd;
}
MessageIter MessageIter::recurse()
{
MessageIter iter(msg());
dbus_message_iter_recurse(&_pvt->iter, &iter._pvt->iter);
return iter;
}
char *MessageIter::signature() const
{
return dbus_message_iter_get_signature(&_pvt->iter);
}
bool MessageIter::append_array(char type, const void *ptr, size_t length)
{
return dbus_message_iter_append_fixed_array(&_pvt->iter, type, &ptr, length);
}
int MessageIter::array_type()
{
return dbus_message_iter_get_element_type(&_pvt->iter);
}
int MessageIter::get_array(void *ptr)
{
int length;
dbus_message_iter_get_fixed_array(&_pvt->iter, ptr, &length);
return length;
}
bool MessageIter::is_array()
{
return dbus_message_iter_get_arg_type(&_pvt->iter) == DBUS_TYPE_ARRAY;
}
bool MessageIter::is_dict()
{
return is_array() && dbus_message_iter_get_element_type(&_pvt->iter) == DBUS_TYPE_DICT_ENTRY;
}
MessageIter MessageIter::new_array(const char *sig)
{
MessageIter arr(msg());
dbus_message_iter_open_container(
&_pvt->iter, DBUS_TYPE_ARRAY, sig, &arr._pvt->iter
);
return arr;
}
MessageIter MessageIter::new_variant(const char *sig)
{
MessageIter var(msg());
dbus_message_iter_open_container(
&_pvt->iter, DBUS_TYPE_VARIANT, sig, &var._pvt->iter
);
return var;
}
MessageIter MessageIter::new_struct()
{
MessageIter stu(msg());
dbus_message_iter_open_container(
&_pvt->iter, DBUS_TYPE_STRUCT, NULL, &stu._pvt->iter
);
return stu;
}
MessageIter MessageIter::new_dict_entry()
{
MessageIter ent(msg());
dbus_message_iter_open_container(
&_pvt->iter, DBUS_TYPE_DICT_ENTRY, NULL, &ent._pvt->iter
);
return ent;
}
void MessageIter::close_container(MessageIter &container)
{
dbus_message_iter_close_container(&_pvt->iter, &container._pvt->iter);
}
static bool is_basic_type(int typecode)
{
switch (typecode)
{
case DBUS_TYPE_BYTE:
case DBUS_TYPE_BOOLEAN:
case DBUS_TYPE_INT16:
case DBUS_TYPE_UINT16:
case DBUS_TYPE_INT32:
case DBUS_TYPE_UINT32:
case DBUS_TYPE_INT64:
case DBUS_TYPE_UINT64:
case DBUS_TYPE_DOUBLE:
case DBUS_TYPE_STRING:
case DBUS_TYPE_OBJECT_PATH:
case DBUS_TYPE_SIGNATURE:
case DBUS_TYPE_UNIX_FD:
return true;
default:
return false;
}
}
void MessageIter::copy_data(MessageIter &to)
{
for (MessageIter &from = *this; !from.at_end(); ++from)
{
if (is_basic_type(from.type()))
{
debug_log("copying basic type: %c", from.type());
unsigned char value[8];
from.get_basic(from.type(), &value);
to.append_basic(from.type(), &value);
}
else
{
MessageIter from_container = from.recurse();
char *sig = from_container.signature();
debug_log("copying compound type: %c[%s]", from.type(), sig);
MessageIter to_container (to.msg());
dbus_message_iter_open_container
(
&to._pvt->iter,
from.type(),
from.type() == DBUS_TYPE_DICT_ENTRY ||
from.type() == DBUS_TYPE_STRUCT ? NULL : sig,
&to_container._pvt->iter
);
from_container.copy_data(to_container);
to.close_container(to_container);
free(sig);
}
}
}
/*
*/
Message::Message()
: _pvt(new Private)
{
}
Message::Message(Message::Private *p, bool incref)
: _pvt(p)
{
if (_pvt->msg && incref) dbus_message_ref(_pvt->msg);
}
Message::Message(const Message &m)
: _pvt(m._pvt)
{
if (_pvt->msg)
dbus_message_ref(_pvt->msg);
}
Message::~Message()
{
if (_pvt->msg)
dbus_message_unref(_pvt->msg);
}
Message &Message::operator = (const Message &m)
{
if (&m != this)
{
if (_pvt->msg)
dbus_message_unref(_pvt->msg);
_pvt = m._pvt;
if (_pvt->msg)
dbus_message_ref(_pvt->msg);
}
return *this;
}
Message Message::copy()
{
Private *pvt = new Private(_pvt->msg ? dbus_message_copy(_pvt->msg) : NULL);
return Message(pvt);
}
bool Message::append(int first_type, ...)
{
va_list vl;
va_start(vl, first_type);
bool b = dbus_message_append_args_valist(_pvt->msg, first_type, vl);
va_end(vl);
return b;
}
void Message::terminate()
{
dbus_message_append_args(_pvt->msg, DBUS_TYPE_INVALID);
}
int Message::type() const
{
return dbus_message_get_type(_pvt->msg);
}
int Message::serial() const
{
return dbus_message_get_serial(_pvt->msg);
}
int Message::reply_serial() const
{
return dbus_message_get_reply_serial(_pvt->msg);
}
bool Message::reply_serial(int s)
{
return dbus_message_set_reply_serial(_pvt->msg, s);
}
const char *Message::sender() const
{
return dbus_message_get_sender(_pvt->msg);
}
bool Message::sender(const char *s)
{
return dbus_message_set_sender(_pvt->msg, s);
}
const char *Message::destination() const
{
return dbus_message_get_destination(_pvt->msg);
}
bool Message::destination(const char *s)
{
return dbus_message_set_destination(_pvt->msg, s);
}
bool Message::is_error() const
{
return type() == DBUS_MESSAGE_TYPE_ERROR;
}
bool Message::is_signal(const char *interface, const char *member) const
{
return dbus_message_is_signal(_pvt->msg, interface, member);
}
Tag *Message::tag() const
{
return _pvt->tag;
}
MessageIter Message::writer()
{
MessageIter iter(*this);
dbus_message_iter_init_append(_pvt->msg, &iter._pvt->iter);
return iter;
}
MessageIter Message::reader() const
{
MessageIter iter(const_cast<Message &>(*this));
dbus_message_iter_init(_pvt->msg, &iter._pvt->iter);
return iter;
}
/*
*/
ErrorMessage::ErrorMessage()
{
_pvt->msg = dbus_message_new(DBUS_MESSAGE_TYPE_ERROR);
}
ErrorMessage::ErrorMessage(const Message &to_reply, const char *name, const char *message)
{
_pvt->msg = dbus_message_new_error(to_reply._pvt->msg, name, message);
}
bool ErrorMessage::operator == (const ErrorMessage &m) const
{
return dbus_message_is_error(_pvt->msg, m.name());
}
const char *ErrorMessage::name() const
{
return dbus_message_get_error_name(_pvt->msg);
}
bool ErrorMessage::name(const char *n)
{
return dbus_message_set_error_name(_pvt->msg, n);
}
/*
*/
SignalMessage::SignalMessage(const char *name)
{
_pvt->msg = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
member(name);
}
SignalMessage::SignalMessage(const char *path, const char *interface, const char *name)
{
_pvt->msg = dbus_message_new_signal(path, interface, name);
}
bool SignalMessage::operator == (const SignalMessage &m) const
{
return dbus_message_is_signal(_pvt->msg, m.interface(), m.member());
}
const char *SignalMessage::interface() const
{
return dbus_message_get_interface(_pvt->msg);
}
bool SignalMessage::interface(const char *i)
{
return dbus_message_set_interface(_pvt->msg, i);
}
const char *SignalMessage::member() const
{
return dbus_message_get_member(_pvt->msg);
}
bool SignalMessage::member(const char *m)
{
return dbus_message_set_member(_pvt->msg, m);
}
const char *SignalMessage::path() const
{
return dbus_message_get_path(_pvt->msg);
}
char ** SignalMessage::path_split() const
{
char ** p;
dbus_message_get_path_decomposed(_pvt->msg, &p); //todo: return as a std::vector ?
return p;
}
bool SignalMessage::path(const char *p)
{
return dbus_message_set_path(_pvt->msg, p);
}
/*
*/
CallMessage::CallMessage()
{
_pvt->msg = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_CALL);
}
CallMessage::CallMessage(const char *dest, const char *path, const char *iface, const char *method)
{
_pvt->msg = dbus_message_new_method_call(dest, path, iface, method);
}
bool CallMessage::operator == (const CallMessage &m) const
{
return dbus_message_is_method_call(_pvt->msg, m.interface(), m.member());
}
const char *CallMessage::interface() const
{
return dbus_message_get_interface(_pvt->msg);
}
bool CallMessage::interface(const char *i)
{
return dbus_message_set_interface(_pvt->msg, i);
}
const char *CallMessage::member() const
{
return dbus_message_get_member(_pvt->msg);
}
bool CallMessage::member(const char *m)
{
return dbus_message_set_member(_pvt->msg, m);
}
const char *CallMessage::path() const
{
return dbus_message_get_path(_pvt->msg);
}
char ** CallMessage::path_split() const
{
char ** p;
dbus_message_get_path_decomposed(_pvt->msg, &p);
return p;
}
bool CallMessage::path(const char *p)
{
return dbus_message_set_path(_pvt->msg, p);
}
const char *CallMessage::signature() const
{
return dbus_message_get_signature(_pvt->msg);
}
/*
*/
TagMessage::TagMessage(Tag *tag)
{
_pvt->tag = tag;
}
/*
*/
ReturnMessage::ReturnMessage(const CallMessage &callee)
{
_pvt = new Private(dbus_message_new_method_return(callee._pvt->msg));
}
const char *ReturnMessage::signature() const
{
return dbus_message_get_signature(_pvt->msg);
}