summaryrefslogtreecommitdiffstats
path: root/src/dbus
diff options
context:
space:
mode:
authorJason Barron <jbarron@trolltech.com>2009-07-24 09:45:33 (GMT)
committerJason Barron <jbarron@trolltech.com>2009-07-27 13:04:30 (GMT)
commit3643028959f0b38350e57e60ba4000435b75e592 (patch)
treec129e4dee11487abd437ab8ebd993ba261e06fa6 /src/dbus
parentcf66c667a97c0079141eb3f2d9e997b7378ae792 (diff)
parentc36139c665e61866aff4bf8572890a735167a7d0 (diff)
downloadQt-3643028959f0b38350e57e60ba4000435b75e592.zip
Qt-3643028959f0b38350e57e60ba4000435b75e592.tar.gz
Qt-3643028959f0b38350e57e60ba4000435b75e592.tar.bz2
Merge commit 'qt/master-stable'
Conflicts: configure.exe qmake/Makefile.unix qmake/generators/makefile.cpp src/corelib/global/qglobal.h src/corelib/kernel/kernel.pri src/corelib/kernel/qcoreevent.cpp src/corelib/kernel/qsharedmemory_unix.cpp src/gui/graphicsview/qgraphicsscene.cpp src/gui/kernel/qaction.cpp src/gui/kernel/qaction.h src/gui/kernel/qaction_p.h src/gui/kernel/qapplication.cpp src/gui/kernel/qapplication.h src/gui/kernel/qwidget.cpp src/gui/kernel/qwidget.h src/gui/kernel/qwidget_mac.mm src/gui/painting/qgraphicssystemfactory.cpp src/gui/styles/qwindowsstyle.cpp src/gui/text/qfontengine_qpf.cpp src/gui/widgets/qabstractscrollarea_p.h src/network/access/qnetworkaccessdebugpipebackend.cpp src/network/socket/qlocalsocket_unix.cpp src/network/socket/qnativesocketengine_p.h src/network/socket/qnativesocketengine_unix.cpp src/openvg/qpaintengine_vg.cpp tests/auto/q3sqlcursor/tst_q3sqlcursor.cpp tests/auto/qcssparser/qcssparser.pro tests/auto/qdir/tst_qdir.cpp tests/auto/qfile/tst_qfile.cpp tests/auto/qobject/tst_qobject.cpp tests/auto/qpathclipper/qpathclipper.pro tests/auto/qprocess/tst_qprocess.cpp tests/auto/qsettings/tst_qsettings.cpp tests/auto/qsharedpointer/qsharedpointer.pro tests/auto/qsqlquerymodel/qsqlquerymodel.pro tests/auto/qsqlrelationaltablemodel/qsqlrelationaltablemodel.pro tests/auto/qsqltablemodel/qsqltablemodel.pro tests/auto/qsqlthread/qsqlthread.pro tests/auto/qwidget/tst_qwidget.cpp
Diffstat (limited to 'src/dbus')
-rw-r--r--src/dbus/qdbusabstractinterface.cpp252
-rw-r--r--src/dbus/qdbusabstractinterface.h18
-rw-r--r--src/dbus/qdbusabstractinterface_p.h8
-rw-r--r--src/dbus/qdbusargument_p.h3
-rw-r--r--src/dbus/qdbusconnection_p.h5
-rw-r--r--src/dbus/qdbuserror.cpp21
-rw-r--r--src/dbus/qdbuserror.h6
-rw-r--r--src/dbus/qdbusintegrator.cpp100
-rw-r--r--src/dbus/qdbusinterface.cpp146
-rw-r--r--src/dbus/qdbusinternalfilters.cpp167
-rw-r--r--src/dbus/qdbusmarshaller.cpp48
-rw-r--r--src/dbus/qdbusmessage.cpp78
-rw-r--r--src/dbus/qdbusmessage.h6
-rw-r--r--src/dbus/qdbusmessage_p.h11
-rw-r--r--src/dbus/qdbusmisc.cpp47
-rw-r--r--src/dbus/qdbuspendingcall.cpp38
-rw-r--r--src/dbus/qdbuspendingcall.h3
-rw-r--r--src/dbus/qdbuspendingcall_p.h3
-rw-r--r--src/dbus/qdbusutil_p.h68
-rw-r--r--src/dbus/qdbusxmlgenerator.cpp37
20 files changed, 750 insertions, 315 deletions
diff --git a/src/dbus/qdbusabstractinterface.cpp b/src/dbus/qdbusabstractinterface.cpp
index 85c3274..7c520df 100644
--- a/src/dbus/qdbusabstractinterface.cpp
+++ b/src/dbus/qdbusabstractinterface.cpp
@@ -44,6 +44,7 @@
#include "qdbusargument.h"
#include "qdbuspendingcall.h"
+#include "qdbusmessage_p.h"
#include "qdbusmetaobject_p.h"
#include "qdbusmetatype_p.h"
#include "qdbusutil_p.h"
@@ -52,99 +53,83 @@
QT_BEGIN_NAMESPACE
+static QDBusError checkIfValid(const QString &service, const QString &path,
+ const QString &interface, bool isDynamic)
+{
+ // We should be throwing exceptions here... oh well
+ QDBusError error;
+
+ // dynamic interfaces (QDBusInterface) can have empty interfaces, but not service and object paths
+ // non-dynamic is the opposite: service and object paths can be empty, but not the interface
+ if (!isDynamic) {
+ // use assertion here because this should never happen, at all
+ Q_ASSERT_X(!interface.isEmpty(), "QDBusAbstractInterface", "Interface name cannot be empty");
+ }
+ if (!QDBusUtil::checkBusName(service, isDynamic ? QDBusUtil::EmptyNotAllowed : QDBusUtil::EmptyAllowed, &error))
+ return error;
+ if (!QDBusUtil::checkObjectPath(path, isDynamic ? QDBusUtil::EmptyNotAllowed : QDBusUtil::EmptyAllowed, &error))
+ return error;
+ if (!QDBusUtil::checkInterfaceName(interface, QDBusUtil::EmptyAllowed, &error))
+ return error;
+
+ // no error
+ return QDBusError();
+}
+
QDBusAbstractInterfacePrivate::QDBusAbstractInterfacePrivate(const QString &serv,
const QString &p,
const QString &iface,
const QDBusConnection& con,
bool isDynamic)
- : connection(con), service(serv), path(p), interface(iface), isValid(true)
+ : connection(con), service(serv), path(p), interface(iface),
+ lastError(checkIfValid(serv, p, iface, isDynamic)),
+ isValid(!lastError.isValid())
{
- if (isDynamic) {
- // QDBusInterface: service and object path can't be empty, but interface can
-#if 0
- Q_ASSERT_X(QDBusUtil::isValidBusName(service),
- "QDBusInterface::QDBusInterface", "Invalid service name");
- Q_ASSERT_X(QDBusUtil::isValidObjectPath(path),
- "QDBusInterface::QDBusInterface", "Invalid object path given");
- Q_ASSERT_X(interface.isEmpty() || QDBusUtil::isValidInterfaceName(interface),
- "QDBusInterface::QDBusInterface", "Invalid interface name");
-#else
- if (!QDBusUtil::isValidBusName(service)) {
- lastError = QDBusError(QDBusError::Disconnected,
- QLatin1String("Invalid service name"));
- isValid = false;
- } else if (!QDBusUtil::isValidObjectPath(path)) {
- lastError = QDBusError(QDBusError::Disconnected,
- QLatin1String("Invalid object name given"));
- isValid = false;
- } else if (!interface.isEmpty() && !QDBusUtil::isValidInterfaceName(interface)) {
- lastError = QDBusError(QDBusError::Disconnected,
- QLatin1String("Invalid interface name"));
- isValid = false;
- }
-#endif
- } else {
- // all others: service and path can be empty here, but interface can't
-#if 0
- Q_ASSERT_X(service.isEmpty() || QDBusUtil::isValidBusName(service),
- "QDBusAbstractInterface::QDBusAbstractInterface", "Invalid service name");
- Q_ASSERT_X(path.isEmpty() || QDBusUtil::isValidObjectPath(path),
- "QDBusAbstractInterface::QDBusAbstractInterface", "Invalid object path given");
- Q_ASSERT_X(QDBusUtil::isValidInterfaceName(interface),
- "QDBusAbstractInterface::QDBusAbstractInterface", "Invalid interface class!");
-#else
- if (!service.isEmpty() && !QDBusUtil::isValidBusName(service)) {
- lastError = QDBusError(QDBusError::Disconnected,
- QLatin1String("Invalid service name"));
- isValid = false;
- } else if (!path.isEmpty() && !QDBusUtil::isValidObjectPath(path)) {
- lastError = QDBusError(QDBusError::Disconnected,
- QLatin1String("Invalid object path given"));
- isValid = false;
- } else if (!QDBusUtil::isValidInterfaceName(interface)) {
- lastError = QDBusError(QDBusError::Disconnected,
- QLatin1String("Invalid interface class"));
- isValid = false;
- }
-#endif
- }
-
if (!isValid)
return;
if (!connection.isConnected()) {
lastError = QDBusError(QDBusError::Disconnected,
QLatin1String("Not connected to D-Bus server"));
- isValid = false;
} else if (!service.isEmpty()) {
currentOwner = connectionPrivate()->getNameOwner(service); // verify the name owner
if (currentOwner.isEmpty()) {
- isValid = false;
lastError = connectionPrivate()->lastError;
}
}
}
-QVariant QDBusAbstractInterfacePrivate::property(const QMetaProperty &mp) const
+bool QDBusAbstractInterfacePrivate::canMakeCalls() const
{
- if (!connection.isConnected()) // not connected
- return QVariant();
+ // recheck only if we have a wildcard (i.e. empty) service or path
+ // if any are empty, set the error message according to QDBusUtil
+ if (service.isEmpty())
+ return QDBusUtil::checkBusName(service, QDBusUtil::EmptyNotAllowed, &lastError);
+ if (path.isEmpty())
+ return QDBusUtil::checkObjectPath(path, QDBusUtil::EmptyNotAllowed, &lastError);
+ return true;
+}
+
+void QDBusAbstractInterfacePrivate::property(const QMetaProperty &mp, QVariant &where) const
+{
+ if (!isValid || !canMakeCalls()) { // can't make calls
+ where.clear();
+ return;
+ }
// is this metatype registered?
- int mid;
- const char *expectedSignature;
- if (mp.type() == QVariant::LastType) {
- // We're asking to read a QVariant
- mid = qMetaTypeId<QDBusVariant>();
- expectedSignature = "v";
- } else {
- mid = QMetaType::type(mp.typeName());
- expectedSignature = QDBusMetaType::typeToSignature(mid);
+ const char *expectedSignature = "";
+ if (mp.type() != 0xff) {
+ expectedSignature = QDBusMetaType::typeToSignature(where.userType());
if (expectedSignature == 0) {
qWarning("QDBusAbstractInterface: type %s must be registered with QtDBus before it can be "
"used to read property %s.%s",
mp.typeName(), qPrintable(interface), mp.name());
- return QVariant();
+ lastError = QDBusError(QDBusError::Failed,
+ QString::fromLatin1("Unregistered type %1 cannot be handled")
+ .arg(QLatin1String(mp.typeName())));
+ where.clear();
+ return;
}
}
@@ -152,26 +137,33 @@ QVariant QDBusAbstractInterfacePrivate::property(const QMetaProperty &mp) const
QDBusMessage msg = QDBusMessage::createMethodCall(service, path,
QLatin1String(DBUS_INTERFACE_PROPERTIES),
QLatin1String("Get"));
+ QDBusMessagePrivate::setParametersValidated(msg, true);
msg << interface << QString::fromUtf8(mp.name());
QDBusMessage reply = connection.call(msg, QDBus::Block);
if (reply.type() != QDBusMessage::ReplyMessage) {
lastError = reply;
- return QVariant();
+ where.clear();
+ return;
}
if (reply.signature() != QLatin1String("v")) {
QString errmsg = QLatin1String("Invalid signature `%1' in return from call to "
DBUS_INTERFACE_PROPERTIES);
lastError = QDBusError(QDBusError::InvalidSignature, errmsg.arg(reply.signature()));
- return QVariant();
+ where.clear();
+ return;
}
QByteArray foundSignature;
const char *foundType = 0;
QVariant value = qvariant_cast<QDBusVariant>(reply.arguments().at(0)).variant();
- if (value.userType() == mid)
- return value; // simple match
+ if (value.userType() == where.userType() || mp.type() == 0xff
+ || (expectedSignature[0] == 'v' && expectedSignature[1] == '\0')) {
+ // simple match
+ where = value;
+ return;
+ }
if (value.userType() == qMetaTypeId<QDBusArgument>()) {
QDBusArgument arg = qvariant_cast<QDBusArgument>(value);
@@ -179,14 +171,9 @@ QVariant QDBusAbstractInterfacePrivate::property(const QMetaProperty &mp) const
foundType = "user type";
foundSignature = arg.currentSignature().toLatin1();
if (foundSignature == expectedSignature) {
- void *null = 0;
- QVariant result(mid, null);
- QDBusMetaType::demarshall(arg, mid, result.data());
-
- if (mp.type() == QVariant::LastType)
- // special case: QVariant
- return qvariant_cast<QDBusVariant>(result).variant();
- return result;
+ // signatures match, we can demarshall
+ QDBusMetaType::demarshall(arg, where.userType(), where.data());
+ return;
}
} else {
foundType = value.typeName();
@@ -203,23 +190,28 @@ QVariant QDBusAbstractInterfacePrivate::property(const QMetaProperty &mp) const
QString::fromUtf8(mp.name()),
QString::fromLatin1(mp.typeName()),
QString::fromLatin1(expectedSignature)));
- return QVariant();
+ where.clear();
+ return;
}
-void QDBusAbstractInterfacePrivate::setProperty(const QMetaProperty &mp, const QVariant &value)
+bool QDBusAbstractInterfacePrivate::setProperty(const QMetaProperty &mp, const QVariant &value)
{
- if (!connection.isConnected()) // not connected
- return;
+ if (!isValid || !canMakeCalls()) // can't make calls
+ return false;
// send the value
QDBusMessage msg = QDBusMessage::createMethodCall(service, path,
QLatin1String(DBUS_INTERFACE_PROPERTIES),
QLatin1String("Set"));
+ QDBusMessagePrivate::setParametersValidated(msg, true);
msg << interface << QString::fromUtf8(mp.name()) << qVariantFromValue(QDBusVariant(value));
QDBusMessage reply = connection.call(msg, QDBus::Block);
- if (reply.type() != QDBusMessage::ReplyMessage)
+ if (reply.type() != QDBusMessage::ReplyMessage) {
lastError = reply;
+ return false;
+ }
+ return true;
}
void QDBusAbstractInterfacePrivate::_q_serviceOwnerChanged(const QString &name,
@@ -230,10 +222,36 @@ void QDBusAbstractInterfacePrivate::_q_serviceOwnerChanged(const QString &name,
//qDebug() << "QDBusAbstractInterfacePrivate serviceOwnerChanged" << name << oldOwner << newOwner;
if (name == service) {
currentOwner = newOwner;
- isValid = !newOwner.isEmpty();
}
}
+QDBusAbstractInterfaceBase::QDBusAbstractInterfaceBase(QDBusAbstractInterfacePrivate &d, QObject *parent)
+ : QObject(d, parent)
+{
+}
+
+int QDBusAbstractInterfaceBase::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
+{
+ int saved_id = _id;
+ _id = QObject::qt_metacall(_c, _id, _a);
+ if (_id < 0)
+ return _id;
+
+ if (_c == QMetaObject::ReadProperty || _c == QMetaObject::WriteProperty) {
+ QMetaProperty mp = metaObject()->property(saved_id);
+ int &status = *reinterpret_cast<int *>(_a[2]);
+ QVariant &variant = *reinterpret_cast<QVariant *>(_a[1]);
+
+ if (_c == QMetaObject::WriteProperty) {
+ status = d_func()->setProperty(mp, variant) ? 1 : 0;
+ } else {
+ d_func()->property(mp, variant);
+ status = variant.isValid() ? 1 : 0;
+ }
+ _id = -1;
+ }
+ return _id;
+}
/*!
\class QDBusAbstractInterface
@@ -258,10 +276,10 @@ void QDBusAbstractInterfacePrivate::_q_serviceOwnerChanged(const QString &name,
This is the constructor called from QDBusInterface::QDBusInterface.
*/
QDBusAbstractInterface::QDBusAbstractInterface(QDBusAbstractInterfacePrivate &d, QObject *parent)
- : QObject(d, parent)
+ : QDBusAbstractInterfaceBase(d, parent)
{
// keep track of the service owner
- if (d_func()->isValid)
+ if (!d_func()->currentOwner.isEmpty())
QObject::connect(d_func()->connectionPrivate(), SIGNAL(serviceOwnerChanged(QString,QString,QString)),
this, SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
}
@@ -274,7 +292,7 @@ QDBusAbstractInterface::QDBusAbstractInterface(QDBusAbstractInterfacePrivate &d,
QDBusAbstractInterface::QDBusAbstractInterface(const QString &service, const QString &path,
const char *interface, const QDBusConnection &con,
QObject *parent)
- : QObject(*new QDBusAbstractInterfacePrivate(service, path, QString::fromLatin1(interface),
+ : QDBusAbstractInterfaceBase(*new QDBusAbstractInterfacePrivate(service, path, QString::fromLatin1(interface),
con, false), parent)
{
// keep track of the service owner
@@ -300,7 +318,7 @@ QDBusAbstractInterface::~QDBusAbstractInterface()
*/
bool QDBusAbstractInterface::isValid() const
{
- return d_func()->isValid;
+ return !d_func()->currentOwner.isEmpty();
}
/*!
@@ -367,6 +385,9 @@ QDBusMessage QDBusAbstractInterface::callWithArgumentList(QDBus::CallMode mode,
{
Q_D(QDBusAbstractInterface);
+ if (!d->isValid || !d->canMakeCalls())
+ return QDBusMessage::createError(d->lastError);
+
QString m = method;
// split out the signature from the method
int pos = method.indexOf(QLatin1Char('.'));
@@ -397,6 +418,7 @@ QDBusMessage QDBusAbstractInterface::callWithArgumentList(QDBus::CallMode mode,
// qDebug() << "QDBusAbstractInterface" << "Service" << service() << "Path:" << path();
QDBusMessage msg = QDBusMessage::createMethodCall(service(), path(), interface(), m);
+ QDBusMessagePrivate::setParametersValidated(msg, true);
msg.setArguments(args);
QDBusMessage reply = d->connection.call(msg, mode);
@@ -425,7 +447,11 @@ QDBusPendingCall QDBusAbstractInterface::asyncCallWithArgumentList(const QString
{
Q_D(QDBusAbstractInterface);
+ if (!d->isValid || !d->canMakeCalls())
+ return QDBusPendingCall::fromError(d->lastError);
+
QDBusMessage msg = QDBusMessage::createMethodCall(service(), path(), interface(), method);
+ QDBusMessagePrivate::setParametersValidated(msg, true);
msg.setArguments(args);
return d->connection.asyncCall(msg);
}
@@ -440,7 +466,8 @@ QDBusPendingCall QDBusAbstractInterface::asyncCallWithArgumentList(const QString
This function returns true if the queueing succeeds. It does
not indicate that the executed call succeeded. If it fails,
- the \a errorMethod is called.
+ the \a errorMethod is called. If the queueing failed, this
+ function returns false and no slot will be called.
The \a returnMethod must have as its parameters the types returned
by the function call. Optionally, it may have a QDBusMessage
@@ -453,22 +480,26 @@ QDBusPendingCall QDBusAbstractInterface::asyncCallWithArgumentList(const QString
bool QDBusAbstractInterface::callWithCallback(const QString &method,
const QList<QVariant> &args,
QObject *receiver,
- const char *returnMethod,
+ const char *returnMethod,
const char *errorMethod)
{
Q_D(QDBusAbstractInterface);
+ if (!d->isValid || !d->canMakeCalls())
+ return false;
+
QDBusMessage msg = QDBusMessage::createMethodCall(service(),
- path(),
- interface(),
- method);
+ path(),
+ interface(),
+ method);
+ QDBusMessagePrivate::setParametersValidated(msg, true);
msg.setArguments(args);
d->lastError = 0;
return d->connection.callWithCallback(msg,
- receiver,
- returnMethod,
- errorMethod);
+ receiver,
+ returnMethod,
+ errorMethod);
}
/*!
@@ -492,7 +523,7 @@ bool QDBusAbstractInterface::callWithCallback(const QString &method,
bool QDBusAbstractInterface::callWithCallback(const QString &method,
const QList<QVariant> &args,
QObject *receiver,
- const char *slot)
+ const char *slot)
{
return callWithCallback(method, args, receiver, slot, 0);
}
@@ -503,13 +534,15 @@ bool QDBusAbstractInterface::callWithCallback(const QString &method,
*/
void QDBusAbstractInterface::connectNotify(const char *signal)
{
+ // someone connecting to one of our signals
+ Q_D(QDBusAbstractInterface);
+ if (!d->isValid)
+ return;
+
// we end up recursing here, so optimise away
if (qstrcmp(signal + 1, "destroyed(QObject*)") == 0)
return;
- // someone connecting to one of our signals
- Q_D(QDBusAbstractInterface);
-
QDBusConnectionPrivate *conn = d->connectionPrivate();
if (conn)
conn->connectRelay(d->service, d->currentOwner, d->path, d->interface,
@@ -524,6 +557,8 @@ void QDBusAbstractInterface::disconnectNotify(const char *signal)
{
// someone disconnecting from one of our signals
Q_D(QDBusAbstractInterface);
+ if (!d->isValid)
+ return;
QDBusConnectionPrivate *conn = d->connectionPrivate();
if (conn)
@@ -540,11 +575,7 @@ QVariant QDBusAbstractInterface::internalPropGet(const char *propname) const
// assume this property exists and is readable
// we're only called from generated code anyways
- int idx = metaObject()->indexOfProperty(propname);
- if (idx != -1)
- return d_func()->property(metaObject()->property(idx));
- qWarning("QDBusAbstractInterface::internalPropGet called with unknown property '%s'", propname);
- return QVariant(); // error
+ return property(propname);
}
/*!
@@ -553,16 +584,7 @@ QVariant QDBusAbstractInterface::internalPropGet(const char *propname) const
*/
void QDBusAbstractInterface::internalPropSet(const char *propname, const QVariant &value)
{
- Q_D(QDBusAbstractInterface);
-
- // assume this property exists and is writeable
- // we're only called from generated code anyways
-
- int idx = metaObject()->indexOfProperty(propname);
- if (idx != -1)
- d->setProperty(metaObject()->property(idx), value);
- else
- qWarning("QDBusAbstractInterface::internalPropGet called with unknown property '%s'", propname);
+ setProperty(propname, value);
}
/*!
diff --git a/src/dbus/qdbusabstractinterface.h b/src/dbus/qdbusabstractinterface.h
index 6400b26..e525f77 100644
--- a/src/dbus/qdbusabstractinterface.h
+++ b/src/dbus/qdbusabstractinterface.h
@@ -61,7 +61,23 @@ class QDBusError;
class QDBusPendingCall;
class QDBusAbstractInterfacePrivate;
-class QDBUS_EXPORT QDBusAbstractInterface: public QObject
+
+class QDBUS_EXPORT QDBusAbstractInterfaceBase: public QObject
+{
+public:
+ int qt_metacall(QMetaObject::Call, int, void**);
+protected:
+ QDBusAbstractInterfaceBase(QDBusAbstractInterfacePrivate &dd, QObject *parent);
+private:
+ Q_DECLARE_PRIVATE(QDBusAbstractInterface)
+};
+
+class QDBUS_EXPORT QDBusAbstractInterface:
+#ifdef Q_QDOC
+ public QObject
+#else
+ public QDBusAbstractInterfaceBase
+#endif
{
Q_OBJECT
diff --git a/src/dbus/qdbusabstractinterface_p.h b/src/dbus/qdbusabstractinterface_p.h
index e2ea058..65df902 100644
--- a/src/dbus/qdbusabstractinterface_p.h
+++ b/src/dbus/qdbusabstractinterface_p.h
@@ -75,15 +75,19 @@ public:
QString path;
QString interface;
mutable QDBusError lastError;
+
+ // this is set during creation and never changed
+ // it can't be const because QDBusInterfacePrivate has one more check
bool isValid;
QDBusAbstractInterfacePrivate(const QString &serv, const QString &p,
const QString &iface, const QDBusConnection& con, bool dynamic);
virtual ~QDBusAbstractInterfacePrivate() { }
+ bool canMakeCalls() const;
// these functions do not check if the property is valid
- QVariant property(const QMetaProperty &mp) const;
- void setProperty(const QMetaProperty &mp, const QVariant &value);
+ void property(const QMetaProperty &mp, QVariant &where) const;
+ bool setProperty(const QMetaProperty &mp, const QVariant &value);
// return conn's d pointer
inline QDBusConnectionPrivate *connectionPrivate() const
diff --git a/src/dbus/qdbusargument_p.h b/src/dbus/qdbusargument_p.h
index b49a517..78bc683 100644
--- a/src/dbus/qdbusargument_p.h
+++ b/src/dbus/qdbusargument_p.h
@@ -130,7 +130,7 @@ public:
QDBusMarshaller *endCommon();
void open(QDBusMarshaller &sub, int code, const char *signature);
void close();
- void error();
+ void error(const QString &message);
bool appendVariantInternal(const QVariant &arg);
bool appendRegisteredType(const QVariant &arg);
@@ -140,6 +140,7 @@ public:
DBusMessageIter iterator;
QDBusMarshaller *parent;
QByteArray *ba;
+ QString errorString;
char closeCode;
bool ok;
diff --git a/src/dbus/qdbusconnection_p.h b/src/dbus/qdbusconnection_p.h
index 5c37509..a156a71 100644
--- a/src/dbus/qdbusconnection_p.h
+++ b/src/dbus/qdbusconnection_p.h
@@ -300,6 +300,8 @@ public:
extern int qDBusParametersForMethod(const QMetaMethod &mm, QList<int>& metaTypes);
extern int qDBusNameToTypeId(const char *name);
extern bool qDBusCheckAsyncTag(const char *tag);
+extern bool qDBusInterfaceInObject(QObject *obj, const QString &interface_name);
+extern QString qDBusInterfaceFromMetaObject(const QMetaObject *mo);
// in qdbusinternalfilters.cpp
extern QString qDBusIntrospectObject(const QDBusConnectionPrivate::ObjectTreeNode &node);
@@ -310,9 +312,6 @@ extern QDBusMessage qDBusPropertySet(const QDBusConnectionPrivate::ObjectTreeNod
extern QDBusMessage qDBusPropertyGetAll(const QDBusConnectionPrivate::ObjectTreeNode &node,
const QDBusMessage &msg);
-// in qdbusxmlgenerator.cpp
-extern QString qDBusInterfaceFromMetaObject(const QMetaObject *mo);
-
QT_END_NAMESPACE
#endif
diff --git a/src/dbus/qdbuserror.cpp b/src/dbus/qdbuserror.cpp
index 4f50e4f..caa2437 100644
--- a/src/dbus/qdbuserror.cpp
+++ b/src/dbus/qdbuserror.cpp
@@ -91,6 +91,10 @@ org.freedesktop.DBus.Error.InvalidSignature
org.freedesktop.DBus.Error.UnknownInterface
com.trolltech.QtDBus.Error.InternalError
org.freedesktop.DBus.Error.UnknownObject
+com.trolltech.QtDBus.Error.InvalidService
+com.trolltech.QtDBus.Error.InvalidObjectPath
+com.trolltech.QtDBus.Error.InvalidInterface
+com.trolltech.QtDBus.Error.InvalidMember
*/
// in the same order as KnownErrors!
@@ -116,12 +120,17 @@ static const char errorMessages_string[] =
"org.freedesktop.DBus.Error.UnknownInterface\0"
"com.trolltech.QtDBus.Error.InternalError\0"
"org.freedesktop.DBus.Error.UnknownObject\0"
+ "com.trolltech.QtDBus.Error.InvalidService\0"
+ "com.trolltech.QtDBus.Error.InvalidObjectPath\0"
+ "com.trolltech.QtDBus.Error.InvalidInterface\0"
+ "com.trolltech.QtDBus.Error.InvalidMember\0"
"\0";
static const int errorMessages_indices[] = {
0, 6, 40, 76, 118, 153, 191, 231,
273, 313, 349, 384, 421, 461, 501, 540,
- 581, 617, 661, 705, 746, 0
+ 581, 617, 661, 705, 746, 787, 829, 874,
+ 918, 0
};
static const int errorMessages_count = sizeof errorMessages_indices /
@@ -216,8 +225,16 @@ static inline QDBusError::ErrorType get(const char *name)
\value UnknownInterface The interface is not known
\value InternalError An internal error occurred
(\c com.trolltech.QtDBus.Error.InternalError)
- \value UnknownObject The remote object could not be found.
+ \value InvalidObjectPath The object path provided is invalid.
+
+ \value InvalidService The service requested is invalid.
+
+ \value InvalidMember The member is invalid.
+
+ \value InvalidInterface The interface is invalid.
+
+ \value UnknownObject The remote object could not be found.
*/
/*!
diff --git a/src/dbus/qdbuserror.h b/src/dbus/qdbuserror.h
index 7b77fd5..4e348dd 100644
--- a/src/dbus/qdbuserror.h
+++ b/src/dbus/qdbuserror.h
@@ -81,10 +81,14 @@ public:
UnknownInterface,
InternalError,
UnknownObject,
+ InvalidService,
+ InvalidObjectPath,
+ InvalidInterface,
+ InvalidMember,
#ifndef Q_QDOC
// don't use this one!
- LastErrorType = UnknownObject
+ LastErrorType = InvalidMember
#endif
};
diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp
index 97a4545..e6c69b6 100644
--- a/src/dbus/qdbusintegrator.cpp
+++ b/src/dbus/qdbusintegrator.cpp
@@ -1143,10 +1143,14 @@ void QDBusConnectionPrivate::relaySignal(QObject *obj, const QMetaObject *mo, in
QDBusReadLocker locker(RelaySignalAction, this);
QDBusMessage message = QDBusMessage::createSignal(QLatin1String("/"), interface,
QLatin1String(memberName));
+ QDBusMessagePrivate::setParametersValidated(message, true);
message.setArguments(args);
- DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message);
+ QDBusError error;
+ DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message, &error);
if (!msg) {
- qWarning("QDBusConnection: Could not emit signal %s.%s", qPrintable(interface), memberName.constData());
+ qWarning("QDBusConnection: Could not emit signal %s.%s: %s", qPrintable(interface), memberName.constData(),
+ qPrintable(error.message()));
+ lastError = error;
return;
}
@@ -1359,12 +1363,8 @@ void QDBusConnectionPrivate::activateObject(ObjectTreeNode &node, const QDBusMes
// try the object itself:
if (node.flags & (QDBusConnection::ExportScriptableSlots|QDBusConnection::ExportNonScriptableSlots)) {
bool interfaceFound = true;
- if (!msg.interface().isEmpty()) {
- // check if the interface name matches anything in the class hierarchy
- const QMetaObject *mo = node.obj->metaObject();
- for ( ; !interfaceFound && mo != &QObject::staticMetaObject; mo = mo->superClass())
- interfaceFound = msg.interface() == qDBusInterfaceFromMetaObject(mo);
- }
+ if (!msg.interface().isEmpty())
+ interfaceFound = qDBusInterfaceInObject(node.obj, msg.interface());
if (interfaceFound) {
if (!activateCall(node.obj, node.flags, msg))
@@ -1702,21 +1702,26 @@ int QDBusConnectionPrivate::send(const QDBusMessage& message)
return -1; // don't send; the reply will be retrieved by the caller
// through the d_ptr->localReply link
- DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message);
+ QDBusError error;
+ DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message, &error);
if (!msg) {
if (message.type() == QDBusMessage::MethodCallMessage)
- qWarning("QDBusConnection: error: could not send message to service \"%s\" path \"%s\" interface \"%s\" member \"%s\"",
+ qWarning("QDBusConnection: error: could not send message to service \"%s\" path \"%s\" interface \"%s\" member \"%s\": %s",
qPrintable(message.service()), qPrintable(message.path()),
- qPrintable(message.interface()), qPrintable(message.member()));
+ qPrintable(message.interface()), qPrintable(message.member()),
+ qPrintable(error.message()));
else if (message.type() == QDBusMessage::SignalMessage)
- qWarning("QDBusConnection: error: could not send signal path \"%s\" interface \"%s\" member \"%s\"",
+ qWarning("QDBusConnection: error: could not send signal path \"%s\" interface \"%s\" member \"%s\": %s",
qPrintable(message.path()), qPrintable(message.interface()),
- qPrintable(message.member()));
+ qPrintable(message.member()),
+ qPrintable(error.message()));
else
- qWarning("QDBusConnection: error: could not send %s message to service \"%s\"",
+ qWarning("QDBusConnection: error: could not send %s message to service \"%s\": %s",
message.type() == QDBusMessage::ReplyMessage ? "reply" :
message.type() == QDBusMessage::ErrorMessage ? "error" :
- "invalid", qPrintable(message.service()));
+ "invalid", qPrintable(message.service()),
+ qPrintable(error.message()));
+ lastError = error;
return 0;
}
@@ -1743,12 +1748,15 @@ QDBusMessage QDBusConnectionPrivate::sendWithReply(const QDBusMessage &message,
return sendWithReplyLocal(message);
if (!QCoreApplication::instance() || sendMode == QDBus::Block) {
- DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message);
+ QDBusError err;
+ DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message, &err);
if (!msg) {
- qWarning("QDBusConnection: error: could not send message to service \"%s\" path \"%s\" interface \"%s\" member \"%s\"",
+ qWarning("QDBusConnection: error: could not send message to service \"%s\" path \"%s\" interface \"%s\" member \"%s\": %s",
qPrintable(message.service()), qPrintable(message.path()),
- qPrintable(message.interface()), qPrintable(message.member()));
- return QDBusMessage();
+ qPrintable(message.interface()), qPrintable(message.member()),
+ qPrintable(err.message()));
+ lastError = err;
+ return QDBusMessage::createError(err);
}
qDBusDebug() << QThread::currentThread() << "sending message (blocking):" << message;
@@ -1758,9 +1766,8 @@ QDBusMessage QDBusConnectionPrivate::sendWithReply(const QDBusMessage &message,
q_dbus_message_unref(msg);
if (!!error) {
- QDBusError qe = error;
- lastError = qe;
- return QDBusMessage::createError(qe);
+ lastError = err = error;
+ return QDBusMessage::createError(err);
}
QDBusMessage amsg = QDBusMessagePrivate::fromDBusMessage(reply);
@@ -1770,16 +1777,17 @@ QDBusMessage QDBusConnectionPrivate::sendWithReply(const QDBusMessage &message,
return amsg;
} else { // use the event loop
QDBusPendingCallPrivate *pcall = sendWithReplyAsync(message, timeout);
- if (!pcall)
- return QDBusMessage();
+ Q_ASSERT(pcall);
- pcall->watcherHelper = new QDBusPendingCallWatcherHelper;
- QEventLoop loop;
- loop.connect(pcall->watcherHelper, SIGNAL(reply(QDBusMessage)), SLOT(quit()));
- loop.connect(pcall->watcherHelper, SIGNAL(error(QDBusError,QDBusMessage)), SLOT(quit()));
+ if (pcall->replyMessage.type() != QDBusMessage::InvalidMessage) {
+ pcall->watcherHelper = new QDBusPendingCallWatcherHelper;
+ QEventLoop loop;
+ loop.connect(pcall->watcherHelper, SIGNAL(reply(QDBusMessage)), SLOT(quit()));
+ loop.connect(pcall->watcherHelper, SIGNAL(error(QDBusError,QDBusMessage)), SLOT(quit()));
- // enter the event loop and wait for a reply
- loop.exec(QEventLoop::ExcludeUserInputEvents | QEventLoop::WaitForMoreEvents);
+ // enter the event loop and wait for a reply
+ loop.exec(QEventLoop::ExcludeUserInputEvents | QEventLoop::WaitForMoreEvents);
+ }
QDBusMessage reply = pcall->replyMessage;
lastError = reply; // set or clear error
@@ -1835,20 +1843,25 @@ QDBusPendingCallPrivate *QDBusConnectionPrivate::sendWithReplyAsync(const QDBusM
return pcall;
}
- DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message);
+ checkThread();
+ QDBusPendingCallPrivate *pcall = new QDBusPendingCallPrivate;
+ pcall->sentMessage = message;
+ pcall->ref = 0;
+
+ QDBusError error;
+ DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message, &error);
if (!msg) {
- qWarning("QDBusConnection: error: could not send message to service \"%s\" path \"%s\" interface \"%s\" member \"%s\"",
+ qWarning("QDBusConnection: error: could not send message to service \"%s\" path \"%s\" interface \"%s\" member \"%s\": %s",
qPrintable(message.service()), qPrintable(message.path()),
- qPrintable(message.interface()), qPrintable(message.member()));
- return 0;
+ qPrintable(message.interface()), qPrintable(message.member()),
+ qPrintable(error.message()));
+ pcall->replyMessage = QDBusMessage::createError(error);
+ lastError = error;
+ return pcall;
}
- checkThread();
qDBusDebug() << QThread::currentThread() << "sending message (async):" << message;
DBusPendingCall *pending = 0;
- QDBusPendingCallPrivate *pcall = new QDBusPendingCallPrivate;
- pcall->sentMessage = message;
- pcall->ref = 0;
QDBusDispatchLocker locker(SendWithReplyAsyncAction, this);
if (q_dbus_connection_send_with_reply(connection, msg, &pending, timeout)) {
@@ -1862,14 +1875,14 @@ QDBusPendingCallPrivate *QDBusConnectionPrivate::sendWithReplyAsync(const QDBusM
return pcall;
} else {
// we're probably disconnected at this point
- lastError = QDBusError(QDBusError::Disconnected, QLatin1String("Not connected to server"));
+ lastError = error = QDBusError(QDBusError::Disconnected, QLatin1String("Not connected to server"));
}
} else {
- lastError = QDBusError(QDBusError::NoMemory, QLatin1String("Out of memory"));
+ lastError = error = QDBusError(QDBusError::NoMemory, QLatin1String("Out of memory"));
}
q_dbus_message_unref(msg);
- pcall->replyMessage = QDBusMessage::createError(lastError);
+ pcall->replyMessage = QDBusMessage::createError(error);
return pcall;
}
@@ -1878,8 +1891,7 @@ int QDBusConnectionPrivate::sendWithReplyAsync(const QDBusMessage &message, QObj
int timeout)
{
QDBusPendingCallPrivate *pcall = sendWithReplyAsync(message, timeout);
- if (!pcall)
- return 0;
+ Q_ASSERT(pcall);
// has it already finished (dispatched locally)?
if (pcall->replyMessage.type() == QDBusMessage::ReplyMessage) {
@@ -2081,6 +2093,7 @@ QString QDBusConnectionPrivate::getNameOwner(const QString& serviceName)
QDBusMessage msg = QDBusMessage::createMethodCall(QLatin1String(DBUS_SERVICE_DBUS),
QLatin1String(DBUS_PATH_DBUS), QLatin1String(DBUS_INTERFACE_DBUS),
QLatin1String("GetNameOwner"));
+ QDBusMessagePrivate::setParametersValidated(msg, true);
msg << serviceName;
QDBusMessage reply = sendWithReply(msg, QDBus::Block);
if (reply.type() == QDBusMessage::ReplyMessage)
@@ -2104,6 +2117,7 @@ QDBusConnectionPrivate::findMetaObject(const QString &service, const QString &pa
QDBusMessage msg = QDBusMessage::createMethodCall(service, path,
QLatin1String(DBUS_INTERFACE_INTROSPECTABLE),
QLatin1String("Introspect"));
+ QDBusMessagePrivate::setParametersValidated(msg, true);
QDBusMessage reply = sendWithReply(msg, QDBus::Block);
diff --git a/src/dbus/qdbusinterface.cpp b/src/dbus/qdbusinterface.cpp
index 211b717..5f6df0a 100644
--- a/src/dbus/qdbusinterface.cpp
+++ b/src/dbus/qdbusinterface.cpp
@@ -51,6 +51,102 @@
QT_BEGIN_NAMESPACE
+static void copyArgument(void *to, int id, const QVariant &arg)
+{
+ if (id == arg.userType()) {
+ switch (id) {
+ case QVariant::Bool:
+ *reinterpret_cast<bool *>(to) = arg.toBool();
+ return;
+
+ case QMetaType::UChar:
+ *reinterpret_cast<uchar *>(to) = arg.value<uchar>();
+ return;
+
+ case QMetaType::Short:
+ *reinterpret_cast<short *>(to) = arg.value<short>();
+ return;
+
+ case QMetaType::UShort:
+ *reinterpret_cast<ushort *>(to) = arg.value<ushort>();
+ return;
+
+ case QVariant::Int:
+ *reinterpret_cast<int *>(to) = arg.toInt();
+ return;
+
+ case QVariant::UInt:
+ *reinterpret_cast<uint *>(to) = arg.toUInt();
+ return;
+
+ case QVariant::LongLong:
+ *reinterpret_cast<qlonglong *>(to) = arg.toLongLong();
+ return;
+
+ case QVariant::ULongLong:
+ *reinterpret_cast<qulonglong *>(to) = arg.toULongLong();
+ return;
+
+ case QVariant::Double:
+ *reinterpret_cast<double *>(to) = arg.toDouble();
+ return;
+
+ case QVariant::String:
+ *reinterpret_cast<QString *>(to) = arg.toString();
+ return;
+
+ case QVariant::ByteArray:
+ *reinterpret_cast<QByteArray *>(to) = arg.toByteArray();
+ return;
+
+ case QVariant::StringList:
+ *reinterpret_cast<QStringList *>(to) = arg.toStringList();
+ return;
+ }
+
+ if (id == QDBusMetaTypeId::variant) {
+ *reinterpret_cast<QDBusVariant *>(to) = arg.value<QDBusVariant>();
+ return;
+ } else if (id == QDBusMetaTypeId::objectpath) {
+ *reinterpret_cast<QDBusObjectPath *>(to) = arg.value<QDBusObjectPath>();
+ return;
+ } else if (id == QDBusMetaTypeId::signature) {
+ *reinterpret_cast<QDBusSignature *>(to) = arg.value<QDBusSignature>();
+ return;
+ }
+
+ // those above are the only types possible
+ // the demarshaller code doesn't demarshall anything else
+ qFatal("Found a decoded basic type in a D-Bus reply that shouldn't be there");
+ }
+
+ // if we got here, it's either an un-dermarshalled type or a mismatch
+ if (arg.userType() != QDBusMetaTypeId::argument) {
+ // it's a mismatch
+ //qWarning?
+ return;
+ }
+
+ // is this type registered?
+ const char *userSignature = QDBusMetaType::typeToSignature(id);
+ if (!userSignature || !*userSignature) {
+ // type not registered
+ //qWarning?
+ return;
+ }
+
+ // is it the same signature?
+ QDBusArgument dbarg = arg.value<QDBusArgument>();
+ if (dbarg.currentSignature() != QLatin1String(userSignature)) {
+ // not the same signature, another mismatch
+ //qWarning?
+ return;
+ }
+
+ // we can demarshall
+ QDBusMetaType::demarshall(dbarg, id, to);
+}
+
QDBusInterfacePrivate::QDBusInterfacePrivate(const QString &serv, const QString &p,
const QString &iface, const QDBusConnection &con)
: QDBusAbstractInterfacePrivate(serv, p, iface, con, true), metaObject(0)
@@ -186,45 +282,39 @@ int QDBusInterfacePrivate::metacall(QMetaObject::Call c, int id, void **argv)
// we will assume that the input arguments were passed correctly
QVariantList args;
- for (int i = 1; i <= inputTypesCount; ++i)
+ int i = 1;
+ for ( ; i <= inputTypesCount; ++i)
args << QVariant(inputTypes[i], argv[i]);
// make the call
- QPointer<QDBusInterface> qq = q;
QDBusMessage reply = q->callWithArgumentList(QDBus::Block, methodName, args);
- args.clear();
- // we ignore return values
+ if (reply.type() == QDBusMessage::ReplyMessage) {
+ // attempt to demarshall the return values
+ args = reply.arguments();
+ QVariantList::ConstIterator it = args.constBegin();
+ const int *outputTypes = metaObject->outputTypesForMethod(id);
+ int outputTypesCount = *outputTypes++;
+
+ if (*mm.typeName()) {
+ // this method has a return type
+ if (argv[0] && it != args.constEnd())
+ copyArgument(argv[0], *outputTypes++, *it);
- // access to "this" or to "q" below this point must check for "qq"
- // we may have been deleted!
+ // skip this argument even if we didn't copy it
+ --outputTypesCount;
+ ++it;
+ }
- if (!qq.isNull())
- lastError = reply;
+ for (int j = 0; j < outputTypesCount && it != args.constEnd(); ++i, ++j, ++it) {
+ copyArgument(argv[i], outputTypes[j], *it);
+ }
+ }
// done
+ lastError = reply;
return -1;
}
- } else if (c == QMetaObject::ReadProperty) {
- // Qt doesn't support non-readable properties
- // we have to re-check
- QMetaProperty mp = metaObject->property(id + metaObject->propertyOffset());
- if (!mp.isReadable())
- return -1; // don't read
-
- QVariant *value = reinterpret_cast<QVariant*>(argv[1]);
- argv[1] = 0;
- *value = property(mp);
-
- return -1; // handled, error or not
- } else if (c == QMetaObject::WriteProperty) {
- // QMetaProperty::write has already checked that we're writable
- // it has also checked that the type is right
- QVariant *value = reinterpret_cast<QVariant *>(argv[1]);
- QMetaProperty mp = metaObject->property(id + metaObject->propertyOffset());
-
- setProperty(mp, *value);
- return -1;
}
return id;
}
diff --git a/src/dbus/qdbusinternalfilters.cpp b/src/dbus/qdbusinternalfilters.cpp
index 416144d..45cbbb0 100644
--- a/src/dbus/qdbusinternalfilters.cpp
+++ b/src/dbus/qdbusinternalfilters.cpp
@@ -53,6 +53,7 @@
#include "qdbusextratypes.h"
#include "qdbusmessage.h"
#include "qdbusmetatype.h"
+#include "qdbusmetatype_p.h"
#include "qdbusmessage_p.h"
#include "qdbusutil_p.h"
@@ -177,14 +178,25 @@ QString qDBusIntrospectObject(const QDBusConnectionPrivate::ObjectTreeNode &node
// implement the D-Bus interface org.freedesktop.DBus.Properties
-static QDBusMessage qDBusPropertyError(const QDBusMessage &msg, const QString &interface_name)
+static inline QDBusMessage interfaceNotFoundError(const QDBusMessage &msg, const QString &interface_name)
{
- return msg.createErrorReply(QLatin1String(DBUS_ERROR_INVALID_ARGS),
+ return msg.createErrorReply(QDBusError::UnknownInterface,
QString::fromLatin1("Interface %1 was not found in object %2")
.arg(interface_name)
.arg(msg.path()));
}
+static inline QDBusMessage
+propertyNotFoundError(const QDBusMessage &msg, const QString &interface_name, const QByteArray &property_name)
+{
+ return msg.createErrorReply(QDBusError::InvalidArgs,
+ QString::fromLatin1("Property %1%2%3 was not found in object %4")
+ .arg(interface_name,
+ QString::fromLatin1(interface_name.isEmpty() ? "" : "."),
+ QString::fromLatin1(property_name),
+ msg.path()));
+}
+
QDBusMessage qDBusPropertyGet(const QDBusConnectionPrivate::ObjectTreeNode &node,
const QDBusMessage &msg)
{
@@ -198,6 +210,7 @@ QDBusMessage qDBusPropertyGet(const QDBusConnectionPrivate::ObjectTreeNode &node
QDBusAdaptorConnector *connector;
QVariant value;
+ bool interfaceFound = false;
if (node.flags & QDBusConnection::ExportAdaptors &&
(connector = qDBusFindAdaptorConnector(node.obj))) {
@@ -217,31 +230,122 @@ QDBusMessage qDBusPropertyGet(const QDBusConnectionPrivate::ObjectTreeNode &node
QDBusAdaptorConnector::AdaptorMap::ConstIterator it;
it = qLowerBound(connector->adaptors.constBegin(), connector->adaptors.constEnd(),
interface_name);
- if (it != connector->adaptors.constEnd() && interface_name == QLatin1String(it->interface))
+ if (it != connector->adaptors.constEnd() && interface_name == QLatin1String(it->interface)) {
+ interfaceFound = true;
value = it->adaptor->property(property_name);
+ }
}
}
- if (!value.isValid() && node.flags & (QDBusConnection::ExportAllProperties |
- QDBusConnection::ExportNonScriptableProperties)) {
+ if (!interfaceFound && !value.isValid()
+ && node.flags & (QDBusConnection::ExportAllProperties |
+ QDBusConnection::ExportNonScriptableProperties)) {
// try the object itself
- int pidx = node.obj->metaObject()->indexOfProperty(property_name);
- if (pidx != -1) {
- QMetaProperty mp = node.obj->metaObject()->property(pidx);
- if ((mp.isScriptable() && (node.flags & QDBusConnection::ExportScriptableProperties)) ||
- (!mp.isScriptable() && (node.flags & QDBusConnection::ExportNonScriptableProperties)))
- value = mp.read(node.obj);
+ if (!interface_name.isEmpty())
+ interfaceFound = qDBusInterfaceInObject(node.obj, interface_name);
+
+ if (interfaceFound) {
+ int pidx = node.obj->metaObject()->indexOfProperty(property_name);
+ if (pidx != -1) {
+ QMetaProperty mp = node.obj->metaObject()->property(pidx);
+ if ((mp.isScriptable() && (node.flags & QDBusConnection::ExportScriptableProperties)) ||
+ (!mp.isScriptable() && (node.flags & QDBusConnection::ExportNonScriptableProperties)))
+ value = mp.read(node.obj);
+ }
}
}
if (!value.isValid()) {
// the property was not found
- return qDBusPropertyError(msg, interface_name);
+ if (!interfaceFound)
+ return interfaceNotFoundError(msg, interface_name);
+ return propertyNotFoundError(msg, interface_name, property_name);
}
return msg.createReply(qVariantFromValue(QDBusVariant(value)));
}
+enum PropertyWriteResult {
+ PropertyWriteSuccess = 0,
+ PropertyNotFound,
+ PropertyTypeMismatch,
+ PropertyWriteFailed
+};
+
+static QDBusMessage propertyWriteReply(const QDBusMessage &msg, const QString &interface_name,
+ const QByteArray &property_name, int status)
+{
+ switch (status) {
+ case PropertyNotFound:
+ return propertyNotFoundError(msg, interface_name, property_name);
+ case PropertyTypeMismatch:
+ return msg.createErrorReply(QDBusError::InvalidArgs,
+ QString::fromLatin1("Invalid arguments for writing to property %1%2%3")
+ .arg(interface_name,
+ QString::fromLatin1(interface_name.isEmpty() ? "" : "."),
+ QString::fromLatin1(property_name)));
+ case PropertyWriteFailed:
+ return msg.createErrorReply(QDBusError::InternalError,
+ QString::fromLatin1("Internal error"));
+
+ case PropertyWriteSuccess:
+ return msg.createReply();
+ }
+ Q_ASSERT_X(false, "", "Should not be reached");
+ return QDBusMessage();
+}
+
+static int writeProperty(QObject *obj, const QByteArray &property_name, QVariant value,
+ int propFlags = QDBusConnection::ExportAllProperties)
+{
+ const QMetaObject *mo = obj->metaObject();
+ int pidx = mo->indexOfProperty(property_name);
+ if (pidx == -1) {
+ // this object has no property by that name
+ return PropertyNotFound;
+ }
+
+ QMetaProperty mp = mo->property(pidx);
+
+ // check if this property is exported
+ bool isScriptable = mp.isScriptable();
+ if (!(propFlags & QDBusConnection::ExportScriptableProperties) && isScriptable)
+ return PropertyNotFound;
+ if (!(propFlags & QDBusConnection::ExportNonScriptableProperties) && !isScriptable)
+ return PropertyNotFound;
+
+ // we found our property
+ // do we have the right type?
+ int id = mp.type();
+ if (id == QVariant::UserType) {
+ // dynamic type
+ id = qDBusNameToTypeId(mp.typeName());
+ if (id == -1) {
+ // type not registered?
+ qWarning("QDBusConnection: Unable to handle unregistered datatype '%s' for property '%s::%s'",
+ mp.typeName(), mo->className(), property_name.constData());
+ return PropertyWriteFailed;
+ }
+ }
+
+ if (id != 0xff && value.userType() == QDBusMetaTypeId::argument) {
+ // we have to demarshall before writing
+ void *null = 0;
+ QVariant other(id, null);
+ if (!QDBusMetaType::demarshall(qVariantValue<QDBusArgument>(value), id, other.data())) {
+ qWarning("QDBusConnection: type `%s' (%d) is not registered with QtDBus. "
+ "Use qDBusRegisterMetaType to register it",
+ mp.typeName(), id);
+ return PropertyWriteFailed;
+ }
+
+ value = other;
+ }
+
+ // the property type here should match
+ return mp.write(obj, value) ? PropertyWriteSuccess : PropertyWriteFailed;
+}
+
QDBusMessage qDBusPropertySet(const QDBusConnectionPrivate::ObjectTreeNode &node,
const QDBusMessage &msg)
{
@@ -263,38 +367,39 @@ QDBusMessage qDBusPropertySet(const QDBusConnectionPrivate::ObjectTreeNode &node
if (interface_name.isEmpty()) {
for (QDBusAdaptorConnector::AdaptorMap::ConstIterator it = connector->adaptors.constBegin(),
end = connector->adaptors.constEnd(); it != end; ++it) {
- const QMetaObject *mo = it->adaptor->metaObject();
- int pidx = mo->indexOfProperty(property_name);
- if (pidx != -1) {
- mo->property(pidx).write(it->adaptor, value);
- return msg.createReply();
- }
+ int status = writeProperty(it->adaptor, property_name, value);
+ if (status == PropertyNotFound)
+ continue;
+ return propertyWriteReply(msg, interface_name, property_name, status);
}
} else {
QDBusAdaptorConnector::AdaptorMap::ConstIterator it;
it = qLowerBound(connector->adaptors.constBegin(), connector->adaptors.constEnd(),
interface_name);
- if (it != connector->adaptors.end() && interface_name == QLatin1String(it->interface))
- if (it->adaptor->setProperty(property_name, value))
- return msg.createReply();
+ if (it != connector->adaptors.end() && interface_name == QLatin1String(it->interface)) {
+ return propertyWriteReply(msg, interface_name, property_name,
+ writeProperty(it->adaptor, property_name, value));
+ }
}
}
if (node.flags & (QDBusConnection::ExportScriptableProperties |
QDBusConnection::ExportNonScriptableProperties)) {
// try the object itself
- int pidx = node.obj->metaObject()->indexOfProperty(property_name);
- if (pidx != -1) {
- QMetaProperty mp = node.obj->metaObject()->property(pidx);
- if ((mp.isScriptable() && (node.flags & QDBusConnection::ExportScriptableProperties)) ||
- (!mp.isScriptable() && (node.flags & QDBusConnection::ExportNonScriptableProperties)))
- if (mp.write(node.obj, value))
- return msg.createReply();
+ bool interfaceFound = true;
+ if (!interface_name.isEmpty())
+ interfaceFound = qDBusInterfaceInObject(node.obj, interface_name);
+
+ if (interfaceFound) {
+ return propertyWriteReply(msg, interface_name, property_name,
+ writeProperty(node.obj, property_name, value, node.flags));
}
}
- // the property was not found or not written to
- return qDBusPropertyError(msg, interface_name);
+ // the property was not found
+ if (!interface_name.isEmpty())
+ return interfaceNotFoundError(msg, interface_name);
+ return propertyWriteReply(msg, interface_name, property_name, PropertyNotFound);
}
// unite two QVariantMaps, but don't generate duplicate keys
@@ -385,7 +490,7 @@ QDBusMessage qDBusPropertyGetAll(const QDBusConnectionPrivate::ObjectTreeNode &n
if (!interfaceFound && !interface_name.isEmpty()) {
// the interface was not found
- return qDBusPropertyError(msg, interface_name);
+ return interfaceNotFoundError(msg, interface_name);
}
return msg.createReply(qVariantFromValue(result));
diff --git a/src/dbus/qdbusmarshaller.cpp b/src/dbus/qdbusmarshaller.cpp
index 7ada1ed..7207b4c 100644
--- a/src/dbus/qdbusmarshaller.cpp
+++ b/src/dbus/qdbusmarshaller.cpp
@@ -121,7 +121,7 @@ inline void QDBusMarshaller::append(const QDBusObjectPath &arg)
{
QByteArray data = arg.path().toUtf8();
if (!ba && data.isEmpty())
- error();
+ error(QLatin1String("Invalid object path passed in arguments"));
const char *cdata = data.constData();
qIterAppend(&iterator, ba, DBUS_TYPE_OBJECT_PATH, &cdata);
}
@@ -130,7 +130,7 @@ inline void QDBusMarshaller::append(const QDBusSignature &arg)
{
QByteArray data = arg.signature().toUtf8();
if (!ba && data.isEmpty())
- error();
+ error(QLatin1String("Invalid signature passed in arguments"));
const char *cdata = data.constData();
qIterAppend(&iterator, ba, DBUS_TYPE_SIGNATURE, &cdata);
}
@@ -161,7 +161,7 @@ inline bool QDBusMarshaller::append(const QDBusVariant &arg)
QVariant::Type id = QVariant::Type(value.userType());
if (id == QVariant::Invalid) {
qWarning("QDBusMarshaller: cannot add a null QDBusVariant");
- error();
+ error(QLatin1String("Variant containing QVariant::Invalid passed in arguments"));
return false;
}
@@ -180,7 +180,8 @@ inline bool QDBusMarshaller::append(const QDBusVariant &arg)
qWarning("QDBusMarshaller: type `%s' (%d) is not registered with D-BUS. "
"Use qDBusRegisterMetaType to register it",
QVariant::typeToName( id ), id);
- error();
+ error(QString::fromLatin1("Unregistered type %1 passed in arguments")
+ .arg(QLatin1String(QVariant::typeToName(id))));
return false;
}
@@ -220,7 +221,8 @@ inline QDBusMarshaller *QDBusMarshaller::beginArray(int id)
qWarning("QDBusMarshaller: type `%s' (%d) is not registered with D-BUS. "
"Use qDBusRegisterMetaType to register it",
QVariant::typeToName( QVariant::Type(id) ), id);
- error();
+ error(QString::fromLatin1("Unregistered type %1 passed in arguments")
+ .arg(QLatin1String(QVariant::typeToName(QVariant::Type(id)))));
return this;
}
@@ -234,22 +236,26 @@ inline QDBusMarshaller *QDBusMarshaller::beginMap(int kid, int vid)
qWarning("QDBusMarshaller: type `%s' (%d) is not registered with D-BUS. "
"Use qDBusRegisterMetaType to register it",
QVariant::typeToName( QVariant::Type(kid) ), kid);
- error();
+ error(QString::fromLatin1("Unregistered type %1 passed in arguments")
+ .arg(QLatin1String(QVariant::typeToName(QVariant::Type(kid)))));
return this;
}
if (ksignature[1] != 0 || !q_dbus_type_is_basic(*ksignature)) {
qWarning("QDBusMarshaller: type '%s' (%d) cannot be used as the key type in a D-BUS map.",
QVariant::typeToName( QVariant::Type(kid) ), kid);
- error();
+ error(QString::fromLatin1("Type %1 passed in arguments cannot be used as a key in a map")
+ .arg(QLatin1String(QVariant::typeToName(QVariant::Type(kid)))));
return this;
}
const char *vsignature = QDBusMetaType::typeToSignature( QVariant::Type(vid) );
if (!vsignature) {
+ const char *typeName = QVariant::typeToName(QVariant::Type(vid));
qWarning("QDBusMarshaller: type `%s' (%d) is not registered with D-BUS. "
"Use qDBusRegisterMetaType to register it",
- QVariant::typeToName( QVariant::Type(vid) ), vid);
- error();
+ typeName, vid);
+ error(QString::fromLatin1("Unregistered type %1 passed in arguments")
+ .arg(QLatin1String(typeName)));
return this;
}
@@ -328,11 +334,13 @@ void QDBusMarshaller::close()
}
}
-void QDBusMarshaller::error()
+void QDBusMarshaller::error(const QString &msg)
{
ok = false;
if (parent)
- parent->error();
+ parent->error(msg);
+ else
+ errorString = msg;
}
bool QDBusMarshaller::appendVariantInternal(const QVariant &arg)
@@ -340,7 +348,7 @@ bool QDBusMarshaller::appendVariantInternal(const QVariant &arg)
int id = arg.userType();
if (id == QVariant::Invalid) {
qWarning("QDBusMarshaller: cannot add an invalid QVariant");
- error();
+ error(QLatin1String("Variant containing QVariant::Invalid passed in arguments"));
return false;
}
@@ -371,7 +379,8 @@ bool QDBusMarshaller::appendVariantInternal(const QVariant &arg)
qWarning("QDBusMarshaller: type `%s' (%d) is not registered with D-BUS. "
"Use qDBusRegisterMetaType to register it",
QVariant::typeToName( QVariant::Type(id) ), id);
- error();
+ error(QString::fromLatin1("Unregistered type %1 passed in arguments")
+ .arg(QLatin1String(QVariant::typeToName(QVariant::Type(id)))));
return false;
}
@@ -388,16 +397,6 @@ bool QDBusMarshaller::appendVariantInternal(const QVariant &arg)
case DBUS_TYPE_DOUBLE:
qIterAppend(&iterator, ba, *signature, arg.constData());
return true;
-
- case DBUS_TYPE_STRING:
- case DBUS_TYPE_OBJECT_PATH:
- case DBUS_TYPE_SIGNATURE: {
- const QByteArray data =
- reinterpret_cast<const QString *>(arg.constData())->toUtf8();
- const char *rawData = data.constData();
- qIterAppend(&iterator, ba, *signature, &rawData);
- return true;
- }
#else
case DBUS_TYPE_BYTE:
append( qvariant_cast<uchar>(arg) );
@@ -426,6 +425,8 @@ bool QDBusMarshaller::appendVariantInternal(const QVariant &arg)
case DBUS_TYPE_DOUBLE:
append( arg.toDouble() );
return true;
+#endif
+
case DBUS_TYPE_STRING:
append( arg.toString() );
return true;
@@ -435,7 +436,6 @@ bool QDBusMarshaller::appendVariantInternal(const QVariant &arg)
case DBUS_TYPE_SIGNATURE:
append( qvariant_cast<QDBusSignature>(arg) );
return true;
-#endif
// compound types:
case DBUS_TYPE_VARIANT:
diff --git a/src/dbus/qdbusmessage.cpp b/src/dbus/qdbusmessage.cpp
index 9150295..78de6d9 100644
--- a/src/dbus/qdbusmessage.cpp
+++ b/src/dbus/qdbusmessage.cpp
@@ -62,7 +62,8 @@ static inline const char *data(const QByteArray &arr)
QDBusMessagePrivate::QDBusMessagePrivate()
: msg(0), reply(0), type(DBUS_MESSAGE_TYPE_INVALID),
- timeout(-1), localReply(0), ref(1), delayedReply(false), localMessage(false)
+ timeout(-1), localReply(0), ref(1), delayedReply(false), localMessage(false),
+ parametersValidated(false)
{
}
@@ -94,11 +95,17 @@ QString QDBusMessage::errorMessage() const
\internal
Constructs a DBusMessage object from this object. The returned value must be de-referenced
with q_dbus_message_unref.
+
+ The \a error object is set to indicate the error if anything went wrong with the
+ marshalling. Usually, this error message will be placed in the reply, as if the call failed.
+ The \a error pointer must not be null.
*/
-DBusMessage *QDBusMessagePrivate::toDBusMessage(const QDBusMessage &message)
+DBusMessage *QDBusMessagePrivate::toDBusMessage(const QDBusMessage &message, QDBusError *error)
{
- if (!qdbus_loadLibDBus())
+ if (!qdbus_loadLibDBus()) {
+ *error = QDBusError(QDBusError::Failed, QLatin1String("Could not open lidbus-1 library"));
return 0;
+ }
DBusMessage *msg = 0;
const QDBusMessagePrivate *d_ptr = message.d_ptr;
@@ -108,10 +115,19 @@ DBusMessage *QDBusMessagePrivate::toDBusMessage(const QDBusMessage &message)
//qDebug() << "QDBusMessagePrivate::toDBusMessage" << "message is invalid";
break;
case DBUS_MESSAGE_TYPE_METHOD_CALL:
- // only interface can be empty
- if (d_ptr->service.isEmpty() || d_ptr->path.isEmpty() || d_ptr->name.isEmpty())
- break;
- msg = q_dbus_message_new_method_call(d_ptr->service.toUtf8(), d_ptr->path.toUtf8(),
+ // only service and interface can be empty -> path and name must not be empty
+ if (!d_ptr->parametersValidated) {
+ if (!QDBusUtil::checkBusName(d_ptr->service, QDBusUtil::EmptyAllowed, error))
+ return 0;
+ if (!QDBusUtil::checkObjectPath(d_ptr->path, QDBusUtil::EmptyNotAllowed, error))
+ return 0;
+ if (!QDBusUtil::checkInterfaceName(d_ptr->interface, QDBusUtil::EmptyAllowed, error))
+ return 0;
+ if (!QDBusUtil::checkMemberName(d_ptr->name, QDBusUtil::EmptyNotAllowed, error, "method"))
+ return 0;
+ }
+
+ msg = q_dbus_message_new_method_call(data(d_ptr->service.toUtf8()), d_ptr->path.toUtf8(),
data(d_ptr->interface.toUtf8()), d_ptr->name.toUtf8());
break;
case DBUS_MESSAGE_TYPE_METHOD_RETURN:
@@ -123,8 +139,10 @@ DBusMessage *QDBusMessagePrivate::toDBusMessage(const QDBusMessage &message)
break;
case DBUS_MESSAGE_TYPE_ERROR:
// error name can't be empty
- if (d_ptr->name.isEmpty())
- break;
+ if (!d_ptr->parametersValidated
+ && !QDBusUtil::checkErrorName(d_ptr->name, QDBusUtil::EmptyNotAllowed, error))
+ return 0;
+
msg = q_dbus_message_new(DBUS_MESSAGE_TYPE_ERROR);
q_dbus_message_set_error_name(msg, d_ptr->name.toUtf8());
if (!d_ptr->localMessage) {
@@ -134,8 +152,15 @@ DBusMessage *QDBusMessagePrivate::toDBusMessage(const QDBusMessage &message)
break;
case DBUS_MESSAGE_TYPE_SIGNAL:
// nothing can be empty here
- if (d_ptr->path.isEmpty() || d_ptr->interface.isEmpty() || d_ptr->name.isEmpty())
- break;
+ if (!d_ptr->parametersValidated) {
+ if (!QDBusUtil::checkObjectPath(d_ptr->path, QDBusUtil::EmptyNotAllowed, error))
+ return 0;
+ if (!QDBusUtil::checkInterfaceName(d_ptr->interface, QDBusUtil::EmptyAllowed, error))
+ return 0;
+ if (!QDBusUtil::checkMemberName(d_ptr->name, QDBusUtil::EmptyNotAllowed, error, "method"))
+ return 0;
+ }
+
msg = q_dbus_message_new_signal(d_ptr->path.toUtf8(), d_ptr->interface.toUtf8(),
d_ptr->name.toUtf8());
break;
@@ -143,16 +168,11 @@ DBusMessage *QDBusMessagePrivate::toDBusMessage(const QDBusMessage &message)
Q_ASSERT(false);
break;
}
-#if 0
- DBusError err;
- q_dbus_error_init(&err);
- if (q_dbus_error_is_set(&err)) {
- QDBusError qe(&err);
- qDebug() << "QDBusMessagePrivate::toDBusMessage" << qe;
- }
-#endif
- if (!msg)
- return 0;
+
+ // if we got here, the parameters validated
+ // and since the message parameters cannot be changed once the message is created
+ // we can record this fact
+ d_ptr->parametersValidated = true;
QDBusMarshaller marshaller;
QVariantList::ConstIterator it = d_ptr->arguments.constBegin();
@@ -170,6 +190,7 @@ DBusMessage *QDBusMessagePrivate::toDBusMessage(const QDBusMessage &message)
// not ok;
q_dbus_message_unref(msg);
+ *error = QDBusError(QDBusError::Failed, QLatin1String("Marshalling failed: ") + marshaller.errorString);
return 0;
}
@@ -247,7 +268,13 @@ QDBusMessage QDBusMessagePrivate::makeLocal(const QDBusConnectionPrivate &conn,
// yes, we are
// we must marshall and demarshall again so as to create QDBusArgument
// entries for the complex types
- DBusMessage *message = toDBusMessage(asSent);
+ QDBusError error;
+ DBusMessage *message = toDBusMessage(asSent, &error);
+ if (!message) {
+ // failed to marshall, so it's a call error
+ return QDBusMessage::createError(error);
+ }
+
q_dbus_message_set_sender(message, conn.baseService.toUtf8());
QDBusMessage retval = fromDBusMessage(message);
@@ -466,6 +493,13 @@ QDBusMessage QDBusMessage::createErrorReply(const QString name, const QString &m
Constructs a new DBus reply message for the error type \a type using
the message \a msg. Returns the DBus message.
*/
+QDBusMessage QDBusMessage::createErrorReply(QDBusError::ErrorType atype, const QString &amsg) const
+{
+ QDBusMessage msg = createErrorReply(QDBusError::errorString(atype), amsg);
+ msg.d_ptr->parametersValidated = true;
+ return msg;
+}
+
/*!
Constructs an empty, invalid QDBusMessage object.
diff --git a/src/dbus/qdbusmessage.h b/src/dbus/qdbusmessage.h
index 55f388a..34b1635 100644
--- a/src/dbus/qdbusmessage.h
+++ b/src/dbus/qdbusmessage.h
@@ -87,8 +87,9 @@ public:
QDBusMessage createErrorReply(const QString name, const QString &msg) const;
inline QDBusMessage createErrorReply(const QDBusError &err) const
{ return createErrorReply(err.name(), err.message()); }
- inline QDBusMessage createErrorReply(QDBusError::ErrorType type, const QString &msg) const;
+ QDBusMessage createErrorReply(QDBusError::ErrorType type, const QString &msg) const;
+ // there are no setters; if this changes, see qdbusmessage_p.h
QString service() const;
QString path() const;
QString interface() const;
@@ -113,9 +114,6 @@ private:
QDBusMessagePrivate *d_ptr;
};
-inline QDBusMessage QDBusMessage::createErrorReply(QDBusError::ErrorType atype, const QString &amsg) const
-{ return createErrorReply(QDBusError::errorString(atype), amsg); }
-
#ifndef QT_NO_DEBUG_STREAM
QDBUS_EXPORT QDebug operator<<(QDebug, const QDBusMessage &);
#endif
diff --git a/src/dbus/qdbusmessage_p.h b/src/dbus/qdbusmessage_p.h
index 12a9500..b8f23dc 100644
--- a/src/dbus/qdbusmessage_p.h
+++ b/src/dbus/qdbusmessage_p.h
@@ -55,6 +55,7 @@
#include <qatomic.h>
#include <qstring.h>
+#include <qdbusmessage.h>
struct DBusMessage;
@@ -69,7 +70,11 @@ public:
~QDBusMessagePrivate();
QList<QVariant> arguments;
+
+ // the following parameters are "const": they are not changed after the constructors
+ // the parametersValidated member below controls whether they've been validated already
QString service, path, interface, name, message, signature;
+
DBusMessage *msg;
DBusMessage *reply;
int type;
@@ -79,8 +84,12 @@ public:
mutable uint delayedReply : 1;
uint localMessage : 1;
+ mutable uint parametersValidated : 1;
+
+ static void setParametersValidated(QDBusMessage &msg, bool enable)
+ { msg.d_ptr->parametersValidated = enable; }
- static DBusMessage *toDBusMessage(const QDBusMessage &message);
+ static DBusMessage *toDBusMessage(const QDBusMessage &message, QDBusError *error);
static QDBusMessage fromDBusMessage(DBusMessage *dmsg);
static bool isLocal(const QDBusMessage &msg);
diff --git a/src/dbus/qdbusmisc.cpp b/src/dbus/qdbusmisc.cpp
index e5c1da6..1b77a9b 100644
--- a/src/dbus/qdbusmisc.cpp
+++ b/src/dbus/qdbusmisc.cpp
@@ -41,12 +41,14 @@
#include <string.h>
+#include <QtCore/qcoreapplication.h>
#include <QtCore/qvariant.h>
#include <QtCore/qmetaobject.h>
#include "qdbusutil_p.h"
#include "qdbusconnection_p.h"
#include "qdbusmetatype_p.h"
+#include "qdbusabstractadaptor_p.h" // for QCLASSINFO_DBUS_*
QT_BEGIN_NAMESPACE
@@ -73,6 +75,51 @@ int qDBusNameToTypeId(const char *name)
return id;
}
+QString qDBusInterfaceFromMetaObject(const QMetaObject *mo)
+{
+ QString interface;
+
+ int idx = mo->indexOfClassInfo(QCLASSINFO_DBUS_INTERFACE);
+ if (idx >= mo->classInfoOffset()) {
+ interface = QLatin1String(mo->classInfo(idx).value());
+ } else {
+ interface = QLatin1String(mo->className());
+ interface.replace(QLatin1String("::"), QLatin1String("."));
+
+ if (interface.startsWith(QLatin1String("QDBus"))) {
+ interface.prepend(QLatin1String("com.trolltech.QtDBus."));
+ } else if (interface.startsWith(QLatin1Char('Q')) &&
+ interface.length() >= 2 && interface.at(1).isUpper()) {
+ // assume it's Qt
+ interface.prepend(QLatin1String("com.trolltech.Qt."));
+ } else if (!QCoreApplication::instance()||
+ QCoreApplication::instance()->applicationName().isEmpty()) {
+ interface.prepend(QLatin1String("local."));
+ } else {
+ interface.prepend(QLatin1Char('.')).prepend(QCoreApplication::instance()->applicationName());
+ QStringList domainName =
+ QCoreApplication::instance()->organizationDomain().split(QLatin1Char('.'),
+ QString::SkipEmptyParts);
+ if (domainName.isEmpty())
+ interface.prepend(QLatin1String("local."));
+ else
+ for (int i = 0; i < domainName.count(); ++i)
+ interface.prepend(QLatin1Char('.')).prepend(domainName.at(i));
+ }
+ }
+
+ return interface;
+}
+
+bool qDBusInterfaceInObject(QObject *obj, const QString &interface_name)
+{
+ const QMetaObject *mo = obj->metaObject();
+ for ( ; mo != &QObject::staticMetaObject; mo = mo->superClass())
+ if (interface_name == qDBusInterfaceFromMetaObject(mo))
+ return true;
+ return false;
+}
+
// calculates the metatypes for the method
// the slot must have the parameters in the following form:
// - zero or more value or const-ref parameters of any kind
diff --git a/src/dbus/qdbuspendingcall.cpp b/src/dbus/qdbuspendingcall.cpp
index 1797ed0..0ec1a26 100644
--- a/src/dbus/qdbuspendingcall.cpp
+++ b/src/dbus/qdbuspendingcall.cpp
@@ -409,6 +409,44 @@ bool QDBusPendingCall::setReplyCallback(QObject *target, const char *member)
}
#endif
+/*!
+ \since 4.6
+ Creates a QDBusPendingCall object based on the error condition
+ \a error. The resulting pending call object will be in the
+ "finished" state and QDBusPendingReply::isError() will return true.
+
+ \sa fromCompletedCall()
+*/
+QDBusPendingCall QDBusPendingCall::fromError(const QDBusError &error)
+{
+ return fromCompletedCall(QDBusMessage::createError(error));
+}
+
+/*!
+ \since 4.6
+ Creates a QDBusPendingCall object based on the message \a msg.
+ The message must be of type QDBusMessage::ErrorMessage or
+ QDBusMessage::ReplyMessage (that is, a message that is typical
+ of a completed call).
+
+ This function is useful for code that requires simulating a pending
+ call, but that has already finished.
+
+ \sa fromError()
+*/
+QDBusPendingCall QDBusPendingCall::fromCompletedCall(const QDBusMessage &msg)
+{
+ QDBusPendingCallPrivate *d = 0;
+ if (msg.type() == QDBusMessage::ErrorMessage ||
+ msg.type() == QDBusMessage::ReplyMessage) {
+ d = new QDBusPendingCallPrivate;
+ d->replyMessage = msg;
+ d->connection = 0;
+ }
+
+ return QDBusPendingCall(d);
+}
+
class QDBusPendingCallWatcherPrivate: public QObjectPrivate
{
diff --git a/src/dbus/qdbuspendingcall.h b/src/dbus/qdbuspendingcall.h
index 8881920..8dbbb3c 100644
--- a/src/dbus/qdbuspendingcall.h
+++ b/src/dbus/qdbuspendingcall.h
@@ -78,6 +78,9 @@ public:
QDBusMessage reply() const;
#endif
+ static QDBusPendingCall fromError(const QDBusError &error);
+ static QDBusPendingCall fromCompletedCall(const QDBusMessage &message);
+
protected:
QExplicitlySharedDataPointer<QDBusPendingCallPrivate> d;
friend class QDBusPendingCallPrivate;
diff --git a/src/dbus/qdbuspendingcall_p.h b/src/dbus/qdbuspendingcall_p.h
index 7136f67..5577451 100644
--- a/src/dbus/qdbuspendingcall_p.h
+++ b/src/dbus/qdbuspendingcall_p.h
@@ -63,6 +63,7 @@
QT_BEGIN_NAMESPACE
+class QDBusPendingCall;
class QDBusPendingCallWatcher;
class QDBusPendingCallWatcherHelper;
class QDBusConnectionPrivate;
@@ -94,6 +95,8 @@ public:
void waitForFinished();
void setMetaTypes(int count, const int *types);
void checkReceivedSignature();
+
+ static QDBusPendingCall fromMessage(const QDBusMessage &msg);
};
class QDBusPendingCallWatcherHelper: public QObject
diff --git a/src/dbus/qdbusutil_p.h b/src/dbus/qdbusutil_p.h
index 13031fd..5c1e4cd 100644
--- a/src/dbus/qdbusutil_p.h
+++ b/src/dbus/qdbusutil_p.h
@@ -57,6 +57,7 @@
#include <QtCore/qvariant.h>
#include <QtDBus/qdbusmacros.h>
+#include <QtDBus/qdbuserror.h>
QT_BEGIN_HEADER
@@ -83,6 +84,73 @@ namespace QDBusUtil
QDBUS_EXPORT bool isValidSingleSignature(const QString &signature);
QDBUS_EXPORT QString argumentToString(const QVariant &variant);
+
+ enum AllowEmptyFlag {
+ EmptyAllowed,
+ EmptyNotAllowed
+ };
+
+ inline bool checkInterfaceName(const QString &name, AllowEmptyFlag empty, QDBusError *error)
+ {
+ if (name.isEmpty()) {
+ if (empty == EmptyAllowed) return true;
+ *error = QDBusError(QDBusError::InvalidInterface, QLatin1String("Interface name cannot be empty"));
+ return false;
+ }
+ if (isValidInterfaceName(name)) return true;
+ *error = QDBusError(QDBusError::InvalidInterface, QString::fromLatin1("Invalid interface class: %1").arg(name));
+ return false;
+ }
+
+ inline bool checkBusName(const QString &name, AllowEmptyFlag empty, QDBusError *error)
+ {
+ if (name.isEmpty()) {
+ if (empty == EmptyAllowed) return true;
+ *error = QDBusError(QDBusError::InvalidService, QLatin1String("Service name cannot be empty"));
+ return false;
+ }
+ if (isValidBusName(name)) return true;
+ *error = QDBusError(QDBusError::InvalidService, QString::fromLatin1("Invalid service name: %1").arg(name));
+ return false;
+ }
+
+ inline bool checkObjectPath(const QString &path, AllowEmptyFlag empty, QDBusError *error)
+ {
+ if (path.isEmpty()) {
+ if (empty == EmptyAllowed) return true;
+ *error = QDBusError(QDBusError::InvalidObjectPath, QLatin1String("Object path cannot be empty"));
+ return false;
+ }
+ if (isValidObjectPath(path)) return true;
+ *error = QDBusError(QDBusError::InvalidObjectPath, QString::fromLatin1("Invalid object path: %1").arg(path));
+ return false;
+ }
+
+ inline bool checkMemberName(const QString &name, AllowEmptyFlag empty, QDBusError *error, const char *nameType = 0)
+ {
+ if (!nameType) nameType = "member";
+ if (name.isEmpty()) {
+ if (empty == EmptyAllowed) return true;
+ *error = QDBusError(QDBusError::InvalidMember, QLatin1String(nameType) + QLatin1String(" name cannot be empty"));
+ return false;
+ }
+ if (isValidMemberName(name)) return true;
+ *error = QDBusError(QDBusError::InvalidMember, QString::fromLatin1("Invalid %1 name: %2")
+ .arg(QString::fromLatin1(nameType), name));
+ return false;
+ }
+
+ inline bool checkErrorName(const QString &name, AllowEmptyFlag empty, QDBusError *error)
+ {
+ if (name.isEmpty()) {
+ if (empty == EmptyAllowed) return true;
+ *error = QDBusError(QDBusError::InvalidInterface, QLatin1String("Error name cannot be empty"));
+ return false;
+ }
+ if (isValidErrorName(name)) return true;
+ *error = QDBusError(QDBusError::InvalidInterface, QString::fromLatin1("Invalid error name: %1").arg(name));
+ return false;
+ }
}
QT_END_NAMESPACE
diff --git a/src/dbus/qdbusxmlgenerator.cpp b/src/dbus/qdbusxmlgenerator.cpp
index 82bd762..b426abd 100644
--- a/src/dbus/qdbusxmlgenerator.cpp
+++ b/src/dbus/qdbusxmlgenerator.cpp
@@ -39,7 +39,6 @@
**
****************************************************************************/
-#include <QtCore/qcoreapplication.h>
#include <QtCore/qmetaobject.h>
#include <QtCore/qstringlist.h>
@@ -232,42 +231,6 @@ static QString generateInterfaceXml(const QMetaObject *mo, int flags, int method
return retval;
}
-QString qDBusInterfaceFromMetaObject(const QMetaObject *mo)
-{
- QString interface;
-
- int idx = mo->indexOfClassInfo(QCLASSINFO_DBUS_INTERFACE);
- if (idx >= mo->classInfoOffset()) {
- interface = QLatin1String(mo->classInfo(idx).value());
- } else {
- interface = QLatin1String(mo->className());
- interface.replace(QLatin1String("::"), QLatin1String("."));
-
- if (interface.startsWith(QLatin1String("QDBus"))) {
- interface.prepend(QLatin1String("com.trolltech.QtDBus."));
- } else if (interface.startsWith(QLatin1Char('Q')) &&
- interface.length() >= 2 && interface.at(1).isUpper()) {
- // assume it's Qt
- interface.prepend(QLatin1String("com.trolltech.Qt."));
- } else if (!QCoreApplication::instance()||
- QCoreApplication::instance()->applicationName().isEmpty()) {
- interface.prepend(QLatin1String("local."));
- } else {
- interface.prepend(QLatin1Char('.')).prepend(QCoreApplication::instance()->applicationName());
- QStringList domainName =
- QCoreApplication::instance()->organizationDomain().split(QLatin1Char('.'),
- QString::SkipEmptyParts);
- if (domainName.isEmpty())
- interface.prepend(QLatin1String("local."));
- else
- for (int i = 0; i < domainName.count(); ++i)
- interface.prepend(QLatin1Char('.')).prepend(domainName.at(i));
- }
- }
-
- return interface;
- }
-
QString qDBusGenerateMetaObjectXml(QString interface, const QMetaObject *mo,
const QMetaObject *base, int flags)
{