1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#include "qdbusreply.h"
6#include "qdbusmetatype.h"
7#include "qdbusmetatype_p.h"
8#include <QDebug>
9
10#ifndef QT_NO_DBUS
11
12QT_BEGIN_NAMESPACE
13
14using namespace Qt::StringLiterals;
15
16/*!
17 \class QDBusReply
18 \inmodule QtDBus
19 \since 4.2
20
21 \brief The QDBusReply class stores the reply for a method call to a remote object.
22
23 A QDBusReply object is a subset of the QDBusMessage object that represents a method call's
24 reply. It contains only the first output argument or the error code and is used by
25 QDBusInterface-derived classes to allow returning the error code as the function's return
26 argument.
27
28 It can be used in the following manner:
29 \snippet code/src_qdbus_qdbusreply.cpp 0
30
31 If the remote method call cannot fail, you can skip the error checking:
32 \snippet code/src_qdbus_qdbusreply.cpp 1
33
34 However, if it does fail under those conditions, the value returned by QDBusReply<T>::value() is
35 a default-constructed value. It may be indistinguishable from a valid return value.
36
37 QDBusReply objects are used for remote calls that have no output
38 arguments or return values (i.e., they have a "void" return
39 type). Use the isValid() function to test if the reply succeeded.
40
41 \sa QDBusMessage, QDBusInterface
42*/
43
44/*!
45 \fn template<typename T> QDBusReply<T>::QDBusReply(const QDBusReply &other)
46 \since 5.15
47
48 Constructs a copy of \a other.
49*/
50
51/*!
52 \fn template<typename T> QDBusReply<T>::QDBusReply(const QDBusMessage &reply)
53 Automatically construct a QDBusReply object from the reply message \a reply, extracting the
54 first return value from it if it is a success reply.
55*/
56
57/*!
58 \fn template<typename T> QDBusReply<T>::QDBusReply(const QDBusPendingReply<T> &reply)
59 Constructs a QDBusReply object from the pending reply message, \a reply.
60*/
61
62/*!
63 \fn template <typename T> QDBusReply<T>::QDBusReply(const QDBusPendingCall &pcall)
64 Automatically construct a QDBusReply object from the asynchronous
65 pending call \a pcall. If the call isn't finished yet, QDBusReply
66 will call QDBusPendingCall::waitForFinished(), which is a blocking
67 operation.
68
69 If the return types patch, QDBusReply will extract the first
70 return argument from the reply.
71*/
72
73/*!
74 \fn template <typename T> QDBusReply<T>::QDBusReply(const QDBusError &error)
75 Constructs an error reply from the D-Bus error code given by \a error.
76*/
77
78/*!
79 \fn template <typename T> QDBusReply<T>::operator=(const QDBusReply &other)
80 Makes this object be a copy of the object \a other.
81*/
82
83/*!
84 \fn template <typename T> QDBusReply<T>::operator=(const QDBusError &dbusError)
85 Sets this object to contain the error code given by \a dbusError. You
86 can later access it with error().
87*/
88
89/*!
90 \fn template <typename T> QDBusReply<T>::operator=(const QDBusMessage &reply)
91
92 Makes this object contain the \a reply message. If \a reply
93 is an error message, this function will
94 copy the error code and message into this object
95
96 If \a reply is a standard reply message and contains at least
97 one parameter, it will be copied into this object, as long as it
98 is of the correct type. If it's not of the same type as this
99 QDBusError object, this function will instead set an error code
100 indicating a type mismatch.
101*/
102
103/*!
104 \fn template <typename T> QDBusReply<T>::operator=(const QDBusPendingCall &pcall)
105
106 Makes this object contain the reply specified by the pending
107 asynchronous call \a pcall. If the call is not finished yet, this
108 function will call QDBusPendingCall::waitForFinished() to block
109 until the reply arrives.
110
111 If \a pcall finishes with an error message, this function will
112 copy the error code and message into this object
113
114 If \a pcall finished with a standard reply message and contains at
115 least one parameter, it will be copied into this object, as long
116 as it is of the correct type. If it's not of the same type as this
117 QDBusError object, this function will instead set an error code
118 indicating a type mismatch.
119*/
120
121/*!
122 \fn template <typename T> bool QDBusReply<T>::isValid() const
123
124 Returns \c true if no error occurred; otherwise, returns \c false.
125
126 \sa error()
127*/
128
129/*!
130 \fn template<typename T> const QDBusError& QDBusReply<T>::error() const
131
132 Returns the error code that was returned from the remote function call. If the remote call did
133 not return an error (i.e., if it succeeded), then the QDBusError object that is returned will
134 not be a valid error code (QDBusError::isValid() will return false).
135
136 \sa isValid()
137*/
138
139/*!
140 \fn template <typename T> const QDBusError& QDBusReply<T>::error()
141 \overload
142*/
143
144/*!
145 \fn template <typename T> Type QDBusReply<T>::value() const
146 Returns the remote function's calls return value. If the remote call returned with an error,
147 the return value of this function is undefined and may be undistinguishable from a valid return
148 value.
149
150 This function is not available if the remote call returns \c void.
151*/
152
153/*!
154 \fn template <typename T> QDBusReply<T>::operator Type() const
155 Returns the same as value().
156
157 This function is not available if the remote call returns \c void.
158*/
159
160/*!
161 \internal
162 Fills in the QDBusReply data \a error and \a data from the reply message \a reply.
163*/
164void qDBusReplyFill(const QDBusMessage &reply, QDBusError &error, QVariant &data)
165{
166 error = QDBusError(reply);
167
168 if (error.isValid()) {
169 data = QVariant(); // clear it
170 return;
171 }
172
173 if (reply.arguments().size() >= 1 && reply.arguments().at(i: 0).metaType() == data.metaType()) {
174 data = reply.arguments().at(i: 0);
175 return;
176 }
177
178 const char *expectedSignature = QDBusMetaType::typeToSignature(type: data.metaType());
179 const char *receivedType = nullptr;
180 QByteArray receivedSignature;
181
182 if (reply.arguments().size() >= 1) {
183 if (reply.arguments().at(i: 0).metaType() == QDBusMetaTypeId::argument()) {
184 // compare signatures instead
185 QDBusArgument arg = qvariant_cast<QDBusArgument>(v: reply.arguments().at(i: 0));
186 receivedSignature = arg.currentSignature().toLatin1();
187 if (receivedSignature == expectedSignature) {
188 // matched. Demarshall it
189 QDBusMetaType::demarshall(arg, id: data.metaType(), data: data.data());
190 return;
191 }
192 } else {
193 // not an argument and doesn't match?
194 QMetaType type = reply.arguments().at(i: 0).metaType();
195 receivedType = type.name();
196 receivedSignature = QDBusMetaType::typeToSignature(type);
197 }
198 }
199
200 // error
201 if (receivedSignature.isEmpty())
202 receivedSignature = "<empty signature>";
203 QString errorMsg;
204 if (receivedType) {
205 errorMsg = "Unexpected reply signature: got \"%1\" (%4), expected \"%2\" (%3)"_L1
206 .arg(args: QLatin1StringView(receivedSignature),
207 args: QLatin1StringView(expectedSignature),
208 args: QLatin1StringView(data.typeName()),
209 args: QLatin1StringView(receivedType));
210 } else {
211 errorMsg = "Unexpected reply signature: got \"%1\", expected \"%2\" (%3)"_L1
212 .arg(args: QLatin1StringView(receivedSignature),
213 args: QLatin1StringView(expectedSignature),
214 args: QLatin1StringView(data.typeName()));
215 }
216
217 error = QDBusError(QDBusError::InvalidSignature, errorMsg);
218 data = QVariant(); // clear it
219}
220
221QT_END_NAMESPACE
222
223#endif // QT_NO_DBUS
224

source code of qtbase/src/dbus/qdbusreply.cpp