Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qdbusmisc.cpp
Go to the documentation of this file.
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 <string.h>
6
7#ifndef QT_BOOTSTRAPPED
8#include <QtCore/qcoreapplication.h>
9#include <QtCore/qlist.h>
10#include <QtCore/qmetaobject.h>
11#include <QtCore/qvariant.h>
12#include <private/qurl_p.h>
13
14#include "qdbusutil_p.h"
16#include "qdbusabstractadaptor_p.h" // for QCLASSINFO_DBUS_*
17#endif
19
20#ifndef QT_NO_DBUS
21
23
24using namespace Qt::StringLiterals;
25
26bool qDBusCheckAsyncTag(const char *tag)
27{
28 static const char noReplyTag[] = "Q_NOREPLY";
29 if (!tag || !*tag)
30 return false;
31
32 const char *p = strstr(tag, noReplyTag);
33 if (p != nullptr &&
34 (p == tag || *(p-1) == ' ') &&
35 (p[sizeof noReplyTag - 1] == '\0' || p[sizeof noReplyTag - 1] == ' '))
36 return true;
37
38 return false;
39}
40
41#ifndef QT_BOOTSTRAPPED
42
44{
45 QString interface;
46
47 int idx = mo->indexOfClassInfo(QCLASSINFO_DBUS_INTERFACE);
48 if (idx >= mo->classInfoOffset()) {
49 interface = QLatin1StringView(mo->classInfo(idx).value());
50 } else {
51 interface = QLatin1StringView(mo->className());
52 interface.replace("::"_L1, "."_L1);
53
54 if (interface.startsWith("QDBus"_L1)) {
55 interface.prepend("org.qtproject.QtDBus."_L1);
56 } else if (interface.startsWith(u'Q') &&
57 interface.size() >= 2 && interface.at(1).isUpper()) {
58 // assume it's Qt
59 interface.prepend("org.qtproject.Qt."_L1);
60 } else if (!QCoreApplication::instance()||
61 QCoreApplication::instance()->applicationName().isEmpty()) {
62 interface.prepend("local."_L1);
63 } else {
64 QString domainName = QCoreApplication::instance()->applicationName();
65 const QString organizationDomain = QCoreApplication::instance()->organizationDomain();
66 if (organizationDomain.isEmpty())
67 domainName.append(".local"_L1);
68 else
69 domainName.append(u'.').append(organizationDomain);
70
71 // Domain names used to produce interface names should be IDN-encoded.
72 QString encodedDomainName = qt_ACE_do(domainName, ToAceOnly, ForbidLeadingDot);
73 if (encodedDomainName.isEmpty()) {
74 interface.prepend("local."_L1);
75 return interface;
76 }
77
78 // Hyphens are not allowed in interface names and should be replaced
79 // by underscores.
80 encodedDomainName.replace(u'-', u'_');
81
82 auto nameParts = QStringView{ encodedDomainName }.split(u'.', Qt::SkipEmptyParts);
83
84 QString composedDomain;
85 // + 1 for additional dot, e.g. domainName equals "App.example.com",
86 // then composedDomain will be equal "com.example.App."
87 composedDomain.reserve(encodedDomainName.size() + nameParts.size() + 1);
88 for (auto it = nameParts.rbegin(), end = nameParts.rend(); it != end; ++it) {
89 // An interface name cannot start with a digit, and cannot
90 // contain digits immediately following a period. Prefix such
91 // digits with underscores.
92 if (it->first().isDigit())
93 composedDomain += u'_';
94 composedDomain += *it + u'.';
95 }
96
97 interface.prepend(composedDomain);
98 }
99 }
100
101 return interface;
102}
103
104bool qDBusInterfaceInObject(QObject *obj, const QString &interface_name)
105{
106 const QMetaObject *mo = obj->metaObject();
107 for ( ; mo != &QObject::staticMetaObject; mo = mo->superClass())
108 if (interface_name == qDBusInterfaceFromMetaObject(mo))
109 return true;
110 return false;
111}
112
113// calculates the metatypes for the method
114// the slot must have the parameters in the following form:
115// - zero or more value or const-ref parameters of any kind
116// - zero or one const ref of QDBusMessage
117// - zero or more non-const ref parameters
118// No parameter may be a template.
119// this function returns -1 if the parameters don't match the above form
120// this function returns the number of *input* parameters, including the QDBusMessage one if any
121// this function does not check the return type, so metaTypes[0] is always 0 and always present
122// metaTypes.count() >= retval + 1 in all cases
123//
124// sig must be the normalised signature for the method
125int qDBusParametersForMethod(const QMetaMethod &mm, QList<QMetaType> &metaTypes, QString &errorMsg)
126{
127 QList<QByteArray> parameterTypes;
128 parameterTypes.reserve(mm.parameterCount());
129
130 // Not using QMetaMethod::parameterTypes() since we call QMetaType::fromName below
131 // where we need any typedefs resolved already.
132 for (int i = 0; i < mm.parameterCount(); ++i) {
133 QByteArray typeName = mm.parameterMetaType(i).name();
134 if (typeName.isEmpty())
135 typeName = mm.parameterTypeName(i);
136 parameterTypes.append(typeName);
137 }
138
139 return qDBusParametersForMethod(parameterTypes, metaTypes, errorMsg);
140}
141
142#endif // QT_BOOTSTRAPPED
143
144int qDBusParametersForMethod(const QList<QByteArray> &parameterTypes, QList<QMetaType> &metaTypes,
145 QString &errorMsg)
146{
148 metaTypes.clear();
149
150 metaTypes.append(QMetaType()); // return type
151 int inputCount = 0;
152 bool seenMessage = false;
153 for (QByteArray type : parameterTypes) {
154 if (type.endsWith('*')) {
155 errorMsg = "Pointers are not supported: "_L1 + QLatin1StringView(type);
156 return -1;
157 }
158
159 if (type.endsWith('&')) {
160 QByteArray basictype = type;
161 basictype.truncate(type.size() - 1);
162
163 QMetaType id = QMetaType::fromName(basictype);
164 if (!id.isValid()) {
165 errorMsg = "Unregistered output type in parameter list: "_L1 + QLatin1StringView(type);
166 return -1;
167 } else if (QDBusMetaType::typeToSignature(id) == nullptr)
168 return -1;
169
170 metaTypes.append(id);
171 seenMessage = true; // it cannot appear anymore anyways
172 continue;
173 }
174
175 if (seenMessage) { // && !type.endsWith('&')
176 errorMsg = "Invalid method, non-output parameters after message or after output parameters: "_L1 + QLatin1StringView(type);
177 return -1; // not allowed
178 }
179
180 if (type.startsWith("QVector<"))
181 type = "QList<" + type.mid(sizeof("QVector<") - 1);
182
183 QMetaType id = QMetaType::fromName(type);
184#ifdef QT_BOOTSTRAPPED
185 // in bootstrap mode QDBusMessage isn't included, thus we need to resolve it manually here
186 if (type == "QDBusMessage") {
187 id = QDBusMetaTypeId::message();
188 }
189#endif
190
191 if (!id.isValid()) {
192 errorMsg = "Unregistered input type in parameter list: "_L1 + QLatin1StringView(type);
193 return -1;
194 }
195
196 if (id == QDBusMetaTypeId::message())
197 seenMessage = true;
198 else if (QDBusMetaType::typeToSignature(id) == nullptr) {
199 errorMsg = "Type not registered with QtDBus in parameter list: "_L1 + QLatin1StringView(type);
200 return -1;
201 }
202
203 metaTypes.append(id);
204 ++inputCount;
205 }
206
207 return inputCount;
208}
209
210QT_END_NAMESPACE
211
212#endif // QT_NO_DBUS
Q_DBUS_EXPORT void init()
#define QCLASSINFO_DBUS_INTERFACE
bool qDBusInterfaceInObject(QObject *obj, const QString &interface_name)
Q_DBUS_EXPORT int qDBusParametersForMethod(const QList< QByteArray > &parameters, QList< QMetaType > &metaTypes, QString &errorMsg)
QString qDBusInterfaceFromMetaObject(const QMetaObject *mo)
Definition qdbusmisc.cpp:43
Q_DBUS_EXPORT bool qDBusCheckAsyncTag(const char *tag)
Definition qdbusmisc.cpp:26
int qDBusParametersForMethod(const QMetaMethod &mm, QList< QMetaType > &metaTypes, QString &errorMsg)