summaryrefslogtreecommitdiffstats
path: root/qt/src/qdbusmessage.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'qt/src/qdbusmessage.cpp')
-rw-r--r--qt/src/qdbusmessage.cpp706
1 files changed, 706 insertions, 0 deletions
diff --git a/qt/src/qdbusmessage.cpp b/qt/src/qdbusmessage.cpp
new file mode 100644
index 00000000..d0a0f1e5
--- /dev/null
+++ b/qt/src/qdbusmessage.cpp
@@ -0,0 +1,706 @@
+/* qdbusmessage.cpp
+ *
+ * Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org>
+ * Copyright (C) 2006 Trolltech AS. All rights reserved.
+ * Author: Thiago Macieira <thiago.macieira@trolltech.com>
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "qdbusmessage.h"
+
+#include <qdebug.h>
+#include <qstringlist.h>
+
+#include <dbus/dbus.h>
+
+#include "qdbuserror.h"
+#include "qdbusmarshall_p.h"
+#include "qdbusmessage_p.h"
+#include "qdbustypehelper_p.h"
+
+QDBusMessagePrivate::QDBusMessagePrivate()
+ : connection(QString()), msg(0), reply(0), type(DBUS_MESSAGE_TYPE_INVALID),
+ timeout(-1), ref(1), repliedTo(false)
+{
+}
+
+QDBusMessagePrivate::~QDBusMessagePrivate()
+{
+ if (msg)
+ dbus_message_unref(msg);
+ if (reply)
+ dbus_message_unref(reply);
+}
+
+///////////////
+/*!
+ \class QDBusMessage
+ \brief Represents one message sent or received over the DBus bus.
+
+ This object can represent any of four different types of messages possible on the bus
+ (see MessageType)
+ \list
+ \o Method calls
+ \o Method return values
+ \o Signal emissions
+ \o Error codes
+ \endlist
+
+ Objects of this type are created with the four static functions signal, methodCall,
+ methodReply and error.
+*/
+
+/*!
+ \enum QDBusMessage::MessageType
+ The possible message types:
+
+ \value MethodCallMessage a message representing an outgoing or incoming method call
+ \value SignalMessage a message representing an outgoing or incoming signal emission
+ \value ReplyMessage a message representing the return values of a method call
+ \value ErrorMessage a message representing an error condition in response to a method call
+ \value InvalidMessage an invalid message: this is never set on messages received from D-Bus
+*/
+
+/*!
+ Constructs a new DBus message representing a signal emission. A DBus signal is emitted
+ from one application and is received by all applications that are listening for that signal
+ from that interface.
+
+ The signal will be constructed to represent a signal coming from the path \a path, interface \a
+ interface and signal name \a name.
+
+ The QDBusMessage object that is returned can be sent with QDBusConnection::send().
+*/
+QDBusMessage QDBusMessage::signal(const QString &path, const QString &interface,
+ const QString &name)
+{
+ QDBusMessage message;
+ message.d_ptr->type = DBUS_MESSAGE_TYPE_SIGNAL;
+ message.d_ptr->path = path;
+ message.d_ptr->interface = interface;
+ message.d_ptr->name = name;
+
+ return message;
+}
+
+/*!
+ Constructs a new DBus message representing a method call. A method call always informs
+ its destination address (\a service, \a path, \a interface and \a method).
+
+ The DBus bus allows calling a method on a given remote object without specifying the
+ destination interface, if the method name is unique. However, if two interfaces on the
+ remote object export the same method name, the result is undefined (one of the two may be
+ called or an error may be returned).
+
+ When using DBus in a peer-to-peer context (i.e., not on a bus), the \a service parameter is
+ optional.
+
+ The QDBusObject and QDBusInterface classes provide a simpler abstraction to synchronous
+ method calling.
+
+ This function returns a QDBusMessage object that can be sent with QDBusConnection::send(),
+ QDBusConnection::sendWithReply(), or QDBusConnection::sendWithReplyAsync().
+*/
+QDBusMessage QDBusMessage::methodCall(const QString &service, const QString &path,
+ const QString &interface, const QString &method)
+{
+ QDBusMessage message;
+ message.d_ptr->type = DBUS_MESSAGE_TYPE_METHOD_CALL;
+ message.d_ptr->service = service;
+ message.d_ptr->path = path;
+ message.d_ptr->interface = interface;
+ message.d_ptr->name = method;
+
+ return message;
+}
+
+/*!
+ Constructs a new DBus message representing the return values from a called method. The \a other
+ variable represents the method call that the reply will be for.
+
+ This function returns a QDBusMessage object that can be sent with QDBusConnection::send().
+*/
+QDBusMessage QDBusMessage::methodReply(const QDBusMessage &other)
+{
+ Q_ASSERT(other.d_ptr->msg);
+
+ QDBusMessage message;
+ message.d_ptr->connection = other.d_ptr->connection;
+ message.d_ptr->type = DBUS_MESSAGE_TYPE_METHOD_RETURN;
+ message.d_ptr->reply = dbus_message_ref(other.d_ptr->msg);
+ other.d_ptr->repliedTo = true;
+
+ return message;
+}
+
+/*!
+ Constructs a DBus message representing an error condition described by the \a name
+ parameter. The \a msg parameter is optional and may contain a human-readable description of the
+ error. The \a other variable represents the method call that this error relates to.
+
+ This function returns a QDBusMessage object that can be sent with QDBusMessage::send().
+*/
+QDBusMessage QDBusMessage::error(const QDBusMessage &other, const QString &name,
+ const QString &msg)
+{
+ Q_ASSERT(other.d_ptr->msg);
+
+ QDBusMessage message;
+ message.d_ptr->connection = other.d_ptr->connection;
+ message.d_ptr->type = DBUS_MESSAGE_TYPE_ERROR;
+ message.d_ptr->name = name;
+ message.d_ptr->message = msg;
+ message.d_ptr->reply = dbus_message_ref(other.d_ptr->msg);
+ other.d_ptr->repliedTo = true;
+
+ return message;
+}
+
+/*!
+ \overload
+ Constructs a DBus message representing an error, where \a other is the method call that
+ generated this error and \a error is the error code.
+*/
+QDBusMessage QDBusMessage::error(const QDBusMessage &other, const QDBusError &error)
+{
+ Q_ASSERT(other.d_ptr->msg);
+
+ QDBusMessage message;
+ message.d_ptr->connection = other.d_ptr->connection;
+ message.d_ptr->type = DBUS_MESSAGE_TYPE_ERROR;
+ message.d_ptr->name = error.name();
+ message.d_ptr->message = error.message();
+ message.d_ptr->reply = dbus_message_ref(other.d_ptr->msg);
+ other.d_ptr->repliedTo = true;
+
+ return message;
+}
+
+/*!
+ Constructs an empty, invalid QDBusMessage object.
+
+ \sa methodCall(), methodReply(), signal(), error()
+*/
+QDBusMessage::QDBusMessage()
+{
+ d_ptr = new QDBusMessagePrivate;
+}
+
+/*!
+ Constructs a copy of the object given by \a other.
+*/
+QDBusMessage::QDBusMessage(const QDBusMessage &other)
+ : QList<QVariant>(other)
+{
+ d_ptr = other.d_ptr;
+ d_ptr->ref.ref();
+}
+
+/*!
+ Disposes of the object and frees any resources that were being held.
+*/
+QDBusMessage::~QDBusMessage()
+{
+ if (!d_ptr->ref.deref())
+ delete d_ptr;
+}
+
+/*!
+ Copies the contents of the object given by \a other.
+*/
+QDBusMessage &QDBusMessage::operator=(const QDBusMessage &other)
+{
+ QList<QVariant>::operator=(other);
+ qAtomicAssign(d_ptr, other.d_ptr);
+ return *this;
+}
+
+static inline const char *data(const QByteArray &arr)
+{
+ return arr.isEmpty() ? 0 : arr.constData();
+}
+
+/*!
+ \internal
+ Constructs a DBusMessage object from this object. The returned value must be de-referenced
+ with dbus_message_unref.
+*/
+DBusMessage *QDBusMessage::toDBusMessage() const
+{
+ DBusMessage *msg = 0;
+
+ switch (d_ptr->type) {
+ case DBUS_MESSAGE_TYPE_METHOD_CALL:
+ msg = dbus_message_new_method_call(data(d_ptr->service.toUtf8()), data(d_ptr->path.toUtf8()),
+ data(d_ptr->interface.toUtf8()), data(d_ptr->name.toUtf8()));
+ break;
+ case DBUS_MESSAGE_TYPE_SIGNAL:
+ msg = dbus_message_new_signal(data(d_ptr->path.toUtf8()), data(d_ptr->interface.toUtf8()),
+ data(d_ptr->name.toUtf8()));
+ break;
+ case DBUS_MESSAGE_TYPE_METHOD_RETURN:
+ msg = dbus_message_new_method_return(d_ptr->reply);
+ break;
+ case DBUS_MESSAGE_TYPE_ERROR:
+ msg = dbus_message_new_error(d_ptr->reply, data(d_ptr->name.toUtf8()), data(d_ptr->message.toUtf8()));
+ break;
+ }
+ if (!msg)
+ return 0;
+
+ QDBusMarshall::listToMessage(*this, msg, d_ptr->signature);
+ return msg;
+}
+
+/*!
+ \internal
+ Constructs a QDBusMessage by parsing the given DBusMessage object.
+*/
+QDBusMessage QDBusMessage::fromDBusMessage(DBusMessage *dmsg, const QDBusConnection &connection)
+{
+ QDBusMessage message;
+ if (!dmsg)
+ return message;
+
+ message.d_ptr->connection = connection;
+ message.d_ptr->type = dbus_message_get_type(dmsg);
+ message.d_ptr->path = QString::fromUtf8(dbus_message_get_path(dmsg));
+ message.d_ptr->interface = QString::fromUtf8(dbus_message_get_interface(dmsg));
+ message.d_ptr->name = message.d_ptr->type == DBUS_MESSAGE_TYPE_ERROR ?
+ QString::fromUtf8(dbus_message_get_error_name(dmsg)) :
+ QString::fromUtf8(dbus_message_get_member(dmsg));
+ message.d_ptr->service = QString::fromUtf8(dbus_message_get_sender(dmsg));
+ message.d_ptr->signature = QString::fromUtf8(dbus_message_get_signature(dmsg));
+ message.d_ptr->msg = dbus_message_ref(dmsg);
+
+ QDBusMarshall::messageToList(message, dmsg);
+ return message;
+}
+
+/*!
+ Creates a QDBusMessage that represents the same error as the QDBusError object.
+*/
+QDBusMessage QDBusMessage::fromError(const QDBusError &error)
+{
+ QDBusMessage message;
+ message.d_ptr->type = DBUS_MESSAGE_TYPE_ERROR;
+ message.d_ptr->name = error.name();
+ message << error.message();
+ return message;
+}
+
+/*!
+ Returns the path of the object that this message is being sent to (in the case of a
+ method call) or being received from (for a signal).
+*/
+QString QDBusMessage::path() const
+{
+ return d_ptr->path;
+}
+
+/*!
+ Returns the interface of the method being called (in the case of a method call) or of
+ the signal being received from.
+*/
+QString QDBusMessage::interface() const
+{
+ return d_ptr->interface;
+}
+
+/*!
+ Returns the name of the signal that was emitted or the name of the error that was
+ received.
+ \sa member()
+*/
+QString QDBusMessage::name() const
+{
+ return d_ptr->name;
+}
+
+/*!
+ \fn QDBusMessage::member() const
+ Returns the name of the method being called.
+*/
+
+/*!
+ \fn QDBusMessage::method() const
+ \overload
+ Returns the name of the method being called.
+*/
+
+/*!
+ Returns the name of the service or the bus address of the remote method call.
+*/
+QString QDBusMessage::service() const
+{
+ return d_ptr->service;
+}
+
+/*!
+ \fn QDBusMessage::sender() const
+ Returns the unique name of the remote sender.
+*/
+
+/*!
+ Returns the timeout (in milliseconds) for this message to be processed.
+*/
+int QDBusMessage::timeout() const
+{
+ return d_ptr->timeout;
+}
+
+/*!
+ Sets the timeout for this message to be processed, given by \a ms, in milliseconds.
+*/
+void QDBusMessage::setTimeout(int ms)
+{
+ qAtomicDetach(d_ptr);
+ d_ptr->timeout = ms;
+}
+
+/*!
+ Returns the flag that indicates if this message should see a reply or not. This is only
+ meaningful for MethodCall messages: any other kind of message cannot have replies and this
+ function will always return false for them.
+*/
+bool QDBusMessage::noReply() const
+{
+ if (!d_ptr->msg)
+ return false;
+ return dbus_message_get_no_reply(d_ptr->msg);
+}
+
+/*!
+ Returns the unique serial number assigned to this message
+ or 0 if the message was not sent yet.
+ */
+int QDBusMessage::serialNumber() const
+{
+ if (!d_ptr->msg)
+ return 0;
+ return dbus_message_get_serial(d_ptr->msg);
+}
+
+/*!
+ Returns the unique serial number assigned to the message
+ that triggered this reply message.
+
+ If this message is not a reply to another message, 0
+ is returned.
+
+ */
+int QDBusMessage::replySerialNumber() const
+{
+ if (!d_ptr->msg)
+ return 0;
+ return dbus_message_get_reply_serial(d_ptr->msg);
+}
+
+/*!
+ Returns true if this is a MethodCall message and a reply for it has been generated using
+ QDBusMessage::methodReply or QDBusMessage::error.
+*/
+bool QDBusMessage::wasRepliedTo() const
+{
+ return d_ptr->repliedTo;
+}
+
+/*!
+ Returns the signature of the signal that was received or for the output arguments
+ of a method call.
+*/
+QString QDBusMessage::signature() const
+{
+ return d_ptr->signature;
+}
+
+/*!
+ Sets the signature for the output arguments of this method call to be the value of \a
+ signature. This function has no meaning in other types of messages or when dealing with received
+ method calls.
+
+ A message's signature indicate the type of the parameters to
+ be marshalled over the bus. If there are more arguments than entries in the signature, the
+ tailing arguments will be silently dropped and not sent. If there are less arguments,
+ default values will be inserted (default values are those created by QVariant::convert
+ when a variant of type QVariant::Invalid is converted to the type).
+
+*/
+void QDBusMessage::setSignature(const QString &signature)
+{
+ qAtomicDetach(d_ptr);
+ d_ptr->signature = signature;
+}
+
+/*!
+ Returns the connection this message was received on or an unconnected QDBusConnection object if
+ this isn't a message that has been received.
+*/
+QDBusConnection QDBusMessage::connection() const
+{
+ return d_ptr->connection;
+}
+
+/*!
+ Returns the message type.
+*/
+QDBusMessage::MessageType QDBusMessage::type() const
+{
+ switch (d_ptr->type) {
+ case DBUS_MESSAGE_TYPE_METHOD_CALL:
+ return MethodCallMessage;
+ case DBUS_MESSAGE_TYPE_METHOD_RETURN:
+ return ReplyMessage;
+ case DBUS_MESSAGE_TYPE_ERROR:
+ return ErrorMessage;
+ case DBUS_MESSAGE_TYPE_SIGNAL:
+ return SignalMessage;
+ default:
+ return InvalidMessage;
+ }
+}
+
+// Document QDBusReply here
+/*!
+ \class QDBusReply
+ \brief The reply for a method call to a remote object.
+
+ A QDBusReply object is a subset of the QDBusMessage object that represents a method call's
+ reply. It contains only the first output argument or the error code and is used by
+ QDBusInterface-derived classes to allow returning the error code as the function's return
+ argument.
+
+ It can be used in the following manner:
+ \code
+ QDBusReply<QString> reply = interface->call("RemoteMethod");
+ if (reply.isSuccess())
+ // use the returned value
+ useValue(reply.value());
+ else
+ // call failed. Show an error condition.
+ showError(reply.error());
+ \endcode
+
+ If the remote method call cannot fail, you can skip the error checking:
+ \code
+ QString reply = interface->call("RemoteMethod");
+ \endcode
+
+ However, if it does fail under those conditions, the value returned by QDBusReply::value() is
+ undefined. It may be undistinguishable from a valid return value.
+
+ QDBusReply objects are used for remote calls that have no output arguments or return values
+ (i.e., they have a "void" return type). In this case, you can only test if the reply succeeded
+ or not, by calling isError() and isSuccess(), and inspecting the error condition by calling
+ error(). You cannot call value().
+
+ \sa QDBusMessage, QDBusInterface
+*/
+
+/*!
+ \fn QDBusReply::QDBusReply(const QDBusMessage &reply)
+ Automatically construct a QDBusReply object from the reply message \a reply, extracting the
+ first return value from it if it is a success reply.
+*/
+
+/*!
+ \fn QDBusReply::QDBusReply(const QDBusError &error)
+ Constructs an error reply from the D-Bus error code given by \a error.
+*/
+
+/*!
+ \fn QDBusReply::isError() const
+ Returns true if this reply is an error reply. You can extract the error contents using the
+ error() function.
+*/
+
+/*!
+ \fn QDBusReply::isSuccess() const
+ Returns true if this reply is a normal error reply (not an error). You can extract the returned
+ value with value()
+*/
+
+/*!
+ \fn QDBusReply::error()
+ Returns the error code that was returned from the remote function call. If the remote call did
+ not return an error (i.e., if it succeeded), then the QDBusError object that is returned will
+ not be a valid error code (QDBusError::isValid() will return false).
+*/
+
+/*!
+ \fn QDBusReply::value()
+ Returns the remote function's calls return value. If the remote call returned with an error,
+ the return value of this function is undefined and may be undistinguishable from a valid return
+ value.
+
+ This function is not available if the remote call returns \c void.
+*/
+
+/*!
+ \fn QDBusReply::operator Type()
+ Returns the same as value().
+
+ This function is not available if the remote call returns \c void.
+*/
+
+/*!
+ \internal
+ \fn QDBusReply::fromVariant(const QDBusReply<QVariant> &variantReply)
+ Converts the QDBusReply<QVariant> object to this type by converting the variant contained in
+ \a variantReply to the template's type and copying the error condition.
+
+ If the QVariant in variantReply is not convertible to this type, it will assume an undefined
+ value.
+*/
+
+#ifndef QT_NO_DEBUG
+QDebug operator<<(QDebug dbg, QDBusMessage::MessageType t)
+{
+ switch (t)
+ {
+ case QDBusMessage::MethodCallMessage:
+ return dbg << "MethodCall";
+ case QDBusMessage::ReplyMessage:
+ return dbg << "MethodReturn";
+ case QDBusMessage::SignalMessage:
+ return dbg << "Signal";
+ case QDBusMessage::ErrorMessage:
+ return dbg << "Error";
+ default:
+ return dbg << "Invalid";
+ }
+}
+
+static void debugVariantList(QDebug dbg, const QVariantList &list);
+static void debugVariantMap(QDebug dbg, const QVariantMap &map);
+
+static void debugVariant(QDebug dbg, const QVariant &v)
+{
+ dbg.nospace() << v.typeName() << "(";
+ switch (v.userType())
+ {
+ case QVariant::Bool:
+ dbg.nospace() << v.toBool();
+ break;
+ case QMetaType::UChar:
+ dbg.nospace() << qvariant_cast<uchar>(v);
+ break;
+ case QMetaType::Short:
+ dbg.nospace() << qvariant_cast<short>(v);
+ break;
+ case QMetaType::UShort:
+ dbg.nospace() << qvariant_cast<ushort>(v);
+ break;
+ case QVariant::Int:
+ dbg.nospace() << v.toInt();
+ break;
+ case QVariant::UInt:
+ dbg.nospace() << v.toUInt();
+ break;
+ case QVariant::LongLong:
+ dbg.nospace() << v.toLongLong();
+ break;
+ case QVariant::ULongLong:
+ dbg.nospace() << v.toULongLong();
+ break;
+ case QVariant::Double:
+ dbg.nospace() << v.toDouble();
+ break;
+ case QVariant::String:
+ dbg.nospace() << v.toString();
+ break;
+ case QVariant::ByteArray:
+ dbg.nospace() << v.toByteArray();
+ break;
+ case QVariant::StringList:
+ dbg.nospace() << v.toStringList();
+ break;
+ case QVariant::List:
+ debugVariantList(dbg, v.toList());
+ break;
+ case QVariant::Map:
+ debugVariantMap(dbg, v.toMap());
+ break;
+
+ default: {
+ int id = v.userType();
+ if (id == QDBusTypeHelper<QVariant>::id())
+ debugVariant(dbg, QDBusTypeHelper<QVariant>::fromVariant(v));
+ else if (id == QDBusTypeHelper<bool>::listId())
+ dbg.nospace() << QDBusTypeHelper<QList<bool> >::fromVariant(v);
+ else if (id == QDBusTypeHelper<short>::listId())
+ dbg.nospace() << QDBusTypeHelper<QList<short> >::fromVariant(v);
+ else if (id == QDBusTypeHelper<ushort>::listId())
+ dbg.nospace() << QDBusTypeHelper<QList<ushort> >::fromVariant(v);
+ else if (id == QDBusTypeHelper<int>::listId())
+ dbg.nospace() << QDBusTypeHelper<QList<int> >::fromVariant(v);
+ else if (id == QDBusTypeHelper<uint>::listId())
+ dbg.nospace() << QDBusTypeHelper<QList<uint> >::fromVariant(v);
+ else if (id == QDBusTypeHelper<qlonglong>::listId())
+ dbg.nospace() << QDBusTypeHelper<QList<qlonglong> >::fromVariant(v);
+ else if (id == QDBusTypeHelper<qulonglong>::listId())
+ dbg.nospace() << QDBusTypeHelper<QList<qulonglong> >::fromVariant(v);
+ else if (id == QDBusTypeHelper<double>::listId())
+ dbg.nospace() << QDBusTypeHelper<QList<double> >::fromVariant(v);
+ else
+ dbg.nospace() << "unknown";
+ }
+ }
+ dbg.nospace() << ")";
+}
+
+static void debugVariantList(QDebug dbg, const QVariantList &list)
+{
+ bool first = true;
+ QVariantList::ConstIterator it = list.constBegin();
+ QVariantList::ConstIterator end = list.constEnd();
+ for ( ; it != end; ++it) {
+ if (!first)
+ dbg.nospace() << ", ";
+ debugVariant(dbg, *it);
+ first = false;
+ }
+}
+
+static void debugVariantMap(QDebug dbg, const QVariantMap &map)
+{
+ QVariantMap::ConstIterator it = map.constBegin();
+ QVariantMap::ConstIterator end = map.constEnd();
+ for ( ; it != end; ++it) {
+ dbg << "(" << it.key() << ", ";
+ debugVariant(dbg, it.value());
+ dbg << ") ";
+ }
+}
+
+QDebug operator<<(QDebug dbg, const QDBusMessage &msg)
+{
+ dbg.nospace() << "QDBusMessage(type=" << msg.type()
+ << ", service=" << msg.service()
+ << ", path=" << msg.path()
+ << ", interface=" << msg.interface()
+ << ", name=" << msg.name()
+ << ", signature=" << msg.signature()
+ << ", contents=(";
+ debugVariantList(dbg, msg);
+ dbg.nospace() << " ) )";
+ return dbg.space();
+}
+#endif
+