3 * Copyright (C) 2006 Trolltech AS. All rights reserved.
4 * Author: Thiago Macieira <thiago.macieira@trolltech.com>
6 * Licensed under the Academic Free License version 2.1
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software Foundation
20 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 #include "qdbusconnection_p.h"
26 #include <dbus/dbus.h>
27 #include <QtCore/qcoreapplication.h>
28 #include <QtCore/qmetaobject.h>
29 #include <QtCore/qstringlist.h>
31 #include "qdbusabstractadaptor.h"
32 #include "qdbusabstractadaptor_p.h"
33 #include "qdbusconnection.h"
34 #include "qdbusmessage.h"
35 #include "qdbustypehelper_p.h"
36 #include "qdbusutil.h"
38 // defined in qdbusxmlgenerator.cpp
39 extern QString qDBusGenerateMetaObjectXml(QString interface, const QMetaObject *mo,
40 const QMetaObject *base, int flags);
42 static const char introspectableInterfaceXml[] =
43 " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
44 " <method name=\"Introspect\">\n"
45 " <arg name=\"xml_data\" type=\"s\" direction=\"out\"/>\n"
49 static const char propertiesInterfaceXml[] =
50 " <interface name=\"org.freedesktop.DBus.Properties\">\n"
51 " <method name=\"Get\">\n"
52 " <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n"
53 " <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n"
54 " <arg name=\"value\" type=\"v\" direction=\"out\"/>\n"
56 " <method name=\"Set\">\n"
57 " <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n"
58 " <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n"
59 " <arg name=\"value\" type=\"v\" direction=\"in\"/>\n"
63 static QString generateSubObjectXml(QObject *object)
66 foreach (QObject *child, object->children()) {
67 QString name = child->objectName();
69 retval += QString(QLatin1String(" <node name=\"%1\"/>\n"))
75 QString qDBusIntrospectObject(const QDBusConnectionPrivate::ObjectTreeNode *node)
79 QString xml_data(QLatin1String(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE));
80 xml_data += QLatin1String("<node>\n");
83 if (node->flags & QDBusConnection::ExportContents) {
84 const QMetaObject *mo = node->obj->metaObject();
85 for ( ; mo != &QObject::staticMetaObject; mo = mo->superClass())
86 xml_data += qDBusGenerateMetaObjectXml(QString(), mo, mo->superClass(),
90 // does this object have adaptors?
91 QDBusAdaptorConnector *connector;
92 if (node->flags & QDBusConnection::ExportAdaptors &&
93 (connector = qDBusFindAdaptorConnector(node->obj))) {
95 // trasverse every adaptor in this object
96 QDBusAdaptorConnector::AdaptorMap::ConstIterator it = connector->adaptors.constBegin();
97 QDBusAdaptorConnector::AdaptorMap::ConstIterator end = connector->adaptors.constEnd();
98 for ( ; it != end; ++it) {
100 QString ifaceXml = QDBusAbstractAdaptorPrivate::retrieveIntrospectionXml(it->adaptor);
101 if (ifaceXml.isEmpty()) {
102 // add the interface's contents:
103 ifaceXml += qDBusGenerateMetaObjectXml(it->interface, it->metaObject,
104 &QDBusAbstractAdaptor::staticMetaObject,
105 QDBusConnection::ExportAllContents);
107 QDBusAbstractAdaptorPrivate::saveIntrospectionXml(it->adaptor, ifaceXml);
110 xml_data += ifaceXml;
114 xml_data += QLatin1String( introspectableInterfaceXml );
115 xml_data += QLatin1String( propertiesInterfaceXml );
118 if (node->flags & QDBusConnection::ExportChildObjects) {
119 xml_data += generateSubObjectXml(node->obj);
121 // generate from the object tree
122 foreach (const QDBusConnectionPrivate::ObjectTreeNode::Data &entry, node->children) {
123 if (entry.node && (entry.node->obj || !entry.node->children.isEmpty()))
124 xml_data += QString(QLatin1String(" <node name=\"%1\"/>\n"))
129 xml_data += QLatin1String("</node>\n");
133 void qDBusIntrospectObject(const QDBusConnectionPrivate::ObjectTreeNode *node,
134 const QDBusMessage &msg)
137 QDBusMessage reply = QDBusMessage::methodReply(msg);
138 reply << qDBusIntrospectObject(node);
139 msg.connection().send(reply);
142 // implement the D-Bus interface org.freedesktop.DBus.Properties
144 static void sendPropertyError(const QDBusMessage &msg, const QString &interface_name)
146 QDBusMessage error = QDBusMessage::error(msg, QLatin1String(DBUS_ERROR_INVALID_ARGS),
147 QString::fromLatin1("Interface %1 was not found in object %2")
150 msg.connection().send(error);
153 void qDBusPropertyGet(const QDBusConnectionPrivate::ObjectTreeNode *node, const QDBusMessage &msg)
155 Q_ASSERT(msg.count() == 2);
156 QString interface_name = msg.at(0).toString();
157 QByteArray property_name = msg.at(1).toString().toUtf8();
159 QDBusAdaptorConnector *connector;
161 if (node->flags & QDBusConnection::ExportAdaptors &&
162 (connector = qDBusFindAdaptorConnector(node->obj))) {
164 // find the class that implements interface_name
165 QDBusAdaptorConnector::AdaptorMap::ConstIterator it;
166 it = qLowerBound(connector->adaptors.constBegin(), connector->adaptors.constEnd(),
168 if (it != connector->adaptors.end() && it->interface == interface_name)
169 value = it->adaptor->property(property_name);
172 if (!value.isValid() && node->flags & QDBusConnection::ExportProperties) {
173 // try the object itself
174 int pidx = node->obj->metaObject()->indexOfProperty(property_name);
176 QMetaProperty mp = node->obj->metaObject()->property(pidx);
177 if (mp.isScriptable() || (node->flags & QDBusConnection::ExportAllProperties) ==
178 QDBusConnection::ExportAllProperties)
179 value = mp.read(node->obj);
183 if (!value.isValid()) {
184 // the property was not found
185 sendPropertyError(msg, interface_name);
189 QDBusMessage reply = QDBusMessage::methodReply(msg);
190 reply.setSignature(QLatin1String("v"));
192 msg.connection().send(reply);
195 void qDBusPropertySet(const QDBusConnectionPrivate::ObjectTreeNode *node, const QDBusMessage &msg)
197 Q_ASSERT(msg.count() == 3);
198 QString interface_name = msg.at(0).toString();
199 QByteArray property_name = msg.at(1).toString().toUtf8();
200 QVariant value = QDBusTypeHelper<QVariant>::fromVariant(msg.at(2));
202 QDBusAdaptorConnector *connector;
203 if (node->flags & QDBusConnection::ExportAdaptors &&
204 (connector = qDBusFindAdaptorConnector(node->obj))) {
206 // find the class that implements interface_name
207 QDBusAdaptorConnector::AdaptorMap::ConstIterator it;
208 it = qLowerBound(connector->adaptors.constBegin(), connector->adaptors.constEnd(),
210 if (it != connector->adaptors.end() && it->interface == interface_name)
211 if (it->adaptor->setProperty(property_name, value)) {
212 msg.connection().send(QDBusMessage::methodReply(msg));
217 if (node->flags & QDBusConnection::ExportProperties) {
218 // try the object itself
219 int pidx = node->obj->metaObject()->indexOfProperty(property_name);
221 QMetaProperty mp = node->obj->metaObject()->property(pidx);
222 if (mp.isScriptable() || (node->flags & QDBusConnection::ExportAllProperties) ==
223 QDBusConnection::ExportAllProperties) {
225 if (mp.write(node->obj, value)) {
226 msg.connection().send(QDBusMessage::methodReply(msg));
233 // the property was not found or not written to
234 sendPropertyError(msg, interface_name);