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 "qdbusreply.h"
43#include "qdbusmetatype.h"
44#include "qdbusmetatype_p.h"
45#include <QDebug>
46
47#ifndef QT_NO_DBUS
48
49QT_BEGIN_NAMESPACE
50
51/*!
52 \class QDBusReply
53 \inmodule QtDBus
54 \since 4.2
55
56 \brief The QDBusReply class stores the reply for a method call to a remote object.
57
58 A QDBusReply object is a subset of the QDBusMessage object that represents a method call's
59 reply. It contains only the first output argument or the error code and is used by
60 QDBusInterface-derived classes to allow returning the error code as the function's return
61 argument.
62
63 It can be used in the following manner:
64 \snippet doc/src/snippets/code/src_qdbus_qdbusreply.cpp 0
65
66 If the remote method call cannot fail, you can skip the error checking:
67 \snippet doc/src/snippets/code/src_qdbus_qdbusreply.cpp 1
68
69 However, if it does fail under those conditions, the value returned by QDBusReply::value() is
70 a default-constructed value. It may be indistinguishable from a valid return value.
71
72 QDBusReply objects are used for remote calls that have no output
73 arguments or return values (i.e., they have a "void" return
74 type). Use the isValid() function to test if the reply succeeded.
75
76 \sa QDBusMessage, QDBusInterface
77*/
78
79/*!
80 \fn QDBusReply::QDBusReply(const QDBusMessage &reply)
81 Automatically construct a QDBusReply object from the reply message \a reply, extracting the
82 first return value from it if it is a success reply.
83*/
84
85/*!
86 \fn QDBusReply::QDBusReply(const QDBusPendingReply<T> &reply)
87 Constructs a QDBusReply object from the pending reply message, \a reply.
88*/
89
90/*!
91 \fn QDBusReply::QDBusReply(const QDBusPendingCall &pcall)
92 Automatically construct a QDBusReply object from the asynchronous
93 pending call \a pcall. If the call isn't finished yet, QDBusReply
94 will call QDBusPendingCall::waitForFinished(), which is a blocking
95 operation.
96
97 If the return types patch, QDBusReply will extract the first
98 return argument from the reply.
99*/
100
101/*!
102 \fn QDBusReply::QDBusReply(const QDBusError &error)
103 Constructs an error reply from the D-Bus error code given by \a error.
104*/
105
106/*!
107 \fn QDBusReply::operator=(const QDBusReply &other)
108 Makes this object be a copy of the object \a other.
109*/
110
111/*!
112 \fn QDBusReply::operator=(const QDBusError &error)
113 Sets this object to contain the error code given by \a error. You
114 can later access it with error().
115*/
116
117/*!
118 \fn QDBusReply::operator=(const QDBusMessage &message)
119
120 Makes this object contain the reply specified by message \a
121 message. If \a message is an error message, this function will
122 copy the error code and message into this object
123
124 If \a message is a standard reply message and contains at least
125 one parameter, it will be copied into this object, as long as it
126 is of the correct type. If it's not of the same type as this
127 QDBusError object, this function will instead set an error code
128 indicating a type mismatch.
129*/
130
131/*!
132 \fn QDBusReply::operator=(const QDBusPendingCall &pcall)
133
134 Makes this object contain the reply specified by the pending
135 asynchronous call \a pcall. If the call is not finished yet, this
136 function will call QDBusPendingCall::waitForFinished() to block
137 until the reply arrives.
138
139 If \a pcall finishes with an error message, this function will
140 copy the error code and message into this object
141
142 If \a pcall finished with a standard reply message and contains at
143 least one parameter, it will be copied into this object, as long
144 as it is of the correct type. If it's not of the same type as this
145 QDBusError object, this function will instead set an error code
146 indicating a type mismatch.
147*/
148
149/*!
150 \fn bool QDBusReply::isValid() const
151
152 Returns true if no error occurred; otherwise, returns false.
153
154 \sa error()
155*/
156
157/*!
158 \fn QDBusReply::error()
159
160 Returns the error code that was returned from the remote function call. If the remote call did
161 not return an error (i.e., if it succeeded), then the QDBusError object that is returned will
162 not be a valid error code (QDBusError::isValid() will return false).
163
164 \sa isValid()
165*/
166
167/*!
168 \fn QDBusReply::value() const
169 Returns the remote function's calls return value. If the remote call returned with an error,
170 the return value of this function is undefined and may be undistinguishable from a valid return
171 value.
172
173 This function is not available if the remote call returns \c void.
174*/
175
176/*!
177 \fn QDBusReply::operator Type() const
178 Returns the same as value().
179
180 This function is not available if the remote call returns \c void.
181*/
182
183/*!
184 \internal
185 Fills in the QDBusReply data \a error and \a data from the reply message \a reply.
186*/
187void qDBusReplyFill(const QDBusMessage &reply, QDBusError &error, QVariant &data)
188{
189 error = reply;
190
191 if (error.isValid()) {
192 data = QVariant(); // clear it
193 return;
194 }
195
196 if (reply.arguments().count() >= 1 && reply.arguments().at(0).userType() == data.userType()) {
197 data = reply.arguments().at(0);
198 return;
199 }
200
201 const char *expectedSignature = QDBusMetaType::typeToSignature(data.userType());
202 const char *receivedType = 0;
203 QByteArray receivedSignature;
204
205 if (reply.arguments().count() >= 1) {
206 if (reply.arguments().at(0).userType() == QDBusMetaTypeId::argument) {
207 // compare signatures instead
208 QDBusArgument arg = qvariant_cast<QDBusArgument>(reply.arguments().at(0));
209 receivedSignature = arg.currentSignature().toLatin1();
210 if (receivedSignature == expectedSignature) {
211 // matched. Demarshall it
212 QDBusMetaType::demarshall(arg, data.userType(), data.data());
213 return;
214 }
215 } else {
216 // not an argument and doesn't match?
217 int type = reply.arguments().at(0).userType();
218 receivedType = QVariant::typeToName(QVariant::Type(type));
219 receivedSignature = QDBusMetaType::typeToSignature(type);
220 }
221 }
222
223 // error
224 if (receivedSignature.isEmpty())
225 receivedSignature = "no signature";
226 QString errorMsg;
227 if (receivedType) {
228 errorMsg = QString::fromLatin1("Unexpected reply signature: got \"%1\" (%4), "
229 "expected \"%2\" (%3)")
230 .arg(QLatin1String(receivedSignature),
231 QLatin1String(expectedSignature),
232 QLatin1String(data.typeName()),
233 QLatin1String(receivedType));
234 } else {
235 errorMsg = QString::fromLatin1("Unexpected reply signature: got \"%1\", "
236 "expected \"%2\" (%3)")
237 .arg(QLatin1String(receivedSignature),
238 QLatin1String(expectedSignature),
239 QLatin1String(data.typeName()));
240 }
241
242 error = QDBusError(QDBusError::InvalidSignature, errorMsg);
243 data = QVariant(); // clear it
244}
245
246QT_END_NAMESPACE
247
248#endif // QT_NO_DBUS
249