* dbus/dbus-sysdeps.c: Make tcp socket connection error somewhat more
[platform/upstream/dbus.git] / qt / qdbusinternalfilters.cpp
1 /* -*- mode: C++ -*-
2  *
3  * Copyright (C) 2006 Trolltech AS. All rights reserved.
4  *    Author: Thiago Macieira <thiago.macieira@trolltech.com>
5  *
6  * Licensed under the Academic Free License version 2.1
7  *
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.
12  *
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.
17  *
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.
21  *
22  */
23
24 #include "qdbusconnection_p.h"
25
26 #include <dbus/dbus.h>
27 #include <QtCore/qcoreapplication.h>
28 #include <QtCore/qmetaobject.h>
29 #include <QtCore/qstringlist.h>
30
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"
37
38 // defined in qdbusxmlgenerator.cpp
39 extern QString qDBusGenerateMetaObjectXml(QString interface, const QMetaObject *mo,
40                                           const QMetaObject *base, int flags);
41
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"
46     "    </method>\n"
47     "  </interface>\n";
48
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"
55     "    </method>\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"
60     "    </method>\n"
61     "  </interface>\n";
62
63 static QString generateSubObjectXml(QObject *object)
64 {
65     QString retval;
66     foreach (QObject *child, object->children()) {
67         QString name = child->objectName();
68         if (!name.isEmpty())
69             retval += QString(QLatin1String("  <node name=\"%1\"/>\n"))
70                       .arg(name);
71     }
72     return retval;
73 }
74
75 QString qDBusIntrospectObject(const QDBusConnectionPrivate::ObjectTreeNode *node)
76 {
77     // object may be null
78
79     QString xml_data(QLatin1String(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE));
80     xml_data += QLatin1String("<node>\n");
81
82     if (node->obj) {
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(),
87                                                   node->flags);
88         }
89
90         // does this object have adaptors?
91         QDBusAdaptorConnector *connector;
92         if (node->flags & QDBusConnection::ExportAdaptors &&
93             (connector = qDBusFindAdaptorConnector(node->obj))) {
94
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) {
99                 // add the interface:
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);
106
107                     QDBusAbstractAdaptorPrivate::saveIntrospectionXml(it->adaptor, ifaceXml);
108                 }
109
110                 xml_data += ifaceXml;
111             }
112         }
113
114         xml_data += QLatin1String( introspectableInterfaceXml );
115         xml_data += QLatin1String( propertiesInterfaceXml );
116     }
117
118     if (node->flags & QDBusConnection::ExportChildObjects) {
119         xml_data += generateSubObjectXml(node->obj);
120     } else {
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"))
125                             .arg(entry.name);
126         }
127     }
128
129     xml_data += QLatin1String("</node>\n");
130     return xml_data;
131 }
132
133 void qDBusIntrospectObject(const QDBusConnectionPrivate::ObjectTreeNode *node,
134                            const QDBusMessage &msg)
135 {
136     // now send it
137     QDBusMessage reply = QDBusMessage::methodReply(msg);
138     reply << qDBusIntrospectObject(node);
139     msg.connection().send(reply);
140 }
141
142 // implement the D-Bus interface org.freedesktop.DBus.Properties
143
144 static void sendPropertyError(const QDBusMessage &msg, const QString &interface_name)
145 {
146     QDBusMessage error = QDBusMessage::error(msg, QLatin1String(DBUS_ERROR_INVALID_ARGS),
147                                    QString::fromLatin1("Interface %1 was not found in object %2")
148                                    .arg(interface_name)
149                                    .arg(msg.path()));
150     msg.connection().send(error);
151 }
152
153 void qDBusPropertyGet(const QDBusConnectionPrivate::ObjectTreeNode *node, const QDBusMessage &msg)
154 {
155     Q_ASSERT(msg.count() == 2);
156     QString interface_name = msg.at(0).toString();
157     QByteArray property_name = msg.at(1).toString().toUtf8();
158
159     QDBusAdaptorConnector *connector;
160     QVariant value;
161     if (node->flags & QDBusConnection::ExportAdaptors &&
162         (connector = qDBusFindAdaptorConnector(node->obj))) {
163
164         // find the class that implements interface_name
165         QDBusAdaptorConnector::AdaptorMap::ConstIterator it;
166         it = qLowerBound(connector->adaptors.constBegin(), connector->adaptors.constEnd(),
167                          interface_name);
168         if (it != connector->adaptors.end() && it->interface == interface_name)
169             value = it->adaptor->property(property_name);
170     }
171
172     if (!value.isValid() && node->flags & QDBusConnection::ExportProperties) {
173         // try the object itself
174         int pidx = node->obj->metaObject()->indexOfProperty(property_name);
175         if (pidx != -1) {
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);
180         }
181     }
182
183     if (!value.isValid()) {
184         // the property was not found
185         sendPropertyError(msg, interface_name);
186         return;
187     }
188
189     QDBusMessage reply = QDBusMessage::methodReply(msg);
190     reply.setSignature(QLatin1String("v"));
191     reply << value;
192     msg.connection().send(reply);
193 }
194
195 void qDBusPropertySet(const QDBusConnectionPrivate::ObjectTreeNode *node, const QDBusMessage &msg)
196 {
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));
201
202     QDBusAdaptorConnector *connector;
203     if (node->flags & QDBusConnection::ExportAdaptors &&
204         (connector = qDBusFindAdaptorConnector(node->obj))) {
205
206         // find the class that implements interface_name
207         QDBusAdaptorConnector::AdaptorMap::ConstIterator it;
208         it = qLowerBound(connector->adaptors.constBegin(), connector->adaptors.constEnd(),
209                          interface_name);
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));
213                 return;
214             }
215     }
216
217     if (node->flags & QDBusConnection::ExportProperties) {
218         // try the object itself
219         int pidx = node->obj->metaObject()->indexOfProperty(property_name);
220         if (pidx != -1) {
221             QMetaProperty mp = node->obj->metaObject()->property(pidx);
222             if (mp.isScriptable() || (node->flags & QDBusConnection::ExportAllProperties) ==
223                 QDBusConnection::ExportAllProperties) {
224
225                 if (mp.write(node->obj, value)) {
226                     msg.connection().send(QDBusMessage::methodReply(msg));
227                     return;
228                 }
229             }
230         }
231     }
232
233     // the property was not found or not written to
234     sendPropertyError(msg, interface_name);
235 }