diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/corelib/kernel/qmetaobject.cpp | 23 | ||||
-rw-r--r-- | src/dbus/qdbusabstractinterface.cpp | 252 | ||||
-rw-r--r-- | src/dbus/qdbusabstractinterface.h | 18 | ||||
-rw-r--r-- | src/dbus/qdbusabstractinterface_p.h | 8 | ||||
-rw-r--r-- | src/dbus/qdbusargument_p.h | 3 | ||||
-rw-r--r-- | src/dbus/qdbusconnection_p.h | 5 | ||||
-rw-r--r-- | src/dbus/qdbuserror.cpp | 11 | ||||
-rw-r--r-- | src/dbus/qdbuserror.h | 6 | ||||
-rw-r--r-- | src/dbus/qdbusintegrator.cpp | 100 | ||||
-rw-r--r-- | src/dbus/qdbusinterface.cpp | 146 | ||||
-rw-r--r-- | src/dbus/qdbusinternalfilters.cpp | 167 | ||||
-rw-r--r-- | src/dbus/qdbusmarshaller.cpp | 35 | ||||
-rw-r--r-- | src/dbus/qdbusmessage.cpp | 78 | ||||
-rw-r--r-- | src/dbus/qdbusmessage.h | 6 | ||||
-rw-r--r-- | src/dbus/qdbusmessage_p.h | 11 | ||||
-rw-r--r-- | src/dbus/qdbusmisc.cpp | 47 | ||||
-rw-r--r-- | src/dbus/qdbuspendingcall.cpp | 36 | ||||
-rw-r--r-- | src/dbus/qdbuspendingcall.h | 3 | ||||
-rw-r--r-- | src/dbus/qdbuspendingcall_p.h | 3 | ||||
-rw-r--r-- | src/dbus/qdbusutil_p.h | 68 | ||||
-rw-r--r-- | src/dbus/qdbusxmlgenerator.cpp | 37 |
21 files changed, 755 insertions, 308 deletions
diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index 215f6ae..3184244 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -2136,8 +2136,15 @@ QVariant QMetaProperty::read(const QObject *object) const return QVariant(); } } + + // the status variable is changed by qt_metacall to indicate what it did + // this feature is currently only used by QtDBus and should not be depended + // upon. Don't change it without looking into QDBusAbstractInterface first + // -1 (unchanged): normal qt_metacall, result stored in argv[0] + // changed: result stored directly in value + int status = -1; QVariant value; - void *argv[2] = { 0, &value }; + void *argv[] = { 0, &value, &status }; if (t == QVariant::LastType) { argv[0] = &value; } else { @@ -2147,8 +2154,8 @@ QVariant QMetaProperty::read(const QObject *object) const const_cast<QObject*>(object)->qt_metacall(QMetaObject::ReadProperty, idx + mobj->propertyOffset(), argv); - if (argv[1] == 0) - // "value" was changed + + if (status != -1) return value; if (t != QVariant::LastType && argv[0] != value.data()) // pointer or reference @@ -2206,13 +2213,19 @@ bool QMetaProperty::write(QObject *object, const QVariant &value) const return false; } - void *argv[2] = { 0, &v }; + // the status variable is changed by qt_metacall to indicate what it did + // this feature is currently only used by QtDBus and should not be depended + // upon. Don't change it without looking into QDBusAbstractInterface first + // -1 (unchanged): normal qt_metacall, result stored in argv[0] + // changed: result stored directly in value, return the value of status + int status = -1; + void *argv[] = { 0, &v, &status }; if (t == QVariant::LastType) argv[0] = &v; else argv[0] = v.data(); object->qt_metacall(QMetaObject::WriteProperty, idx + mobj->propertyOffset(), argv); - return true; + return status; } /*! 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..b2d21ec 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 / 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..bb7fa6b 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; } 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..7807543 100644 --- a/src/dbus/qdbuspendingcall.cpp +++ b/src/dbus/qdbuspendingcall.cpp @@ -409,6 +409,42 @@ bool QDBusPendingCall::setReplyCallback(QObject *target, const char *member) } #endif +/*! + 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)); +} + +/*! + 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) { |