Qt 4.8
qdbusmessage.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtDBus module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qdbusmessage.h"
43 
44 #include <qdebug.h>
45 #include <qstringlist.h>
46 
47 #include "qdbus_symbols_p.h"
48 
49 #include "qdbusargument_p.h"
50 #include "qdbuserror.h"
51 #include "qdbusmessage_p.h"
52 #include "qdbusmetatype.h"
53 #include "qdbusconnection_p.h"
54 #include "qdbusutil_p.h"
55 
56 #ifndef QT_NO_DBUS
57 
59 
60 static inline const char *data(const QByteArray &arr)
61 {
62  return arr.isEmpty() ? 0 : arr.constData();
63 }
64 
66  : msg(0), reply(0), type(DBUS_MESSAGE_TYPE_INVALID),
67  timeout(-1), localReply(0), ref(1), delayedReply(false), localMessage(false),
68  parametersValidated(false), autoStartService(true)
69 {
70 }
71 
73 {
74  if (msg)
75  q_dbus_message_unref(msg);
76  if (reply)
77  q_dbus_message_unref(reply);
78  delete localReply;
79 }
80 
89 {
90  if (d_ptr->type == ErrorMessage) {
91  if (!d_ptr->message.isEmpty())
92  return d_ptr->message;
93  if (!d_ptr->arguments.isEmpty())
94  return d_ptr->arguments.at(0).toString();
95  }
96  return QString();
97 }
98 
111 DBusMessage *QDBusMessagePrivate::toDBusMessage(const QDBusMessage &message, QDBusConnection::ConnectionCapabilities capabilities,
112  QDBusError *error)
113 {
114  if (!qdbus_loadLibDBus()) {
115  *error = QDBusError(QDBusError::Failed, QLatin1String("Could not open lidbus-1 library"));
116  return 0;
117  }
118 
119  DBusMessage *msg = 0;
120  const QDBusMessagePrivate *d_ptr = message.d_ptr;
121 
122  switch (d_ptr->type) {
123  case DBUS_MESSAGE_TYPE_INVALID:
124  //qDebug() << "QDBusMessagePrivate::toDBusMessage" << "message is invalid";
125  break;
126  case DBUS_MESSAGE_TYPE_METHOD_CALL:
127  // only service and interface can be empty -> path and name must not be empty
128  if (!d_ptr->parametersValidated) {
130  return 0;
132  return 0;
134  return 0;
135  if (!QDBusUtil::checkMemberName(d_ptr->name, QDBusUtil::EmptyNotAllowed, error, "method"))
136  return 0;
137  }
138 
139  msg = q_dbus_message_new_method_call(data(d_ptr->service.toUtf8()), d_ptr->path.toUtf8(),
140  data(d_ptr->interface.toUtf8()), d_ptr->name.toUtf8());
141  q_dbus_message_set_auto_start( msg, d_ptr->autoStartService );
142  break;
143  case DBUS_MESSAGE_TYPE_METHOD_RETURN:
144  msg = q_dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN);
145  if (!d_ptr->localMessage) {
146  q_dbus_message_set_destination(msg, q_dbus_message_get_sender(d_ptr->reply));
147  q_dbus_message_set_reply_serial(msg, q_dbus_message_get_serial(d_ptr->reply));
148  }
149  break;
150  case DBUS_MESSAGE_TYPE_ERROR:
151  // error name can't be empty
152  if (!d_ptr->parametersValidated
154  return 0;
155 
156  msg = q_dbus_message_new(DBUS_MESSAGE_TYPE_ERROR);
157  q_dbus_message_set_error_name(msg, d_ptr->name.toUtf8());
158  if (!d_ptr->localMessage) {
159  q_dbus_message_set_destination(msg, q_dbus_message_get_sender(d_ptr->reply));
160  q_dbus_message_set_reply_serial(msg, q_dbus_message_get_serial(d_ptr->reply));
161  }
162  break;
163  case DBUS_MESSAGE_TYPE_SIGNAL:
164  // nothing can be empty here
165  if (!d_ptr->parametersValidated) {
167  return 0;
169  return 0;
170  if (!QDBusUtil::checkMemberName(d_ptr->name, QDBusUtil::EmptyNotAllowed, error, "method"))
171  return 0;
172  }
173 
174  msg = q_dbus_message_new_signal(d_ptr->path.toUtf8(), d_ptr->interface.toUtf8(),
175  d_ptr->name.toUtf8());
176  break;
177  default:
178  Q_ASSERT(false);
179  break;
180  }
181 
182  // if we got here, the parameters validated
183  // and since the message parameters cannot be changed once the message is created
184  // we can record this fact
185  d_ptr->parametersValidated = true;
186 
187  QDBusMarshaller marshaller(capabilities);
190  q_dbus_message_iter_init_append(msg, &marshaller.iterator);
191  if (!d_ptr->message.isEmpty())
192  // prepend the error message
193  marshaller.append(d_ptr->message);
194  for ( ; it != cend; ++it)
195  marshaller.appendVariantInternal(*it);
196 
197  // check if everything is ok
198  if (marshaller.ok)
199  return msg;
200 
201  // not ok;
202  q_dbus_message_unref(msg);
203  *error = QDBusError(QDBusError::Failed, QLatin1String("Marshalling failed: ") + marshaller.errorString);
204  return 0;
205 }
206 
207 /*
208 struct DBusMessage
209 {
210  DBusAtomic refcount;
211  DBusHeader header;
212  DBusString body;
213  char byte_order;
214  unsigned int locked : 1;
215 DBUS_DISABLE_CHECKS
216  unsigned int in_cache : 1;
217 #endif
218  DBusList *size_counters;
219  long size_counter_delta;
220  dbus_uint32_t changed_stamp : CHANGED_STAMP_BITS;
221  DBusDataSlotList slot_list;
222 #ifndef DBUS_DISABLE_CHECKS
223  int generation;
224 #endif
225 };
226 */
227 
235 QDBusMessage QDBusMessagePrivate::fromDBusMessage(DBusMessage *dmsg, QDBusConnection::ConnectionCapabilities capabilities)
236 {
238  if (!dmsg)
239  return message;
240 
241  message.d_ptr->type = q_dbus_message_get_type(dmsg);
242  message.d_ptr->path = QString::fromUtf8(q_dbus_message_get_path(dmsg));
243  message.d_ptr->interface = QString::fromUtf8(q_dbus_message_get_interface(dmsg));
244  message.d_ptr->name = message.d_ptr->type == DBUS_MESSAGE_TYPE_ERROR ?
245  QString::fromUtf8(q_dbus_message_get_error_name(dmsg)) :
246  QString::fromUtf8(q_dbus_message_get_member(dmsg));
247  message.d_ptr->service = QString::fromUtf8(q_dbus_message_get_sender(dmsg));
248  message.d_ptr->signature = QString::fromUtf8(q_dbus_message_get_signature(dmsg));
249  message.d_ptr->msg = q_dbus_message_ref(dmsg);
250 
251  QDBusDemarshaller demarshaller(capabilities);
252  demarshaller.message = q_dbus_message_ref(dmsg);
253  if (q_dbus_message_iter_init(demarshaller.message, &demarshaller.iterator))
254  while (!demarshaller.atEnd())
255  message << demarshaller.toVariantInternal();
256  return message;
257 }
258 
260 {
261  return message.d_ptr->localMessage;
262 }
263 
265  const QDBusMessage &asSent)
266 {
267  // simulate the message being sent to the bus and then received back
268  // the only field that the bus sets when delivering the message
269  // (as opposed to the message as we send it), is the sender
270  // so we simply set the sender to our unique name
271 
272  // determine if we are carrying any complex types
273  QString computedSignature;
276  for ( ; it != end; ++it) {
277  int id = it->userType();
278  const char *signature = QDBusMetaType::typeToSignature(id);
279  if ((id != QVariant::StringList && id != QVariant::ByteArray &&
280  qstrlen(signature) != 1) || id == qMetaTypeId<QDBusVariant>()) {
281  // yes, we are
282  // we must marshall and demarshall again so as to create QDBusArgument
283  // entries for the complex types
285  DBusMessage *message = toDBusMessage(asSent, conn.capabilities, &error);
286  if (!message) {
287  // failed to marshall, so it's a call error
288  return QDBusMessage::createError(error);
289  }
290 
291  q_dbus_message_set_sender(message, conn.baseService.toUtf8());
292 
293  QDBusMessage retval = fromDBusMessage(message, conn.capabilities);
294  retval.d_ptr->localMessage = true;
295  q_dbus_message_unref(message);
296  if (retval.d_ptr->service.isEmpty())
297  retval.d_ptr->service = conn.baseService;
298  return retval;
299  } else {
300  computedSignature += QLatin1String(signature);
301  }
302  }
303 
304  // no complex types seen
305  // optimize by using the variant list itself
306  QDBusMessage retval;
307  QDBusMessagePrivate *d = retval.d_ptr;
308  d->arguments = asSent.d_ptr->arguments;
309  d->path = asSent.d_ptr->path;
310  d->interface = asSent.d_ptr->interface;
311  d->name = asSent.d_ptr->name;
312  d->message = asSent.d_ptr->message;
313  d->type = asSent.d_ptr->type;
314 
315  d->service = conn.baseService;
316  d->signature = computedSignature;
317  d->localMessage = true;
318  return retval;
319 }
320 
322  const QDBusMessage &callMsg)
323 {
324  // simulate the reply (return or error) message being sent to the bus and
325  // then received back.
326  if (callMsg.d_ptr->localReply)
327  return makeLocal(conn, *callMsg.d_ptr->localReply);
328  return QDBusMessage(); // failed
329 }
330 
380  const QString &name)
381 {
383  message.d_ptr->type = DBUS_MESSAGE_TYPE_SIGNAL;
384  message.d_ptr->path = path;
385  message.d_ptr->interface = interface;
386  message.d_ptr->name = name;
387 
388  return message;
389 }
390 
411  const QString &interface, const QString &method)
412 {
414  message.d_ptr->type = DBUS_MESSAGE_TYPE_METHOD_CALL;
415  message.d_ptr->service = service;
416  message.d_ptr->path = path;
417  message.d_ptr->interface = interface;
418  message.d_ptr->name = method;
419 
420  return message;
421 }
422 
428 {
430  error.d_ptr->type = DBUS_MESSAGE_TYPE_ERROR;
431  error.d_ptr->name = name;
432  error.d_ptr->message = msg;
433 
434  return error;
435 }
436 
466 {
468  reply.setArguments(arguments);
469  reply.d_ptr->type = DBUS_MESSAGE_TYPE_METHOD_RETURN;
470  if (d_ptr->msg)
471  reply.d_ptr->reply = q_dbus_message_ref(d_ptr->msg);
472  if (d_ptr->localMessage) {
473  reply.d_ptr->localMessage = true;
474  d_ptr->localReply = new QDBusMessage(reply); // keep an internal copy
475  }
476 
477  // the reply must have a msg or be a local-loop optimization
478  Q_ASSERT(reply.d_ptr->reply || reply.d_ptr->localMessage);
479  return reply;
480 }
481 
487 {
489  if (d_ptr->msg)
490  reply.d_ptr->reply = q_dbus_message_ref(d_ptr->msg);
491  if (d_ptr->localMessage) {
492  reply.d_ptr->localMessage = true;
493  d_ptr->localReply = new QDBusMessage(reply); // keep an internal copy
494  }
495 
496  // the reply must have a msg or be a local-loop optimization
497  Q_ASSERT(reply.d_ptr->reply || reply.d_ptr->localMessage);
498  return reply;
499 }
500 
531 {
532  QDBusMessage msg = createErrorReply(QDBusError::errorString(atype), amsg);
533  msg.d_ptr->parametersValidated = true;
534  return msg;
535 }
536 
537 
544 {
545  d_ptr = new QDBusMessagePrivate;
546 }
547 
556 {
557  d_ptr = other.d_ptr;
558  d_ptr->ref.ref();
559 }
560 
565 {
566  if (!d_ptr->ref.deref())
567  delete d_ptr;
568 }
569 
578 {
579  qAtomicAssign(d_ptr, other.d_ptr);
580  return *this;
581 }
582 
587 {
588  return d_ptr->service;
589 }
590 
596 {
597  return d_ptr->path;
598 }
599 
605 {
606  return d_ptr->interface;
607 }
608 
613 {
614  if (d_ptr->type != ErrorMessage)
615  return d_ptr->name;
616  return QString();
617 }
618 
623 {
624  if (d_ptr->type == ErrorMessage)
625  return d_ptr->name;
626  return QString();
627 }
628 
634 {
635  return d_ptr->signature;
636 }
637 
645 {
646  if (!d_ptr->msg)
647  return d_ptr->localMessage; // if it's a local message, reply is required
648  return !q_dbus_message_get_no_reply(d_ptr->msg);
649 }
650 
665 void QDBusMessage::setDelayedReply(bool enable) const
666 {
667  d_ptr->delayedReply = enable;
668 }
669 
676 {
677  return d_ptr->delayedReply;
678 }
679 
701 {
702  d_ptr->autoStartService = enable;
703 }
704 
715 {
716  return d_ptr->autoStartService;
717 }
718 
726 {
727  // FIXME: should we detach?
728  d_ptr->arguments = arguments;
729 }
730 
736 {
737  return d_ptr->arguments;
738 }
739 
746 {
747  // FIXME: should we detach?
748  d_ptr->arguments.append(arg);
749  return *this;
750 }
751 
756 {
757  switch (d_ptr->type) {
758  case DBUS_MESSAGE_TYPE_METHOD_CALL:
759  return MethodCallMessage;
760  case DBUS_MESSAGE_TYPE_METHOD_RETURN:
761  return ReplyMessage;
762  case DBUS_MESSAGE_TYPE_ERROR:
763  return ErrorMessage;
764  case DBUS_MESSAGE_TYPE_SIGNAL:
765  return SignalMessage;
766  default:
767  break;
768  }
769  return InvalidMessage;
770 }
771 
782 #ifndef QT_NO_DEBUG_STREAM
784 {
785  switch (t)
786  {
788  return dbg << "MethodCall";
790  return dbg << "MethodReturn";
792  return dbg << "Signal";
794  return dbg << "Error";
795  default:
796  return dbg << "Invalid";
797  }
798 }
799 
800 static void debugVariantList(QDebug dbg, const QVariantList &list)
801 {
802  bool first = true;
805  for ( ; it != end; ++it) {
806  if (!first)
807  dbg.nospace() << ", ";
809  first = false;
810  }
811 }
812 
814 {
815  dbg.nospace() << "QDBusMessage(type=" << msg.type()
816  << ", service=" << msg.service();
817  if (msg.type() == QDBusMessage::MethodCallMessage ||
819  dbg.nospace() << ", path=" << msg.path()
820  << ", interface=" << msg.interface()
821  << ", member=" << msg.member();
822  if (msg.type() == QDBusMessage::ErrorMessage)
823  dbg.nospace() << ", error name=" << msg.errorName()
824  << ", error message=" << msg.errorMessage();
825  dbg.nospace() << ", signature=" << msg.signature()
826  << ", contents=(";
827  debugVariantList(dbg, msg.arguments());
828  dbg.nospace() << ") )";
829  return dbg.space();
830 }
831 #endif
832 
834 
835 #endif // QT_NO_DBUS
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:92
QDBusMessage & operator=(const QDBusMessage &other)
Copies the contents of the object given by other.
The QDebug class provides an output stream for debugging information.
Definition: qdebug.h:62
double d
Definition: qnumeric_p.h:62
DBusMessage * message
static QDBusMessage createError(const QString &name, const QString &msg)
Constructs a new DBus message representing an error, with the given name and msg. ...
int type
Definition: qmetatype.cpp:239
static bool isLocal(const QDBusMessage &msg)
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
bool checkMemberName(const QString &name, AllowEmptyFlag empty, QDBusError *error, const char *nameType=0)
Definition: qdbusutil_p.h:135
static QDBusMessage createSignal(const QString &path, const QString &interface, const QString &name)
Constructs a new DBus message with the given path, interface and name, representing a signal emission...
#define it(className, varName)
QDebug & nospace()
Clears the stream&#39;s internal flag that records whether the last character was a space and returns a r...
Definition: qdebug.h:92
QByteArray toUtf8() const Q_REQUIRED_RESULT
Returns a UTF-8 representation of the string as a QByteArray.
Definition: qstring.cpp:4074
#define error(msg)
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
QString service() const
Returns the name of the service or the bus address of the remote method call.
QList< QVariant > arguments
The QDBusError class represents an error received from the D-Bus bus or from remote applications foun...
Definition: qdbuserror.h:60
void setAutoStartService(bool enable)
Sets the auto start flag to enable.
MessageType
The possible message types:
Definition: qdbusmessage.h:62
const_iterator constBegin() const
Returns a const STL-style iterator pointing to the first item in the list.
Definition: qlist.h:269
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
bool ref()
Atomically increments the value of this QAtomicInt.
void setDelayedReply(bool enable) const
Sets whether the message will be replied later (if enable is true) or if an automatic reply should be...
The QString class provides a Unicode character string.
Definition: qstring.h:83
static QDebug operator<<(QDebug dbg, QDBusMessage::MessageType t)
Sends the message without waiting for a reply.
static void debugVariantList(QDebug dbg, const QVariantList &list)
DBusMessageIter iterator
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
ErrorType
In order to facilitate verification of the most common D-Bus errors generated by the D-Bus implementa...
Definition: qdbuserror.h:63
bool appendVariantInternal(const QVariant &arg)
static QDBusMessage fromDBusMessage(DBusMessage *dmsg, QDBusConnection::ConnectionCapabilities capabilities)
Constructs a QDBusMessage by parsing the given DBusMessage object.
QDBusMessage createErrorReply(const QString name, const QString &msg) const
Constructs a new DBus message representing an error reply message, with the given name and msg...
QString signature() const
Returns the signature of the signal that was received or for the output arguments of a method call...
static const char * typeToSignature(int type)
Returns the D-Bus signature equivalent to the supplied meta type id type.
DBusMessage * reply
void append(const T &t)
Inserts value at the end of the list.
Definition: qlist.h:507
bool checkBusName(const QString &name, AllowEmptyFlag empty, QDBusError *error)
Definition: qdbusutil_p.h:111
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
QString errorMessage() const
Returns the human-readable message associated with the error that was received.
QList< QVariant > arguments() const
Returns the list of arguments that are going to be sent or were received from D-Bus.
static QDBusMessage makeLocal(const QDBusConnectionPrivate &conn, const QDBusMessage &asSent)
QString path() const
Returns the path of the object that this message is being sent to (in the case of a method call) or b...
QDBusMessage()
Constructs an empty, invalid QDBusMessage object.
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
~QDBusMessage()
Disposes of the object and frees any resources that were being held.
QDBusMessagePrivate * d_ptr
Definition: qdbusmessage.h:119
bool isReplyRequired() const
Returns the flag that indicates if this message should see a reply or not.
DBusMessage * msg
static QString fromUtf8(const char *, int size=-1)
Returns a QString initialized with the first size bytes of the UTF-8 string str.
Definition: qstring.cpp:4302
static DBusMessage * toDBusMessage(const QDBusMessage &message, QDBusConnection::ConnectionCapabilities capabilities, QDBusError *error)
Constructs a DBusMessage object from message.
static const char * data(const QByteArray &arr)
QDBusMessage * localReply
QDBusMessage & operator<<(const QVariant &arg)
Appends the argument arg to the list of arguments to be sent over D-Bus in a method call or signal em...
QString member() const
Returns the name of the signal that was emitted or the name of the method that was called...
QDBusConnection::ConnectionCapabilities capabilities
bool isDelayedReply() const
Returns the delayed reply flag, as set by setDelayedReply().
void append(uchar arg)
QDBusMessage createReply(const QList< QVariant > &arguments=QList< QVariant >()) const
Constructs a new DBus message representing a reply, with the given arguments.
const char * constData() const
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:433
QString interface() const
Returns the interface of the method being called (in the case of a method call) or of the signal bein...
uint qstrlen(const char *str)
Definition: qbytearray.h:79
bool autoStartService() const
Returns the auto start flag, as set by setAutoStartService().
QString errorName() const
Returns the name of the error that was received.
static QDBusMessage createMethodCall(const QString &destination, const QString &path, const QString &interface, const QString &method)
Constructs a new DBus message representing a method call.
const_iterator ConstIterator
Qt-style synonym for QList::const_iterator.
Definition: qlist.h:279
DBusMessageIter iterator
if(void) toggleToolbarShown
void qAtomicAssign(T *&d, T *x)
This is a helper for the assignment operators of implicitly shared classes.
Definition: qatomic.h:195
bool checkObjectPath(const QString &path, AllowEmptyFlag empty, QDBusError *error)
Definition: qdbusutil_p.h:123
The QDBusMessage class represents one message sent or received over the D-Bus bus.
Definition: qdbusmessage.h:59
bool qdbus_loadLibDBus()
MessageType type() const
Returns the message type.
bool checkErrorName(const QString &name, AllowEmptyFlag empty, QDBusError *error)
Definition: qdbusutil_p.h:149
void setArguments(const QList< QVariant > &arguments)
Sets the arguments that are going to be sent over D-Bus to arguments.
bool isEmpty() const
Returns true if the byte array has size 0; otherwise returns false.
Definition: qbytearray.h:421
static QDBusMessage makeLocalReply(const QDBusConnectionPrivate &conn, const QDBusMessage &asSent)
bool checkInterfaceName(const QString &name, AllowEmptyFlag empty, QDBusError *error)
Definition: qdbusutil_p.h:99
static const KeyPair *const end
QDebug & space()
Writes a space character to the debug stream and returns a reference to the stream.
Definition: qdebug.h:91
#define qPrintable(string)
Definition: qglobal.h:1750
static QString errorString(ErrorType error)
Returns the error name associated with error condition error.
Definition: qdbuserror.cpp:368
QString argumentToString(const QVariant &arg)
Dumps the contents of a QtDBus argument from arg into a string.
Definition: qdbusutil.cpp:324
const_iterator constEnd() const
Returns a const STL-style iterator pointing to the imaginary item after the last item in the list...
Definition: qlist.h:272