3 * Copyright (C) 2006 Trolltech AS. All rights reserved.
4 * Author: Thiago Macieira <thiago.macieira@trolltech.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 #include <dbus/qdbus.h>
26 #include <QtCore/QCoreApplication>
27 #include <QtCore/QStringList>
28 #include <QtCore/qmetaobject.h>
29 #include <QtXml/QDomDocument>
30 #include <QtXml/QDomElement>
32 Q_DECLARE_METATYPE(QVariant)
33 QDBusConnection *connection;
35 void listObjects(const QString &service, const QString &path)
37 QDBusInterfacePtr iface(*connection, service, path.isEmpty() ? "/" : path,
38 "org.freedesktop.DBus.Introspectable");
39 if (!iface->isValid()) {
40 QDBusError err(iface->lastError());
41 fprintf(stderr, "Cannot introspect object %s at %s:\n%s (%s)\n",
42 qPrintable(path.isEmpty() ? "/" : path), qPrintable(service),
43 qPrintable(err.name()), qPrintable(err.message()));
46 QDBusReply<QString> xml = iface->call("Introspect");
53 QDomElement node = doc.documentElement();
54 QDomElement child = node.firstChildElement();
55 while (!child.isNull()) {
56 if (child.tagName() == QLatin1String("node")) {
57 QString sub = path + '/' + child.attribute("name");
58 printf("%s\n", qPrintable(sub));
59 listObjects(service, sub);
61 child = child.nextSiblingElement();
65 void listInterface(const QString &service, const QString &path, const QString &interface)
67 QDBusInterfacePtr iface(*connection, service, path, interface);
68 if (!iface->isValid()) {
69 QDBusError err(iface->lastError());
70 fprintf(stderr, "Interface '%s' not available in object %s at %s:\n%s (%s)\n",
71 qPrintable(interface), qPrintable(path), qPrintable(service),
72 qPrintable(err.name()), qPrintable(err.message()));
75 const QMetaObject *mo = iface->metaObject();
78 for (int i = mo->propertyOffset(); i < mo->propertyCount(); ++i) {
79 QMetaProperty mp = mo->property(i);
82 if (mp.isReadable() && mp.isWritable())
84 else if (mp.isReadable())
89 printf(" %s %s.%s\n", mp.typeName(), qPrintable(interface), mp.name());
92 // methods (signals and slots)
93 for (int i = mo->methodOffset(); i < mo->methodCount(); ++i) {
94 QMetaMethod mm = mo->method(i);
96 QByteArray signature = mm.signature();
97 signature.truncate(signature.indexOf('('));
98 printf("%s %s%s%s %s.%s(",
99 mm.methodType() == QMetaMethod::Signal ? "signal" : "method",
100 mm.tag(), *mm.tag() ? " " : "",
101 *mm.typeName() ? mm.typeName() : "void",
102 qPrintable(interface), signature.constData());
104 QList<QByteArray> types = mm.parameterTypes();
105 QList<QByteArray> names = mm.parameterNames();
107 for (int i = 0; i < types.count(); ++i) {
110 types.at(i).constData());
111 if (!names.at(i).isEmpty())
112 printf(" %s", names.at(i).constData());
119 void listAllInterfaces(const QString &service, const QString &path)
121 QDBusInterfacePtr iface(*connection, service, path, "org.freedesktop.DBus.Introspectable");
122 if (!iface->isValid()) {
123 QDBusError err(iface->lastError());
124 fprintf(stderr, "Cannot introspect object %s at %s:\n%s (%s)\n",
125 qPrintable(path), qPrintable(service),
126 qPrintable(err.name()), qPrintable(err.message()));
129 QDBusReply<QString> xml = iface->call("Introspect");
136 QDomElement node = doc.documentElement();
137 QDomElement child = node.firstChildElement();
138 while (!child.isNull()) {
139 if (child.tagName() == QLatin1String("interface")) {
140 QString ifaceName = child.attribute("name");
141 if (QDBusUtil::isValidInterfaceName(ifaceName))
142 listInterface(service, path, ifaceName);
144 qWarning("Invalid D-BUS interface name '%s' found while parsing introspection",
145 qPrintable(ifaceName));
148 child = child.nextSiblingElement();
152 QStringList readList(int &argc, const char *const *&argv)
158 while (argc && QLatin1String(argv[0]) != ")")
159 retval += QString::fromLocal8Bit(argv[0]);
164 void placeCall(const QString &service, const QString &path, const QString &interface,
165 const QString &member, int argc, const char *const *argv)
167 QDBusInterfacePtr iface(*connection, service, path, interface);
168 if (!iface->isValid()) {
169 QDBusError err(iface->lastError());
170 fprintf(stderr, "Interface '%s' not available in object %s at %s:\n%s (%s)\n",
171 qPrintable(interface), qPrintable(path), qPrintable(service),
172 qPrintable(err.name()), qPrintable(err.message()));
176 const QMetaObject *mo = iface->metaObject();
177 QByteArray match = member.toLatin1();
181 for (int i = mo->methodOffset(); i < mo->methodCount(); ++i) {
182 QMetaMethod mm = mo->method(i);
183 QByteArray signature = mm.signature();
184 if (signature.startsWith(match)) {
191 fprintf(stderr, "Cannot find '%s.%s' in object %s at %s\n",
192 qPrintable(interface), qPrintable(member), qPrintable(path),
193 qPrintable(service));
197 QMetaMethod mm = mo->method(midx);
198 QList<QByteArray> types = mm.parameterTypes();
201 for (int i = 0; argc && i < types.count(); ++i) {
202 int id = QVariant::nameToType(types.at(i));
203 if ((id == QVariant::UserType || id == QVariant::Map) && types.at(i) != "QVariant") {
204 fprintf(stderr, "Sorry, can't pass arg of type %s yet\n",
205 types.at(i).constData());
208 if (id == QVariant::UserType)
209 id = QMetaType::type(types.at(i));
214 if ((id == QVariant::List || id == QVariant::StringList) && QLatin1String("(") == argv[0])
215 p = readList(argc, argv);
217 p = QString::fromLocal8Bit(argv[0]);
219 if (id < int(QVariant::UserType)) {
220 // avoid calling it for QVariant
221 p.convert( QVariant::Type(id) );
222 if (p.type() == QVariant::Invalid) {
223 fprintf(stderr, "Could not convert '%s' to type '%s'.\n",
224 argv[0], types.at(i).constData());
227 } else if (types.at(i) == "QVariant") {
228 QVariant tmp(id, p.constData());
235 if (params.count() != types.count()) {
236 fprintf(stderr, "Invalid number of parameters\n");
240 QDBusMessage reply = iface->callWithArgs(member, params, QDBusInterface::NoUseEventLoop);
241 if (reply.type() == QDBusMessage::ErrorMessage) {
242 QDBusError err = reply;
243 printf("Error: %s\n%s\n", qPrintable(err.name()), qPrintable(err.message()));
245 } else if (reply.type() != QDBusMessage::ReplyMessage) {
246 fprintf(stderr, "Invalid reply type %d\n", int(reply.type()));
250 foreach (QVariant v, reply) {
251 if (v.userType() == QVariant::StringList) {
252 foreach (QString s, v.toStringList())
253 printf("%s\n", qPrintable(s));
255 if (v.userType() == qMetaTypeId<QVariant>())
256 v = qvariant_cast<QVariant>(v);
257 printf("%s\n", qPrintable(v.toString()));
264 bool splitInterfaceAndName(const QString &interfaceAndName, const char *type,
265 QString &interface, QString &member)
267 interface = interfaceAndName;
268 int pos = interface.lastIndexOf(QLatin1Char('.'));
270 member = interface.mid(pos + 1);
271 interface.truncate(pos);
274 if (!QDBusUtil::isValidInterfaceName(interface)) {
275 fprintf(stderr, "Interface '%s' is not a valid interface name.\n", qPrintable(interface));
277 } else if (!QDBusUtil::isValidMemberName(member)) {
278 fprintf(stderr, "%s name '%s' is not a valid member name.\n", type, qPrintable(member));
284 void getProperty(const QString &service, const QString &path, const QString &interfaceAndName)
288 if (!splitInterfaceAndName(interfaceAndName, "Property", interface, property))
291 QDBusInterfacePtr iface(*connection, service, path, interface);
292 QVariant reply = iface->property(property.toLatin1());
293 if (reply.isNull()) {
294 QDBusError error = iface->lastError();
295 fprintf(stderr, "Could not get property '%s' on interface '%s': %s (%s)\n",
296 qPrintable(property), qPrintable(interface), qPrintable(error.name()),
297 qPrintable(error.message()));
301 printf("%s\n", qPrintable(reply.toString()));
304 void setProperty(const QString &service, const QString &path, const QString &interfaceAndName,
305 const QString &valueStr)
309 if (!splitInterfaceAndName(interfaceAndName, "Property", interface, property))
312 QDBusInterfacePtr iface(*connection, service, path, interface);
313 iface->setProperty(property.toLatin1(), valueStr);
316 int main(int argc, char **argv)
318 QCoreApplication app(argc, argv);
319 if (argc >= 1 && qstrcmp(argv[1], "--system") == 0) {
320 connection = &QDBus::systemBus();
324 connection = &QDBus::sessionBus();
326 if (!connection->isConnected()) {
327 fprintf(stderr, "Could not connect to D-Bus server: %s: %s\n",
328 qPrintable(connection->lastError().name()),
329 qPrintable(connection->lastError().message()));
332 QDBusBusService *bus = connection->busService();
335 QStringList names = bus->ListNames();
336 foreach (QString name, names)
337 printf("%s\n", qPrintable(name));
341 QString service = QLatin1String(argv[1]);
342 if (!QDBusUtil::isValidBusName(service)) {
343 fprintf(stderr, "Service '%s' is not a valid name.\n", qPrintable(service));
346 if (!bus->NameHasOwner(service)) {
347 fprintf(stderr, "Service '%s' does not exist.\n", qPrintable(service));
353 listObjects(service, QString());
357 QString path = QLatin1String(argv[2]);
358 if (!QDBusUtil::isValidObjectPath(path)) {
359 fprintf(stderr, "Path '%s' is not a valid path name.\n", qPrintable(path));
363 listAllInterfaces(service, path);
367 QString interface = QLatin1String(argv[3]);
369 int pos = interface.lastIndexOf(QLatin1Char('.'));
374 member = interface.mid(pos + 1);
375 interface.truncate(pos);
377 if (!interface.isEmpty() && !QDBusUtil::isValidInterfaceName(interface)) {
378 fprintf(stderr, "Interface '%s' is not a valid interface name.\n", qPrintable(interface));
381 if (!QDBusUtil::isValidMemberName(member)) {
382 fprintf(stderr, "Method name '%s' is not a valid member name.\n", qPrintable(member));
386 if (interface.isEmpty()) {
387 if (member.toLower() == QLatin1String("get") && argc == 5) {
388 getProperty(service, path, QLatin1String(argv[4]));
390 } else if (member.toLower() == QLatin1String("set") && argc == 6) {
391 setProperty(service, path, QLatin1String(argv[4]), QLatin1String(argv[5]));
395 placeCall(service, path, interface, member, argc - 4, argv + 4);