source: trunk/src/dbus/qdbusmessage.cpp@ 168

Last change on this file since 168 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 22.2 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtDBus module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
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
56QT_BEGIN_NAMESPACE
57
58static inline const char *data(const QByteArray &arr)
59{
60 return arr.isEmpty() ? 0 : arr.constData();
61}
62
63QDBusMessagePrivate::QDBusMessagePrivate()
64 : msg(0), reply(0), type(DBUS_MESSAGE_TYPE_INVALID),
65 timeout(-1), localReply(0), ref(1), delayedReply(false), localMessage(false)
66{
67}
68
69QDBusMessagePrivate::~QDBusMessagePrivate()
70{
71 if (msg)
72 q_dbus_message_unref(msg);
73 if (reply)
74 q_dbus_message_unref(reply);
75 delete localReply;
76}
77
78/*!
79 \since 4.3
80 Returns the human-readable message associated with the error that was received.
81*/
82QString QDBusMessage::errorMessage() const
83{
84 if (d_ptr->type == ErrorMessage) {
85 if (!d_ptr->message.isEmpty())
86 return d_ptr->message;
87 if (!d_ptr->arguments.isEmpty())
88 return d_ptr->arguments.at(0).toString();
89 }
90 return QString();
91}
92
93/*!
94 \internal
95 Constructs a DBusMessage object from this object. The returned value must be de-referenced
96 with q_dbus_message_unref.
97*/
98DBusMessage *QDBusMessagePrivate::toDBusMessage(const QDBusMessage &message)
99{
100 if (!qdbus_loadLibDBus())
101 return 0;
102
103 DBusMessage *msg = 0;
104 const QDBusMessagePrivate *d_ptr = message.d_ptr;
105
106 switch (d_ptr->type) {
107 case DBUS_MESSAGE_TYPE_INVALID:
108 //qDebug() << "QDBusMessagePrivate::toDBusMessage" << "message is invalid";
109 break;
110 case DBUS_MESSAGE_TYPE_METHOD_CALL:
111 msg = q_dbus_message_new_method_call(data(d_ptr->service.toUtf8()), data(d_ptr->path.toUtf8()),
112 data(d_ptr->interface.toUtf8()), data(d_ptr->name.toUtf8()));
113 break;
114 case DBUS_MESSAGE_TYPE_METHOD_RETURN:
115 msg = q_dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN);
116 if (!d_ptr->localMessage) {
117 q_dbus_message_set_destination(msg, q_dbus_message_get_sender(d_ptr->reply));
118 q_dbus_message_set_reply_serial(msg, q_dbus_message_get_serial(d_ptr->reply));
119 }
120 break;
121 case DBUS_MESSAGE_TYPE_ERROR:
122 msg = q_dbus_message_new(DBUS_MESSAGE_TYPE_ERROR);
123 q_dbus_message_set_error_name(msg, data(d_ptr->name.toUtf8()));
124 if (!d_ptr->localMessage) {
125 q_dbus_message_set_destination(msg, q_dbus_message_get_sender(d_ptr->reply));
126 q_dbus_message_set_reply_serial(msg, q_dbus_message_get_serial(d_ptr->reply));
127 }
128 break;
129 case DBUS_MESSAGE_TYPE_SIGNAL:
130 msg = q_dbus_message_new_signal(data(d_ptr->path.toUtf8()), data(d_ptr->interface.toUtf8()),
131 data(d_ptr->name.toUtf8()));
132 break;
133 default:
134 Q_ASSERT(false);
135 break;
136 }
137#if 0
138 DBusError err;
139 q_dbus_error_init(&err);
140 if (q_dbus_error_is_set(&err)) {
141 QDBusError qe(&err);
142 qDebug() << "QDBusMessagePrivate::toDBusMessage" << qe;
143 }
144#endif
145 if (!msg)
146 return 0;
147
148 QDBusMarshaller marshaller;
149 QVariantList::ConstIterator it = d_ptr->arguments.constBegin();
150 QVariantList::ConstIterator cend = d_ptr->arguments.constEnd();
151 q_dbus_message_iter_init_append(msg, &marshaller.iterator);
152 if (!d_ptr->message.isEmpty())
153 // prepend the error message
154 marshaller.append(d_ptr->message);
155 for ( ; it != cend; ++it)
156 marshaller.appendVariantInternal(*it);
157
158 // check if everything is ok
159 if (marshaller.ok)
160 return msg;
161
162 // not ok;
163 q_dbus_message_unref(msg);
164 Q_ASSERT(false);
165 return 0;
166}
167
168/*
169struct DBusMessage
170{
171 DBusAtomic refcount;
172 DBusHeader header;
173 DBusString body;
174 char byte_order;
175 unsigned int locked : 1;
176DBUS_DISABLE_CHECKS
177 unsigned int in_cache : 1;
178#endif
179 DBusList *size_counters;
180 long size_counter_delta;
181 dbus_uint32_t changed_stamp : CHANGED_STAMP_BITS;
182 DBusDataSlotList slot_list;
183#ifndef DBUS_DISABLE_CHECKS
184 int generation;
185#endif
186};
187*/
188
189/*!
190 \internal
191 Constructs a QDBusMessage by parsing the given DBusMessage object.
192*/
193QDBusMessage QDBusMessagePrivate::fromDBusMessage(DBusMessage *dmsg)
194{
195 QDBusMessage message;
196 if (!dmsg)
197 return message;
198
199 message.d_ptr->type = q_dbus_message_get_type(dmsg);
200 message.d_ptr->path = QString::fromUtf8(q_dbus_message_get_path(dmsg));
201 message.d_ptr->interface = QString::fromUtf8(q_dbus_message_get_interface(dmsg));
202 message.d_ptr->name = message.d_ptr->type == DBUS_MESSAGE_TYPE_ERROR ?
203 QString::fromUtf8(q_dbus_message_get_error_name(dmsg)) :
204 QString::fromUtf8(q_dbus_message_get_member(dmsg));
205 message.d_ptr->service = QString::fromUtf8(q_dbus_message_get_sender(dmsg));
206 message.d_ptr->signature = QString::fromUtf8(q_dbus_message_get_signature(dmsg));
207 message.d_ptr->msg = q_dbus_message_ref(dmsg);
208
209 QDBusDemarshaller demarshaller;
210 demarshaller.message = q_dbus_message_ref(dmsg);
211 if (q_dbus_message_iter_init(demarshaller.message, &demarshaller.iterator))
212 while (!demarshaller.atEnd())
213 message << demarshaller.toVariantInternal();
214 return message;
215}
216
217bool QDBusMessagePrivate::isLocal(const QDBusMessage &message)
218{
219 return message.d_ptr->localMessage;
220}
221
222QDBusMessage QDBusMessagePrivate::makeLocal(const QDBusConnectionPrivate &conn,
223 const QDBusMessage &asSent)
224{
225 // simulate the message being sent to the bus and then received back
226 // the only field that the bus sets when delivering the message
227 // (as opposed to the message as we send it), is the sender
228 // so we simply set the sender to our unique name
229
230 // determine if we are carrying any complex types
231 QString computedSignature;
232 QVariantList::ConstIterator it = asSent.d_ptr->arguments.constBegin();
233 QVariantList::ConstIterator end = asSent.d_ptr->arguments.constEnd();
234 for ( ; it != end; ++it) {
235 int id = it->userType();
236 const char *signature = QDBusMetaType::typeToSignature(id);
237 if ((id != QVariant::StringList && id != QVariant::ByteArray &&
238 qstrlen(signature) != 1) || id == qMetaTypeId<QDBusVariant>()) {
239 // yes, we are
240 // we must marshall and demarshall again so as to create QDBusArgument
241 // entries for the complex types
242 DBusMessage *message = toDBusMessage(asSent);
243 q_dbus_message_set_sender(message, conn.baseService.toUtf8());
244
245 QDBusMessage retval = fromDBusMessage(message);
246 retval.d_ptr->localMessage = true;
247 q_dbus_message_unref(message);
248 if (retval.d_ptr->service.isEmpty())
249 retval.d_ptr->service = conn.baseService;
250 return retval;
251 } else {
252 computedSignature += QLatin1String(signature);
253 }
254 }
255
256 // no complex types seen
257 // optimise by using the variant list itself
258 QDBusMessage retval;
259 QDBusMessagePrivate *d = retval.d_ptr;
260 d->arguments = asSent.d_ptr->arguments;
261 d->path = asSent.d_ptr->path;
262 d->interface = asSent.d_ptr->interface;
263 d->name = asSent.d_ptr->name;
264 d->message = asSent.d_ptr->message;
265 d->type = asSent.d_ptr->type;
266
267 d->service = conn.baseService;
268 d->signature = computedSignature;
269 d->localMessage = true;
270 return retval;
271}
272
273QDBusMessage QDBusMessagePrivate::makeLocalReply(const QDBusConnectionPrivate &conn,
274 const QDBusMessage &callMsg)
275{
276 // simulate the reply (return or error) message being sent to the bus and
277 // then received back.
278 if (callMsg.d_ptr->localReply)
279 return makeLocal(conn, *callMsg.d_ptr->localReply);
280 return QDBusMessage(); // failed
281}
282
283/*!
284 \class QDBusMessage
285 \inmodule QtDBus
286 \since 4.2
287
288 \brief The QDBusMessage class represents one message sent or
289 received over the D-Bus bus.
290
291 This object can represent any of the four different types of
292 messages (MessageType) that can occur on the bus:
293
294 \list
295 \o Method calls
296 \o Method return values
297 \o Signal emissions
298 \o Error codes
299 \endlist
300
301 Objects of this type are created with the static createError(),
302 createMethodCall() and createSignal() functions. Use the
303 QDBusConnection::send() function to send the messages.
304*/
305
306/*!
307 \enum QDBusMessage::MessageType
308 The possible message types:
309
310 \value MethodCallMessage a message representing an outgoing or incoming method call
311 \value SignalMessage a message representing an outgoing or incoming signal emission
312 \value ReplyMessage a message representing the return values of a method call
313 \value ErrorMessage a message representing an error condition in response to a method call
314 \value InvalidMessage an invalid message: this is never set on messages received from D-Bus
315*/
316
317/*!
318 Constructs a new DBus message with the given \a path, \a interface
319 and \a name, representing a signal emission.
320
321 A DBus signal is emitted from one application and is received by
322 all applications that are listening for that signal from that
323 interface.
324
325 The QDBusMessage object that is returned can be sent using the
326 QDBusConnection::send() function.
327*/
328QDBusMessage QDBusMessage::createSignal(const QString &path, const QString &interface,
329 const QString &name)
330{
331 QDBusMessage message;
332 message.d_ptr->type = DBUS_MESSAGE_TYPE_SIGNAL;
333 message.d_ptr->path = path;
334 message.d_ptr->interface = interface;
335 message.d_ptr->name = name;
336
337 return message;
338}
339
340/*!
341 Constructs a new DBus message representing a method call.
342 A method call always informs its destination address
343 (\a service, \a path, \a interface and \a method).
344
345 The DBus bus allows calling a method on a given remote object without specifying the
346 destination interface, if the method name is unique. However, if two interfaces on the
347 remote object export the same method name, the result is undefined (one of the two may be
348 called or an error may be returned).
349
350 When using DBus in a peer-to-peer context (i.e., not on a bus), the \a service parameter is
351 optional.
352
353 The QDBusObject and QDBusInterface classes provide a simpler abstraction to synchronous
354 method calling.
355
356 This function returns a QDBusMessage object that can be sent with
357 QDBusConnection::call().
358*/
359QDBusMessage QDBusMessage::createMethodCall(const QString &service, const QString &path,
360 const QString &interface, const QString &method)
361{
362 QDBusMessage message;
363 message.d_ptr->type = DBUS_MESSAGE_TYPE_METHOD_CALL;
364 message.d_ptr->service = service;
365 message.d_ptr->path = path;
366 message.d_ptr->interface = interface;
367 message.d_ptr->name = method;
368
369 return message;
370}
371
372/*!
373 Constructs a new DBus message representing an error,
374 with the given \a name and \a msg.
375*/
376QDBusMessage QDBusMessage::createError(const QString &name, const QString &msg)
377{
378 QDBusMessage error;
379 error.d_ptr->type = DBUS_MESSAGE_TYPE_ERROR;
380 error.d_ptr->name = name;
381 error.d_ptr->message = msg;
382
383 return error;
384}
385
386/*!
387 \fn QDBusMessage QDBusMessage::createError(const QDBusError &error)
388
389 Constructs a new DBus message representing the given \a error.
390*/
391
392/*!
393 \fn QDBusMessage QDBusMessage::createError(QDBusError::ErrorType type, const QString &msg)
394
395 Constructs a new DBus message for the error type \a type using
396 the message \a msg. Returns the DBus message.
397*/
398
399/*!
400 \fn QDBusMessage QDBusMessage::createReply(const QList<QVariant> &arguments) const
401
402 Constructs a new DBus message representing a reply, with the given
403 \a arguments.
404*/
405QDBusMessage QDBusMessage::createReply(const QVariantList &arguments) const
406{
407 QDBusMessage reply;
408 reply.setArguments(arguments);
409 reply.d_ptr->type = DBUS_MESSAGE_TYPE_METHOD_RETURN;
410 if (d_ptr->msg)
411 reply.d_ptr->reply = q_dbus_message_ref(d_ptr->msg);
412 if (d_ptr->localMessage) {
413 reply.d_ptr->localMessage = true;
414 d_ptr->localReply = new QDBusMessage(reply); // keep an internal copy
415 }
416
417 // the reply must have a msg or be a local-loop optimisation
418 Q_ASSERT(reply.d_ptr->reply || reply.d_ptr->localMessage);
419 return reply;
420}
421
422/*!
423 Constructs a new DBus message representing an error reply message,
424 with the given \a name and \a msg.
425*/
426QDBusMessage QDBusMessage::createErrorReply(const QString name, const QString &msg) const
427{
428 QDBusMessage reply = QDBusMessage::createError(name, msg);
429 if (d_ptr->msg)
430 reply.d_ptr->reply = q_dbus_message_ref(d_ptr->msg);
431 if (d_ptr->localMessage) {
432 reply.d_ptr->localMessage = true;
433 d_ptr->localReply = new QDBusMessage(reply); // keep an internal copy
434 }
435
436 // the reply must have a msg or be a local-loop optimisation
437 Q_ASSERT(reply.d_ptr->reply || reply.d_ptr->localMessage);
438 return reply;
439}
440
441/*!
442 \fn QDBusMessage QDBusMessage::createReply(const QVariant &argument) const
443
444 Constructs a new DBus message representing a reply, with the
445 given \a argument.
446*/
447
448/*!
449 \fn QDBusMessage QDBusMessage::createErrorReply(const QDBusError &error) const
450
451 Constructs a new DBus message representing an error reply message,
452 from the given \a error object.
453*/
454
455/*!
456 \fn QDBusMessage QDBusMessage::createErrorReply(QDBusError::ErrorType type, const QString &msg) const
457
458 Constructs a new DBus reply message for the error type \a type using
459 the message \a msg. Returns the DBus message.
460*/
461
462/*!
463 Constructs an empty, invalid QDBusMessage object.
464
465 \sa createError(), createMethodCall(), createSignal()
466*/
467QDBusMessage::QDBusMessage()
468{
469 d_ptr = new QDBusMessagePrivate;
470}
471
472/*!
473 Constructs a copy of the object given by \a other.
474
475 Note: QDBusMessage objects are shared. Modifications made to the
476 copy will affect the original one as well. See setDelayedReply()
477 for more information.
478*/
479QDBusMessage::QDBusMessage(const QDBusMessage &other)
480{
481 d_ptr = other.d_ptr;
482 d_ptr->ref.ref();
483}
484
485/*!
486 Disposes of the object and frees any resources that were being held.
487*/
488QDBusMessage::~QDBusMessage()
489{
490 if (!d_ptr->ref.deref())
491 delete d_ptr;
492}
493
494/*!
495 Copies the contents of the object given by \a other.
496
497 Note: QDBusMessage objects are shared. Modifications made to the
498 copy will affect the original one as well. See setDelayedReply()
499 for more information.
500*/
501QDBusMessage &QDBusMessage::operator=(const QDBusMessage &other)
502{
503 qAtomicAssign(d_ptr, other.d_ptr);
504 return *this;
505}
506
507/*!
508 Returns the name of the service or the bus address of the remote method call.
509*/
510QString QDBusMessage::service() const
511{
512 return d_ptr->service;
513}
514
515/*!
516 Returns the path of the object that this message is being sent to (in the case of a
517 method call) or being received from (for a signal).
518*/
519QString QDBusMessage::path() const
520{
521 return d_ptr->path;
522}
523
524/*!
525 Returns the interface of the method being called (in the case of a method call) or of
526 the signal being received from.
527*/
528QString QDBusMessage::interface() const
529{
530 return d_ptr->interface;
531}
532
533/*!
534 Returns the name of the signal that was emitted or the name of the method that was called.
535*/
536QString QDBusMessage::member() const
537{
538 if (d_ptr->type != ErrorMessage)
539 return d_ptr->name;
540 return QString();
541}
542
543/*!
544 Returns the name of the error that was received.
545*/
546QString QDBusMessage::errorName() const
547{
548 if (d_ptr->type == ErrorMessage)
549 return d_ptr->name;
550 return QString();
551}
552
553/*!
554 Returns the signature of the signal that was received or for the output arguments
555 of a method call.
556*/
557QString QDBusMessage::signature() const
558{
559 return d_ptr->signature;
560}
561
562/*!
563 Returns the flag that indicates if this message should see a reply
564 or not. This is only meaningful for \l {MethodCallMessage}{method
565 call messages}: any other kind of message cannot have replies and
566 this function will always return false for them.
567*/
568bool QDBusMessage::isReplyRequired() const
569{
570 if (!d_ptr->msg)
571 return d_ptr->localMessage; // if it's a local message, reply is required
572 return !q_dbus_message_get_no_reply(d_ptr->msg);
573}
574
575/*!
576 Sets whether the message will be replied later (if \a enable is
577 true) or if an automatic reply should be generated by QtDBus
578 (if \a enable is false).
579
580 In D-Bus, all method calls must generate a reply to the caller, unless the
581 caller explicitly indicates otherwise (see isReplyRequired()). QtDBus
582 automatically generates such replies for any slots being called, but it
583 also allows slots to indicate whether they will take responsibility
584 of sending the reply at a later time, after the function has finished
585 processing.
586
587 \sa {Delayed Replies}
588*/
589void QDBusMessage::setDelayedReply(bool enable) const
590{
591 d_ptr->delayedReply = enable;
592}
593
594/*!
595 Returns the delayed reply flag, as set by setDelayedReply(). By default, this
596 flag is false, which means QtDBus will generate automatic replies
597 when necessary.
598*/
599bool QDBusMessage::isDelayedReply() const
600{
601 return d_ptr->delayedReply;
602}
603
604/*!
605 Sets the arguments that are going to be sent over D-Bus to \a arguments. Those
606 will be the arguments to a method call or the parameters in the signal.
607
608 \sa arguments()
609*/
610void QDBusMessage::setArguments(const QList<QVariant> &arguments)
611{
612 // FIXME: should we detach?
613 d_ptr->arguments = arguments;
614}
615
616/*!
617 Returns the list of arguments that are going to be sent or were received from
618 D-Bus.
619*/
620QList<QVariant> QDBusMessage::arguments() const
621{
622 return d_ptr->arguments;
623}
624
625/*!
626 Appends the argument \a arg to the list of arguments to be sent over D-Bus in
627 a method call or signal emission.
628*/
629
630QDBusMessage &QDBusMessage::operator<<(const QVariant &arg)
631{
632 // FIXME: should we detach?
633 d_ptr->arguments.append(arg);
634 return *this;
635}
636
637/*!
638 Returns the message type.
639*/
640QDBusMessage::MessageType QDBusMessage::type() const
641{
642 switch (d_ptr->type) {
643 case DBUS_MESSAGE_TYPE_METHOD_CALL:
644 return MethodCallMessage;
645 case DBUS_MESSAGE_TYPE_METHOD_RETURN:
646 return ReplyMessage;
647 case DBUS_MESSAGE_TYPE_ERROR:
648 return ErrorMessage;
649 case DBUS_MESSAGE_TYPE_SIGNAL:
650 return SignalMessage;
651 default:
652 break;
653 }
654 return InvalidMessage;
655}
656
657/*!
658 Sends the message without waiting for a reply. This is suitable
659 for errors, signals, and return values as well as calls whose
660 return values are not necessary.
661
662 Returns true if the message was queued successfully;
663 otherwise returns false.
664
665 \sa QDBusConnection::send()
666*/
667#ifndef QT_NO_DEBUG_STREAM
668QDebug operator<<(QDebug dbg, QDBusMessage::MessageType t)
669{
670 switch (t)
671 {
672 case QDBusMessage::MethodCallMessage:
673 return dbg << "MethodCall";
674 case QDBusMessage::ReplyMessage:
675 return dbg << "MethodReturn";
676 case QDBusMessage::SignalMessage:
677 return dbg << "Signal";
678 case QDBusMessage::ErrorMessage:
679 return dbg << "Error";
680 default:
681 return dbg << "Invalid";
682 }
683}
684
685static void debugVariantList(QDebug dbg, const QVariantList &list)
686{
687 bool first = true;
688 QVariantList::ConstIterator it = list.constBegin();
689 QVariantList::ConstIterator end = list.constEnd();
690 for ( ; it != end; ++it) {
691 if (!first)
692 dbg.nospace() << ", ";
693 dbg.nospace() << qPrintable(QDBusUtil::argumentToString(*it));
694 first = false;
695 }
696}
697
698QDebug operator<<(QDebug dbg, const QDBusMessage &msg)
699{
700 dbg.nospace() << "QDBusMessage(type=" << msg.type()
701 << ", service=" << msg.service();
702 if (msg.type() == QDBusMessage::MethodCallMessage ||
703 msg.type() == QDBusMessage::SignalMessage)
704 dbg.nospace() << ", path=" << msg.path()
705 << ", interface=" << msg.interface()
706 << ", member=" << msg.member();
707 if (msg.type() == QDBusMessage::ErrorMessage)
708 dbg.nospace() << ", error name=" << msg.errorName()
709 << ", error message=" << msg.errorMessage();
710 dbg.nospace() << ", signature=" << msg.signature()
711 << ", contents=(";
712 debugVariantList(dbg, msg.arguments());
713 dbg.nospace() << ") )";
714 return dbg.space();
715}
716#endif
717
718QT_END_NAMESPACE
719
Note: See TracBrowser for help on using the repository browser.