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 "qdbusconnectioninterface.h"
41 
42 #include <QtCore/QByteArray>
43 #include <QtCore/QList>
44 #include <QtCore/QMap>
45 #include <QtCore/QMetaMethod>
46 #include <QtCore/QString>
47 #include <QtCore/QStringList>
48 #include <QtCore/QVariant>
49 #include <QtCore/QDebug>
50 
51 #include "qdbusutil_p.h"          // for the DBUS_* constants
52 
53 #ifndef QT_NO_DBUS
54 
55 QT_BEGIN_NAMESPACE
56 
57 /*
58  * Implementation of interface class QDBusConnectionInterface
59  */
60 
61 /*!
62     \class QDBusConnectionInterface
63     \inmodule QtDBus
64     \since 4.2
65 
66     \brief The QDBusConnectionInterface class provides access to the D-Bus bus daemon service.
67 
68     The D-Bus bus server daemon provides one special interface \c
69     org.freedesktop.DBus that allows clients to access certain
70     properties of the bus, such as the current list of clients
71     connected. The QDBusConnectionInterface class provides access to that
72     interface.
73 
74     The most common uses of this class are to register and unregister
75     service names on the bus using the registerService() and
76     unregisterService() functions, query about existing names using
77     the isServiceRegistered(), registeredServiceNames() and
78     serviceOwner() functions, and to receive notification that a
79     client has registered or de-registered through the
80     serviceRegistered(), serviceUnregistered() and serviceOwnerChanged()
81     signals.
82 */
83 
84 /*!
85     \enum QDBusConnectionInterface::ServiceQueueOptions
86 
87     Flags for determining how a service registration should behave, in
88     case the service name is already registered.
89 
90     \value DontQueueService     If an application requests a name that
91                                 is already owned, no queueing will be
92                                 performed. The registeredService()
93                                 call will simply fail.
94                                 This is the default.
95 
96     \value QueueService         Attempts to register the requested
97                                 service, but do not try to replace it
98                                 if another application already has it
99                                 registered. Instead, simply put this
100                                 application in queue, until it is
101                                 given up. The serviceRegistered()
102                                 signal will be emitted when that
103                                 happens.
104 
105     \value ReplaceExistingService If another application already has
106                                 the service name registered, attempt
107                                 to replace it.
108 
109     \sa ServiceReplacementOptions
110 */
111 
112 /*!
113     \enum QDBusConnectionInterface::ServiceReplacementOptions
114 
115     Flags for determining if the D-Bus server should allow another
116     application to replace a name that this application has registered
117     with the ReplaceExistingService option.
118 
119     The possible values are:
120 
121     \value DontAllowReplacement Do not allow another application to
122                                 replace us. The service must be
123                                 explicitly unregistered with
124                                 unregisterService() for another
125                                 application to acquire it.
126                                 This is the default.
127 
128     \value AllowReplacement     Allow other applications to replace us
129                                 with the ReplaceExistingService option
130                                 to registerService() without
131                                 intervention. If that happens, the
132                                 serviceUnregistered() signal will be
133                                 emitted.
134 
135     \sa ServiceQueueOptions
136 */
137 
138 /*!
139     \enum QDBusConnectionInterface::RegisterServiceReply
140 
141     The possible return values from registerService():
142 
143     \value ServiceNotRegistered The call failed and the service name was not registered.
144     \value ServiceRegistered    The caller is now the owner of the service name.
145     \value ServiceQueued        The caller specified the QueueService flag and the
146                                 service was already registered, so we are in queue.
147 
148     The serviceRegistered() signal will be emitted when the service is
149     acquired by this application.
150 */
151 
152 /*!
153     \internal
154 */
staticInterfaceName()155 const char *QDBusConnectionInterface::staticInterfaceName()
156 { return "org.freedesktop.DBus"; }
157 
158 /*!
159     \internal
160 */
QDBusConnectionInterface(const QDBusConnection & connection,QObject * parent)161 QDBusConnectionInterface::QDBusConnectionInterface(const QDBusConnection &connection,
162                                                    QObject *parent)
163     : QDBusAbstractInterface(QDBusUtil::dbusService(),
164                              QDBusUtil::dbusPath(),
165                              DBUS_INTERFACE_DBUS, connection, parent)
166 {
167     connect(this, &QDBusConnectionInterface::NameAcquired, this, emit &QDBusConnectionInterface::serviceRegistered);
168     connect(this, &QDBusConnectionInterface::NameLost, this, emit &QDBusConnectionInterface::serviceUnregistered);
169     connect(this, &QDBusConnectionInterface::NameOwnerChanged,
170             this, emit &QDBusConnectionInterface::serviceOwnerChanged);
171 }
172 
173 /*!
174     \internal
175 */
~QDBusConnectionInterface()176 QDBusConnectionInterface::~QDBusConnectionInterface()
177 {
178 }
179 
180 /*!
181     Returns the unique connection name of the primary owner of the
182     name \a name. If the requested name doesn't have an owner, returns
183     a \c org.freedesktop.DBus.Error.NameHasNoOwner error.
184 */
serviceOwner(const QString & name) const185 QDBusReply<QString> QDBusConnectionInterface::serviceOwner(const QString &name) const
186 {
187     return internalConstCall(QDBus::AutoDetect, QLatin1String("GetNameOwner"), QList<QVariant>() << name);
188 }
189 
190 /*!
191   \property QDBusConnectionInterface::registeredServiceNames
192   \brief holds the registered service names
193 
194   Lists all names currently registered on the bus.
195 */
registeredServiceNames() const196 QDBusReply<QStringList> QDBusConnectionInterface::registeredServiceNames() const
197 {
198     return internalConstCall(QDBus::AutoDetect, QLatin1String("ListNames"));
199 }
200 
201 /*!
202   \property QDBusConnectionInterface::activatableServiceNames
203   \brief holds the activatable service names
204   \since 5.14
205 
206   Lists all names that can be activated on the bus.
207 */
activatableServiceNames() const208 QDBusReply<QStringList> QDBusConnectionInterface::activatableServiceNames() const
209 {
210     return internalConstCall(QDBus::AutoDetect, QLatin1String("ListActivatableNames"));
211 }
212 
213 /*!
214     Returns \c true if the service name \a serviceName has is currently
215     registered.
216 */
isServiceRegistered(const QString & serviceName) const217 QDBusReply<bool> QDBusConnectionInterface::isServiceRegistered(const QString &serviceName) const
218 {
219     return internalConstCall(QDBus::AutoDetect, QLatin1String("NameHasOwner"),
220                              QList<QVariant>() << serviceName);
221 }
222 
223 /*!
224     Returns the Unix Process ID (PID) for the process currently
225     holding the bus service \a serviceName.
226 */
servicePid(const QString & serviceName) const227 QDBusReply<uint> QDBusConnectionInterface::servicePid(const QString &serviceName) const
228 {
229     return internalConstCall(QDBus::AutoDetect, QLatin1String("GetConnectionUnixProcessID"),
230                              QList<QVariant>() << serviceName);
231 }
232 
233 /*!
234     Returns the Unix User ID (UID) for the process currently holding
235     the bus service \a serviceName.
236 */
serviceUid(const QString & serviceName) const237 QDBusReply<uint> QDBusConnectionInterface::serviceUid(const QString &serviceName) const
238 {
239     return internalConstCall(QDBus::AutoDetect, QLatin1String("GetConnectionUnixUser"),
240                              QList<QVariant>() << serviceName);
241 }
242 
243 /*!
244     Requests that the bus start the service given by the name \a name.
245 */
startService(const QString & name)246 QDBusReply<void> QDBusConnectionInterface::startService(const QString &name)
247 {
248     return call(QLatin1String("StartServiceByName"), name, uint(0));
249 }
250 
251 /*!
252     Requests to register the service name \a serviceName on the
253     bus. The \a qoption flag specifies how the D-Bus server should behave
254     if \a serviceName is already registered. The \a roption flag
255     specifies if the server should allow another application to
256     replace our registered name.
257 
258     If the service registration succeeds, the serviceRegistered()
259     signal will be emitted. If we are placed in queue, the signal will
260     be emitted when we obtain the name. If \a roption is
261     AllowReplacement, the serviceUnregistered() signal will be emitted
262     if another application replaces this one.
263 
264     \sa unregisterService()
265 */
266 QDBusReply<QDBusConnectionInterface::RegisterServiceReply>
registerService(const QString & serviceName,ServiceQueueOptions qoption,ServiceReplacementOptions roption)267 QDBusConnectionInterface::registerService(const QString &serviceName,
268                                           ServiceQueueOptions qoption,
269                                           ServiceReplacementOptions roption)
270 {
271     // reconstruct the low-level flags
272     uint flags = 0;
273     switch (qoption) {
274     case DontQueueService:
275         flags = DBUS_NAME_FLAG_DO_NOT_QUEUE;
276         break;
277     case QueueService:
278         flags = 0;
279         break;
280     case ReplaceExistingService:
281         flags = DBUS_NAME_FLAG_DO_NOT_QUEUE | DBUS_NAME_FLAG_REPLACE_EXISTING;
282         break;
283     }
284 
285     switch (roption) {
286     case DontAllowReplacement:
287         break;
288     case AllowReplacement:
289         flags |= DBUS_NAME_FLAG_ALLOW_REPLACEMENT;
290         break;
291     }
292 
293     QDBusMessage reply = call(QLatin1String("RequestName"), serviceName, flags);
294 //    qDebug() << "QDBusConnectionInterface::registerService" << serviceName << "Reply:" << reply;
295 
296     // convert the low-level flags to something that we can use
297     if (reply.type() == QDBusMessage::ReplyMessage) {
298         uint code = 0;
299 
300         switch (reply.arguments().at(0).toUInt()) {
301         case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
302         case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
303             code = uint(ServiceRegistered);
304             break;
305 
306         case DBUS_REQUEST_NAME_REPLY_EXISTS:
307             code = uint(ServiceNotRegistered);
308             break;
309 
310         case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
311             code = uint(ServiceQueued);
312             break;
313         }
314 
315         reply.setArguments(QVariantList() << code);
316     }
317 
318     return reply;
319 }
320 
321 /*!
322     Releases the claim on the bus service name \a serviceName, that
323     had been previously registered with registerService(). If this
324     application had ownership of the name, it will be released for
325     other applications to claim. If it only had the name queued, it
326     gives up its position in the queue.
327 */
328 QDBusReply<bool>
unregisterService(const QString & serviceName)329 QDBusConnectionInterface::unregisterService(const QString &serviceName)
330 {
331     QDBusMessage reply = call(QLatin1String("ReleaseName"), serviceName);
332     if (reply.type() == QDBusMessage::ReplyMessage) {
333         bool success = reply.arguments().at(0).toUInt() == DBUS_RELEASE_NAME_REPLY_RELEASED;
334         reply.setArguments(QVariantList() << success);
335     }
336     return reply;
337 }
338 
339 /*!
340     \internal
341 */
connectNotify(const QMetaMethod & signal)342 void QDBusConnectionInterface::connectNotify(const QMetaMethod &signal)
343 {
344     // translate the signal names to what we really want
345     // this avoids setting hooks for signals that don't exist on the bus
346     static const QMetaMethod serviceRegisteredSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::serviceRegistered);
347     static const QMetaMethod serviceUnregisteredSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::serviceUnregistered);
348     static const QMetaMethod serviceOwnerChangedSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::serviceOwnerChanged);
349     static const QMetaMethod NameAcquiredSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::NameAcquired);
350     static const QMetaMethod NameLostSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::NameLost);
351     static const QMetaMethod NameOwnerChangedSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::NameOwnerChanged);
352     if (signal == serviceRegisteredSignal)
353         QDBusAbstractInterface::connectNotify(NameAcquiredSignal);
354 
355     else if (signal == serviceUnregisteredSignal)
356         QDBusAbstractInterface::connectNotify(NameLostSignal);
357 
358     else if (signal == serviceOwnerChangedSignal) {
359         static bool warningPrinted = false;
360         if (!warningPrinted) {
361             qWarning("Connecting to deprecated signal QDBusConnectionInterface::serviceOwnerChanged(QString,QString,QString)");
362             warningPrinted = true;
363         }
364         QDBusAbstractInterface::connectNotify(NameOwnerChangedSignal);
365     }
366 }
367 
368 /*!
369     \internal
370 */
disconnectNotify(const QMetaMethod & signal)371 void QDBusConnectionInterface::disconnectNotify(const QMetaMethod &signal)
372 {
373     // translate the signal names to what we really want
374     // this avoids setting hooks for signals that don't exist on the bus
375     static const QMetaMethod serviceRegisteredSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::serviceRegistered);
376     static const QMetaMethod serviceUnregisteredSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::serviceUnregistered);
377     static const QMetaMethod serviceOwnerChangedSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::serviceOwnerChanged);
378     static const QMetaMethod NameAcquiredSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::NameAcquired);
379     static const QMetaMethod NameLostSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::NameLost);
380     static const QMetaMethod NameOwnerChangedSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::NameOwnerChanged);
381     if (signal == serviceRegisteredSignal)
382         QDBusAbstractInterface::disconnectNotify(NameAcquiredSignal);
383 
384     else if (signal == serviceUnregisteredSignal)
385         QDBusAbstractInterface::disconnectNotify(NameLostSignal);
386 
387     else if (signal == serviceOwnerChangedSignal)
388         QDBusAbstractInterface::disconnectNotify(NameOwnerChangedSignal);
389 }
390 
391 // signals
392 /*!
393     \fn QDBusConnectionInterface::serviceRegistered(const QString &service)
394 
395     This signal is emitted by the D-Bus server when the bus service
396     name (unique connection name or well-known service name) given by
397     \a service is acquired by this application.
398 
399     Acquisition happens after this application has requested a name using
400     registerService().
401 */
402 
403 /*!
404     \fn QDBusConnectionInterface::serviceUnregistered(const QString &service)
405 
406     This signal is emitted by the D-Bus server when this application
407     loses ownership of the bus service name given by \a service.
408 */
409 
410 /*!
411     \fn QDBusConnectionInterface::serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner)
412     \deprecated
413 
414     Use QDBusServiceWatcher instead.
415 
416     This signal is emitted by the D-Bus server whenever a service
417     ownership change happens in the bus, including apparition and
418     disparition of names.
419 
420     This signal means the application \a oldOwner lost ownership of
421     bus name \a name to application \a newOwner. If \a oldOwner is an
422     empty string, it means the name \a name has just been created; if
423     \a newOwner is empty, the name \a name has no current owner and is
424     no longer available.
425 
426     \note connecting to this signal will make the application listen for and
427     receive every single service ownership change on the bus. Depending on
428     how many services are running, this make the application be activated to
429     receive more signals than it needs. To avoid this problem, use the
430     QDBusServiceWatcher class, which can listen for specific changes.
431 */
432 
433 /*!
434   \fn void QDBusConnectionInterface::callWithCallbackFailed(const QDBusError &error, const QDBusMessage &call)
435 
436   This signal is emitted when there is an error during a
437   QDBusConnection::callWithCallback(). \a error specifies the error.
438   \a call is the message that couldn't be delivered.
439 
440   \sa QDBusConnection::callWithCallback()
441  */
442 
443 QT_END_NAMESPACE
444 
445 #endif // QT_NO_DBUS
446