Index: trunk/src/dbus/qdbusabstractinterface.cpp
===================================================================
--- trunk/src/dbus/qdbusabstractinterface.cpp	(revision 5)
+++ trunk/src/dbus/qdbusabstractinterface.cpp	(revision 561)
@@ -2,5 +2,6 @@
 **
 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
-** Contact: Qt Software Information (qt-info@nokia.com)
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
 **
 ** This file is part of the QtDBus module of the Qt Toolkit.
@@ -21,8 +22,7 @@
 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 **
-** In addition, as a special exception, Nokia gives you certain
-** additional rights. These rights are described in the Nokia Qt LGPL
-** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
 **
 ** GNU General Public License Usage
@@ -34,6 +34,6 @@
 ** met: http://www.gnu.org/copyleft/gpl.html.
 **
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at qt-sales@nokia.com.
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
 ** $QT_END_LICENSE$
 **
@@ -45,4 +45,5 @@
 #include "qdbusargument.h"
 #include "qdbuspendingcall.h"
+#include "qdbusmessage_p.h"
 #include "qdbusmetaobject_p.h"
 #include "qdbusmetatype_p.h"
@@ -52,4 +53,27 @@
 
 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,
@@ -58,56 +82,8 @@
                                                              const QDBusConnection& con,
                                                              bool isDynamic)
-    : connection(con), service(serv), path(p), interface(iface), isValid(true)
-{
-    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
-    }
-
+    : connection(con), service(serv), path(p), interface(iface),
+      lastError(checkIfValid(serv, p, iface, isDynamic)),
+      isValid(!lastError.isValid())
+{
     if (!isValid)
         return;
@@ -116,9 +92,7 @@
         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;
         }
@@ -126,24 +100,35 @@
 }
 
-QVariant QDBusAbstractInterfacePrivate::property(const QMetaProperty &mp) const
-{
-    if (!connection.isConnected())    // not connected
-        return QVariant();
+bool QDBusAbstractInterfacePrivate::canMakeCalls() const
+{
+    // 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;
         }
     }
@@ -153,4 +138,5 @@
                                                       QLatin1String(DBUS_INTERFACE_PROPERTIES),
                                                       QLatin1String("Get"));
+    QDBusMessagePrivate::setParametersValidated(msg, true);
     msg << interface << QString::fromUtf8(mp.name());
     QDBusMessage reply = connection.call(msg, QDBus::Block);
@@ -158,5 +144,6 @@
     if (reply.type() != QDBusMessage::ReplyMessage) {
         lastError = reply;
-        return QVariant();
+        where.clear();
+        return;
     }
     if (reply.signature() != QLatin1String("v")) {
@@ -164,5 +151,6 @@
                                        DBUS_INTERFACE_PROPERTIES);
         lastError = QDBusError(QDBusError::InvalidSignature, errmsg.arg(reply.signature()));
-        return QVariant();
+        where.clear();
+        return;
     }
 
@@ -171,6 +159,10 @@
     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>()) {
@@ -180,12 +172,7 @@
         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 {
@@ -204,11 +191,12 @@
                                       QString::fromLatin1(mp.typeName()),
                                       QString::fromLatin1(expectedSignature)));
-    return QVariant();
-}
-
-void QDBusAbstractInterfacePrivate::setProperty(const QMetaProperty &mp, const QVariant &value)
-{
-    if (!connection.isConnected())    // not connected
-        return;
+    where.clear();
+    return;
+}
+
+bool QDBusAbstractInterfacePrivate::setProperty(const QMetaProperty &mp, const QVariant &value)
+{
+    if (!isValid || !canMakeCalls())    // can't make calls
+        return false;
 
     // send the value
@@ -216,9 +204,13 @@
                                                 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;
 }
 
@@ -231,8 +223,34 @@
     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;
+}
 
 /*!
@@ -259,10 +277,18 @@
 */
 QDBusAbstractInterface::QDBusAbstractInterface(QDBusAbstractInterfacePrivate &d, QObject *parent)
-    : QObject(d, parent)
+    : QDBusAbstractInterfaceBase(d, parent)
 {
     // keep track of the service owner
-    if (d_func()->isValid)
-        QObject::connect(d_func()->connectionPrivate(), SIGNAL(serviceOwnerChanged(QString,QString,QString)),
-                         this, SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
+    if (d.isValid &&
+        d.connection.isConnected()
+        && !d.service.isEmpty()
+        && !d.service.startsWith(QLatin1Char(':')))
+        d_func()->connection.connect(QLatin1String(DBUS_SERVICE_DBUS), // service
+                                     QString(), // path
+                                     QLatin1String(DBUS_INTERFACE_DBUS), // interface
+                                     QLatin1String("NameOwnerChanged"),
+                                     QStringList() << d.service,
+                                     QString(), // signature
+                                     this, SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
 }
 
@@ -275,11 +301,19 @@
                                                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
-    if (d_func()->connection.isConnected())
-        QObject::connect(d_func()->connectionPrivate(), SIGNAL(serviceOwnerChanged(QString,QString,QString)),
-                         this, SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
+    if (d_func()->isValid &&
+        d_func()->connection.isConnected()
+        && !service.isEmpty()
+        && !service.startsWith(QLatin1Char(':')))
+        d_func()->connection.connect(QLatin1String(DBUS_SERVICE_DBUS), // service
+                                     QString(), // path
+                                     QLatin1String(DBUS_INTERFACE_DBUS), // interface
+                                     QLatin1String("NameOwnerChanged"),
+                                     QStringList() << service,
+                                     QString(), //signature
+                                     this, SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
 }
 
@@ -301,5 +335,5 @@
 bool QDBusAbstractInterface::isValid() const
 {
-    return d_func()->isValid;
+    return !d_func()->currentOwner.isEmpty();
 }
 
@@ -367,4 +401,7 @@
 {
     Q_D(QDBusAbstractInterface);
+
+    if (!d->isValid || !d->canMakeCalls())
+        return QDBusMessage::createError(d->lastError);
 
     QString m = method;
@@ -398,4 +435,5 @@
 //    qDebug() << "QDBusAbstractInterface" << "Service" << service() << "Path:" << path();
     QDBusMessage msg = QDBusMessage::createMethodCall(service(), path(), interface(), m);
+    QDBusMessagePrivate::setParametersValidated(msg, true);
     msg.setArguments(args);
 
@@ -426,5 +464,9 @@
     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);
@@ -441,5 +483,6 @@
     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
@@ -454,20 +497,24 @@
                                               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);
 }
 
@@ -493,5 +540,5 @@
                                               const QList<QVariant> &args,
                                               QObject *receiver,
-					      const char *slot)
+                                              const char *slot)
 {
     return callWithCallback(method, args, receiver, slot, 0);
@@ -504,29 +551,34 @@
 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
+    QDBusConnectionPrivate *conn = d->connectionPrivate();
+    if (conn) {
+        conn->connectRelay(d->service, d->path, d->interface,
+                           this, signal);
+    }
+}
+
+/*!
+    \internal
+    Catch signal disconnections.
+*/
+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)
-        conn->connectRelay(d->service, d->currentOwner, d->path, d->interface,
-                           this, signal);
-}
-
-/*!
-    \internal
-    Catch signal disconnections.
-*/
-void QDBusAbstractInterface::disconnectNotify(const char *signal)
-{
-    // someone disconnecting from one of our signals
-    Q_D(QDBusAbstractInterface);
-
-    QDBusConnectionPrivate *conn = d->connectionPrivate();
-    if (conn)
-        conn->disconnectRelay(d->service, d->currentOwner, d->path, d->interface,
+        conn->disconnectRelay(d->service, d->path, d->interface,
                               this, signal);
 }
@@ -541,9 +593,5 @@
     // 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);
 }
 
@@ -554,14 +602,5 @@
 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);
 }
 
