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