src/dbus/qdbusintegrator.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtDBus module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include <qcoreapplication.h>
       
    43 #include <qdebug.h>
       
    44 #include <qmetaobject.h>
       
    45 #include <qobject.h>
       
    46 #include <qsocketnotifier.h>
       
    47 #include <qstringlist.h>
       
    48 #include <qtimer.h>
       
    49 #include <qthread.h>
       
    50 
       
    51 #include "qdbusargument.h"
       
    52 #include "qdbusconnection_p.h"
       
    53 #include "qdbusinterface_p.h"
       
    54 #include "qdbusmessage.h"
       
    55 #include "qdbusmetatype.h"
       
    56 #include "qdbusmetatype_p.h"
       
    57 #include "qdbusabstractadaptor.h"
       
    58 #include "qdbusabstractadaptor_p.h"
       
    59 #include "qdbusutil_p.h"
       
    60 #include "qdbusmessage_p.h"
       
    61 #include "qdbuscontext_p.h"
       
    62 #include "qdbuspendingcall_p.h"
       
    63 #include "qdbusintegrator_p.h"
       
    64 
       
    65 #include "qdbusthreaddebug_p.h"
       
    66 
       
    67 QT_BEGIN_NAMESPACE
       
    68 
       
    69 static bool isDebugging;
       
    70 #define qDBusDebug              if (!::isDebugging); else qDebug
       
    71 
       
    72 static inline QDebug operator<<(QDebug dbg, const QThread *th)
       
    73 {
       
    74     dbg.nospace() << "QThread(ptr=" << (void*)th;
       
    75     if (th && !th->objectName().isEmpty())
       
    76         dbg.nospace() << ", name=" << th->objectName();
       
    77     dbg.nospace() << ')';
       
    78     return dbg.space();
       
    79 }
       
    80 
       
    81 #if QDBUS_THREAD_DEBUG
       
    82 static inline QDebug operator<<(QDebug dbg, const QDBusConnectionPrivate *conn)
       
    83 {
       
    84     dbg.nospace() << "QDBusConnection("
       
    85                   << "ptr=" << (void*)conn
       
    86                   << ", name=" << conn->name
       
    87                   << ", baseService=" << conn->baseService
       
    88                   << ", thread=";
       
    89     if (conn->thread() == QThread::currentThread())
       
    90         dbg.nospace() << "same thread";
       
    91     else
       
    92         dbg.nospace() << conn->thread();
       
    93     dbg.nospace() << ')';
       
    94     return dbg.space();
       
    95 }
       
    96 
       
    97 Q_AUTOTEST_EXPORT void qdbusDefaultThreadDebug(int action, int condition, QDBusConnectionPrivate *conn)
       
    98 {
       
    99     qDBusDebug() << QThread::currentThread()
       
   100                  << "QtDBus threading action" << action
       
   101                  << (condition == QDBusLockerBase::BeforeLock ? "before lock" :
       
   102                      condition == QDBusLockerBase::AfterLock ? "after lock" :
       
   103                      condition == QDBusLockerBase::BeforeUnlock ? "before unlock" :
       
   104                      condition == QDBusLockerBase::AfterUnlock ? "after unlock" :
       
   105                      condition == QDBusLockerBase::BeforePost ? "before event posting" :
       
   106                      condition == QDBusLockerBase::AfterPost ? "after event posting" :
       
   107                      condition == QDBusLockerBase::BeforeDeliver ? "before event delivery" :
       
   108                      condition == QDBusLockerBase::AfterDeliver ? "after event delivery" :
       
   109                      condition == QDBusLockerBase::BeforeAcquire ? "before acquire" :
       
   110                      condition == QDBusLockerBase::AfterAcquire ? "after acquire" :
       
   111                      condition == QDBusLockerBase::BeforeRelease ? "before release" :
       
   112                      condition == QDBusLockerBase::AfterRelease ? "after release" :
       
   113                      "condition unknown")
       
   114                  << "in connection" << conn;
       
   115 }
       
   116 Q_AUTOTEST_EXPORT qdbusThreadDebugFunc qdbusThreadDebug = 0;
       
   117 #endif
       
   118 
       
   119 typedef void (*QDBusSpyHook)(const QDBusMessage&);
       
   120 typedef QVarLengthArray<QDBusSpyHook, 4> QDBusSpyHookList;
       
   121 Q_GLOBAL_STATIC(QDBusSpyHookList, qDBusSpyHookList)
       
   122 
       
   123 extern "C" {
       
   124 
       
   125     // libdbus-1 callbacks
       
   126 
       
   127 static bool qDBusRealAddTimeout(QDBusConnectionPrivate *d, DBusTimeout *timeout, int ms);
       
   128 static dbus_bool_t qDBusAddTimeout(DBusTimeout *timeout, void *data)
       
   129 {
       
   130     Q_ASSERT(timeout);
       
   131     Q_ASSERT(data);
       
   132 
       
   133   //  qDebug("addTimeout %d", q_dbus_timeout_get_interval(timeout));
       
   134 
       
   135     QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
       
   136 
       
   137     if (!q_dbus_timeout_get_enabled(timeout))
       
   138         return true;
       
   139 
       
   140     QDBusWatchAndTimeoutLocker locker(AddTimeoutAction, d);
       
   141     if (QCoreApplication::instance() && QThread::currentThread() == d->thread()) {
       
   142         // correct thread
       
   143         return qDBusRealAddTimeout(d, timeout, q_dbus_timeout_get_interval(timeout));
       
   144     } else {
       
   145         // wrong thread: sync back
       
   146         QDBusConnectionCallbackEvent *ev = new QDBusConnectionCallbackEvent;
       
   147         ev->subtype = QDBusConnectionCallbackEvent::AddTimeout;
       
   148         d->timeoutsPendingAdd.append(qMakePair(timeout, q_dbus_timeout_get_interval(timeout)));
       
   149         d->postEventToThread(AddTimeoutAction, d, ev);
       
   150         return true;
       
   151     }
       
   152 }
       
   153 
       
   154 static bool qDBusRealAddTimeout(QDBusConnectionPrivate *d, DBusTimeout *timeout, int ms)
       
   155 {
       
   156     Q_ASSERT(d->timeouts.keys(timeout).isEmpty());
       
   157 
       
   158     int timerId = d->startTimer(ms);
       
   159     if (!timerId)
       
   160         return false;
       
   161 
       
   162     d->timeouts[timerId] = timeout;
       
   163     return true;
       
   164 }
       
   165 
       
   166 static void qDBusRemoveTimeout(DBusTimeout *timeout, void *data)
       
   167 {
       
   168     Q_ASSERT(timeout);
       
   169     Q_ASSERT(data);
       
   170 
       
   171   //  qDebug("removeTimeout");
       
   172 
       
   173     QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
       
   174 
       
   175     QDBusWatchAndTimeoutLocker locker(RemoveTimeoutAction, d);
       
   176 
       
   177     // is it pending addition?
       
   178     QDBusConnectionPrivate::PendingTimeoutList::iterator pit = d->timeoutsPendingAdd.begin();
       
   179     while (pit != d->timeoutsPendingAdd.end()) {
       
   180         if (pit->first == timeout)
       
   181             pit = d->timeoutsPendingAdd.erase(pit);
       
   182         else
       
   183             ++pit;
       
   184     }
       
   185 
       
   186     // is it a running timer?
       
   187     bool correctThread = QCoreApplication::instance() && QThread::currentThread() == d->thread();
       
   188     QDBusConnectionPrivate::TimeoutHash::iterator it = d->timeouts.begin();
       
   189     while (it != d->timeouts.end()) {
       
   190         if (it.value() == timeout) {
       
   191             if (correctThread) {
       
   192                 // correct thread
       
   193                 d->killTimer(it.key());
       
   194             } else {
       
   195                 // incorrect thread or no application, post an event for later
       
   196                 QDBusConnectionCallbackEvent *ev = new QDBusConnectionCallbackEvent;
       
   197                 ev->subtype = QDBusConnectionCallbackEvent::KillTimer;
       
   198                 ev->timerId = it.key();
       
   199                 d->postEventToThread(KillTimerAction, d, ev);
       
   200             }
       
   201             it = d->timeouts.erase(it);
       
   202             break;
       
   203         } else {
       
   204             ++it;
       
   205         }
       
   206     }
       
   207 }
       
   208 
       
   209 static void qDBusToggleTimeout(DBusTimeout *timeout, void *data)
       
   210 {
       
   211     Q_ASSERT(timeout);
       
   212     Q_ASSERT(data);
       
   213 
       
   214     //qDebug("ToggleTimeout");
       
   215 
       
   216     qDBusRemoveTimeout(timeout, data);
       
   217     qDBusAddTimeout(timeout, data);
       
   218 }
       
   219 
       
   220 static bool qDBusRealAddWatch(QDBusConnectionPrivate *d, DBusWatch *watch, int flags, int fd);
       
   221 static dbus_bool_t qDBusAddWatch(DBusWatch *watch, void *data)
       
   222 {
       
   223     Q_ASSERT(watch);
       
   224     Q_ASSERT(data);
       
   225 
       
   226     QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
       
   227 
       
   228     int flags = q_dbus_watch_get_flags(watch);
       
   229     int fd = q_dbus_watch_get_fd(watch);
       
   230 
       
   231     if (QCoreApplication::instance() && QThread::currentThread() == d->thread()) {
       
   232         return qDBusRealAddWatch(d, watch, flags, fd);
       
   233     } else {
       
   234         QDBusConnectionCallbackEvent *ev = new QDBusConnectionCallbackEvent;
       
   235         ev->subtype = QDBusConnectionCallbackEvent::AddWatch;
       
   236         ev->watch = watch;
       
   237         ev->fd = fd;
       
   238         ev->extra = flags;
       
   239         d->postEventToThread(AddWatchAction, d, ev);
       
   240         return true;
       
   241     }
       
   242 }
       
   243 
       
   244 static bool qDBusRealAddWatch(QDBusConnectionPrivate *d, DBusWatch *watch, int flags, int fd)
       
   245 {
       
   246     QDBusConnectionPrivate::Watcher watcher;
       
   247 
       
   248     QDBusWatchAndTimeoutLocker locker(AddWatchAction, d);
       
   249     if (flags & DBUS_WATCH_READABLE) {
       
   250         //qDebug("addReadWatch %d", fd);
       
   251         watcher.watch = watch;
       
   252         if (QCoreApplication::instance()) {
       
   253             watcher.read = new QSocketNotifier(fd, QSocketNotifier::Read, d);
       
   254             watcher.read->setEnabled(q_dbus_watch_get_enabled(watch));
       
   255             d->connect(watcher.read, SIGNAL(activated(int)), SLOT(socketRead(int)));
       
   256         }
       
   257     }
       
   258     if (flags & DBUS_WATCH_WRITABLE) {
       
   259         //qDebug("addWriteWatch %d", fd);
       
   260         watcher.watch = watch;
       
   261         if (QCoreApplication::instance()) {
       
   262             watcher.write = new QSocketNotifier(fd, QSocketNotifier::Write, d);
       
   263             watcher.write->setEnabled(q_dbus_watch_get_enabled(watch));
       
   264             d->connect(watcher.write, SIGNAL(activated(int)), SLOT(socketWrite(int)));
       
   265         }
       
   266     }
       
   267     d->watchers.insertMulti(fd, watcher);
       
   268 
       
   269     return true;
       
   270 }
       
   271 
       
   272 static void qDBusRemoveWatch(DBusWatch *watch, void *data)
       
   273 {
       
   274     Q_ASSERT(watch);
       
   275     Q_ASSERT(data);
       
   276 
       
   277     //qDebug("remove watch");
       
   278 
       
   279     QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
       
   280     int fd = q_dbus_watch_get_fd(watch);
       
   281 
       
   282     QDBusWatchAndTimeoutLocker locker(RemoveWatchAction, d);
       
   283     QDBusConnectionPrivate::WatcherHash::iterator i = d->watchers.find(fd);
       
   284     while (i != d->watchers.end() && i.key() == fd) {
       
   285         if (i.value().watch == watch) {
       
   286             if (QCoreApplication::instance() && QThread::currentThread() == d->thread()) {
       
   287                 // correct thread, delete the socket notifiers
       
   288                 delete i.value().read;
       
   289                 delete i.value().write;
       
   290             } else {
       
   291                 // incorrect thread or no application, use delete later
       
   292                 if (i->read)
       
   293                     i->read->deleteLater();
       
   294                 if (i->write)
       
   295                     i->write->deleteLater();
       
   296             }
       
   297             i = d->watchers.erase(i);
       
   298         } else {
       
   299             ++i;
       
   300         }
       
   301     }
       
   302 }
       
   303 
       
   304 static void qDBusRealToggleWatch(QDBusConnectionPrivate *d, DBusWatch *watch, int fd);
       
   305 static void qDBusToggleWatch(DBusWatch *watch, void *data)
       
   306 {
       
   307     Q_ASSERT(watch);
       
   308     Q_ASSERT(data);
       
   309 
       
   310     QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
       
   311     int fd = q_dbus_watch_get_fd(watch);
       
   312 
       
   313     if (QCoreApplication::instance() && QThread::currentThread() == d->thread()) {
       
   314         qDBusRealToggleWatch(d, watch, fd);
       
   315     } else {
       
   316         QDBusConnectionCallbackEvent *ev = new QDBusConnectionCallbackEvent;
       
   317         ev->subtype = QDBusConnectionCallbackEvent::ToggleWatch;
       
   318         ev->watch = watch;
       
   319         ev->fd = fd;
       
   320         d->postEventToThread(ToggleWatchAction, d, ev);
       
   321     }
       
   322 }
       
   323 
       
   324 static void qDBusRealToggleWatch(QDBusConnectionPrivate *d, DBusWatch *watch, int fd)
       
   325 {
       
   326     QDBusWatchAndTimeoutLocker locker(ToggleWatchAction, d);
       
   327 
       
   328     QDBusConnectionPrivate::WatcherHash::iterator i = d->watchers.find(fd);
       
   329     while (i != d->watchers.end() && i.key() == fd) {
       
   330         if (i.value().watch == watch) {
       
   331             bool enabled = q_dbus_watch_get_enabled(watch);
       
   332             int flags = q_dbus_watch_get_flags(watch);
       
   333 
       
   334             //qDebug("toggle watch %d to %d (write: %d, read: %d)", q_dbus_watch_get_fd(watch), enabled, flags & DBUS_WATCH_WRITABLE, flags & DBUS_WATCH_READABLE);
       
   335 
       
   336             if (flags & DBUS_WATCH_READABLE && i.value().read)
       
   337                 i.value().read->setEnabled(enabled);
       
   338             if (flags & DBUS_WATCH_WRITABLE && i.value().write)
       
   339                 i.value().write->setEnabled(enabled);
       
   340             return;
       
   341         }
       
   342         ++i;
       
   343     }
       
   344 }
       
   345 
       
   346 static void qDBusUpdateDispatchStatus(DBusConnection *connection, DBusDispatchStatus new_status, void *data)
       
   347 {
       
   348     Q_ASSERT(connection);
       
   349     Q_UNUSED(connection);
       
   350     QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
       
   351 
       
   352     static int slotId; // 0 is QObject::deleteLater()
       
   353     if (!slotId) {
       
   354         // it's ok to do this: there's no race condition because the store is atomic
       
   355         // and we always set to the same value
       
   356         slotId = QDBusConnectionPrivate::staticMetaObject.indexOfSlot("doDispatch()");
       
   357     }
       
   358 
       
   359     //qDBusDebug() << "Updating dispatcher status" << slotId;
       
   360     if (new_status == DBUS_DISPATCH_DATA_REMAINS)
       
   361         QDBusConnectionPrivate::staticMetaObject.method(slotId).
       
   362             invoke(d, Qt::QueuedConnection);
       
   363 }
       
   364 
       
   365 static void qDBusNewConnection(DBusServer *server, DBusConnection *connection, void *data)
       
   366 {
       
   367     // ### We may want to separate the server from the QDBusConnectionPrivate    
       
   368     Q_ASSERT(server); Q_UNUSED(server);
       
   369     Q_ASSERT(connection);
       
   370     Q_ASSERT(data);
       
   371 
       
   372     // keep the connection alive
       
   373     q_dbus_connection_ref(connection);
       
   374     QDBusConnectionPrivate *d = new QDBusConnectionPrivate;
       
   375     
       
   376     // setConnection does the error handling for us
       
   377     QDBusErrorInternal error;
       
   378     d->setPeer(connection, error);
       
   379 
       
   380     QDBusConnection retval = QDBusConnectionPrivate::q(d);
       
   381     d->setBusService(retval);
       
   382 
       
   383     //d->name = QString::number(reinterpret_cast<int>(d));
       
   384     //d->setConnection(d->name, d); 
       
   385 
       
   386     // make QDBusServer emit the newConnection signal
       
   387     QDBusConnectionPrivate *server_d = static_cast<QDBusConnectionPrivate *>(data);
       
   388     server_d->serverConnection(retval);
       
   389 }
       
   390 
       
   391 } // extern "C"
       
   392 
       
   393 static QByteArray buildMatchRule(const QString &service, const QString & /*owner*/,
       
   394                                  const QString &objectPath, const QString &interface,
       
   395                                  const QString &member, const QString & /*signature*/)
       
   396 {
       
   397     QString result = QLatin1String("type='signal',");
       
   398     QString keyValue = QLatin1String("%1='%2',");
       
   399 
       
   400     if (!service.isEmpty())
       
   401         result += keyValue.arg(QLatin1String("sender"), service);
       
   402     if (!objectPath.isEmpty())
       
   403         result += keyValue.arg(QLatin1String("path"), objectPath);
       
   404     if (!interface.isEmpty())
       
   405         result += keyValue.arg(QLatin1String("interface"), interface);
       
   406     if (!member.isEmpty())
       
   407         result += keyValue.arg(QLatin1String("member"), member);
       
   408 
       
   409     result.chop(1);             // remove ending comma
       
   410     return result.toLatin1();
       
   411 }
       
   412 
       
   413 static bool findObject(const QDBusConnectionPrivate::ObjectTreeNode *root,
       
   414                        const QString &fullpath, int &usedLength,
       
   415                        QDBusConnectionPrivate::ObjectTreeNode &result)
       
   416 {
       
   417     int start = 0;
       
   418     int length = fullpath.length();
       
   419     if (fullpath.at(0) == QLatin1Char('/'))
       
   420         start = 1;
       
   421 
       
   422     // walk the object tree
       
   423     const QDBusConnectionPrivate::ObjectTreeNode *node = root;
       
   424     while (start < length && node && !(node->flags & QDBusConnection::ExportChildObjects)) {
       
   425         int end = fullpath.indexOf(QLatin1Char('/'), start);
       
   426         end = (end == -1 ? length : end);
       
   427         QStringRef pathComponent(&fullpath, start, end - start);
       
   428 
       
   429         QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator it =
       
   430             qLowerBound(node->children.constBegin(), node->children.constEnd(), pathComponent);
       
   431         if (it != node->children.constEnd() && it->name == pathComponent)
       
   432             // match
       
   433             node = it;
       
   434         else
       
   435             node = 0;
       
   436 
       
   437         start = end + 1;
       
   438     }
       
   439 
       
   440     // found our object
       
   441     usedLength = (start > length ? length : start);
       
   442     if (node) {
       
   443         if (node->obj || !node->children.isEmpty())
       
   444             result = *node;
       
   445         else
       
   446             // there really is no object here
       
   447             // we're just looking at an unused space in the QVector
       
   448             node = 0;
       
   449     }
       
   450     return node;
       
   451 }
       
   452 
       
   453 static QObject *findChildObject(const QDBusConnectionPrivate::ObjectTreeNode *root,
       
   454                                 const QString &fullpath, int start)
       
   455 {
       
   456     int length = fullpath.length();
       
   457 
       
   458     // any object in the tree can tell us to switch to its own object tree:
       
   459     const QDBusConnectionPrivate::ObjectTreeNode *node = root;
       
   460     if (node && node->flags & QDBusConnection::ExportChildObjects) {
       
   461         QObject *obj = node->obj;
       
   462 
       
   463         while (obj) {
       
   464             if (start >= length)
       
   465                 // we're at the correct level
       
   466                 return obj;
       
   467 
       
   468             int pos = fullpath.indexOf(QLatin1Char('/'), start);
       
   469             pos = (pos == -1 ? length : pos);
       
   470             QStringRef pathComponent(&fullpath, start, pos - start);
       
   471 
       
   472             const QObjectList children = obj->children();
       
   473 
       
   474             // find a child with the proper name
       
   475             QObject *next = 0;
       
   476             QObjectList::ConstIterator it = children.constBegin();
       
   477             QObjectList::ConstIterator end = children.constEnd();
       
   478             for ( ; it != end; ++it)
       
   479                 if ((*it)->objectName() == pathComponent) {
       
   480                     next = *it;
       
   481                     break;
       
   482                 }
       
   483 
       
   484             if (!next)
       
   485                 break;
       
   486 
       
   487             obj = next;
       
   488             start = pos + 1;
       
   489         }
       
   490     }
       
   491 
       
   492     // object not found
       
   493     return 0;
       
   494 }
       
   495 
       
   496 extern QDBUS_EXPORT void qDBusAddSpyHook(QDBusSpyHook);
       
   497 void qDBusAddSpyHook(QDBusSpyHook hook)
       
   498 {
       
   499     qDBusSpyHookList()->append(hook);
       
   500 }
       
   501 
       
   502 extern "C" {
       
   503 static DBusHandlerResult
       
   504 qDBusSignalFilter(DBusConnection *connection, DBusMessage *message, void *data)
       
   505 {
       
   506     Q_ASSERT(data);
       
   507     Q_UNUSED(connection);
       
   508     QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
       
   509     if (d->mode == QDBusConnectionPrivate::InvalidMode)
       
   510         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
       
   511 
       
   512     QDBusMessage amsg = QDBusMessagePrivate::fromDBusMessage(message);
       
   513     qDBusDebug() << QThread::currentThread() << "got message:" << amsg;
       
   514 
       
   515     return d->handleMessage(amsg) ?
       
   516         DBUS_HANDLER_RESULT_HANDLED :
       
   517         DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
       
   518 }
       
   519 }
       
   520 
       
   521 bool QDBusConnectionPrivate::handleMessage(const QDBusMessage &amsg)
       
   522 {
       
   523     const QDBusSpyHookList *list = qDBusSpyHookList();
       
   524     for (int i = 0; i < list->size(); ++i) {
       
   525         qDBusDebug() << "calling the message spy hook";
       
   526         (*(*list)[i])(amsg);
       
   527     }
       
   528 
       
   529     switch (amsg.type()) {
       
   530     case QDBusMessage::SignalMessage:
       
   531         handleSignal(amsg);
       
   532         return true;
       
   533         break;
       
   534     case QDBusMessage::MethodCallMessage:
       
   535         handleObjectCall(amsg);
       
   536         return true;
       
   537     case QDBusMessage::ReplyMessage:
       
   538     case QDBusMessage::ErrorMessage:
       
   539         return false;           // we don't handle those here
       
   540     case QDBusMessage::InvalidMessage:
       
   541         Q_ASSERT_X(false, "QDBusConnection", "Invalid message found when processing");
       
   542         break;
       
   543     }
       
   544 
       
   545     return false;
       
   546 }
       
   547 
       
   548 static void huntAndDestroy(QObject *needle, QDBusConnectionPrivate::ObjectTreeNode &haystack)
       
   549 {
       
   550     QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator it = haystack.children.begin();
       
   551     QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator end = haystack.children.end();
       
   552     for ( ; it != end; ++it)
       
   553         huntAndDestroy(needle, *it);
       
   554 
       
   555     if (needle == haystack.obj) {
       
   556         haystack.obj = 0;
       
   557         haystack.flags = 0;
       
   558     }
       
   559 }
       
   560 
       
   561 static void huntAndEmit(DBusConnection *connection, DBusMessage *msg,
       
   562                         QObject *needle, const QDBusConnectionPrivate::ObjectTreeNode &haystack,
       
   563                         bool isScriptable, bool isAdaptor, const QString &path = QString())
       
   564 {
       
   565     QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator it = haystack.children.constBegin();
       
   566     QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator end = haystack.children.constEnd();
       
   567     for ( ; it != end; ++it)
       
   568         huntAndEmit(connection, msg, needle, *it, isScriptable, isAdaptor, path + QLatin1Char('/') + it->name);
       
   569 
       
   570     if (needle == haystack.obj) {
       
   571         // is this a signal we should relay?
       
   572         if (isAdaptor && (haystack.flags & QDBusConnection::ExportAdaptors) == 0)
       
   573             return;             // no: it comes from an adaptor and we're not exporting adaptors
       
   574         else if (!isAdaptor) {
       
   575             int mask = isScriptable
       
   576                        ? QDBusConnection::ExportScriptableSignals
       
   577                        : QDBusConnection::ExportNonScriptableSignals;
       
   578             if ((haystack.flags & mask) == 0)
       
   579                 return;         // signal was not exported
       
   580         }
       
   581 
       
   582         QByteArray p = path.toLatin1();
       
   583         if (p.isEmpty())
       
   584             p = "/";
       
   585         qDBusDebug() << QThread::currentThread() << "emitting signal at" << p;
       
   586         DBusMessage *msg2 = q_dbus_message_copy(msg);
       
   587         q_dbus_message_set_path(msg2, p);
       
   588         q_dbus_connection_send(connection, msg2, 0);
       
   589         q_dbus_message_unref(msg2);
       
   590     }
       
   591 }
       
   592 
       
   593 static int findSlot(const QMetaObject *mo, const QByteArray &name, int flags,
       
   594                     const QString &signature_, QList<int>& metaTypes)
       
   595 {
       
   596     QByteArray msgSignature = signature_.toLatin1();
       
   597 
       
   598     for (int idx = mo->methodCount() - 1 ; idx >= QObject::staticMetaObject.methodCount(); --idx) {
       
   599         QMetaMethod mm = mo->method(idx);
       
   600 
       
   601         // check access:
       
   602         if (mm.access() != QMetaMethod::Public)
       
   603             continue;
       
   604 
       
   605         // check type:
       
   606         if (mm.methodType() != QMetaMethod::Slot)
       
   607             continue;
       
   608 
       
   609         // check name:
       
   610         QByteArray slotname = mm.signature();
       
   611         int paren = slotname.indexOf('(');
       
   612         if (paren != name.length() || !slotname.startsWith(name))
       
   613             continue;
       
   614 
       
   615         int returnType = qDBusNameToTypeId(mm.typeName());
       
   616         bool isAsync = qDBusCheckAsyncTag(mm.tag());
       
   617         bool isScriptable = mm.attributes() & QMetaMethod::Scriptable;
       
   618 
       
   619         // consistency check:
       
   620         if (isAsync && returnType != QMetaType::Void)
       
   621             continue;
       
   622 
       
   623         int inputCount = qDBusParametersForMethod(mm, metaTypes);
       
   624         if (inputCount == -1)
       
   625             continue;           // problem parsing
       
   626 
       
   627         metaTypes[0] = returnType;
       
   628         bool hasMessage = false;
       
   629         if (inputCount > 0 &&
       
   630             metaTypes.at(inputCount) == QDBusMetaTypeId::message) {
       
   631             // "no input parameters" is allowed as long as the message meta type is there
       
   632             hasMessage = true;
       
   633             --inputCount;
       
   634         }
       
   635 
       
   636         // try to match the parameters
       
   637         int i;
       
   638         QByteArray reconstructedSignature;
       
   639         for (i = 1; i <= inputCount; ++i) {
       
   640             const char *typeSignature = QDBusMetaType::typeToSignature( metaTypes.at(i) );
       
   641             if (!typeSignature)
       
   642                 break;          // invalid
       
   643 
       
   644             reconstructedSignature += typeSignature;
       
   645             if (!msgSignature.startsWith(reconstructedSignature))
       
   646                 break;
       
   647         }
       
   648 
       
   649         if (reconstructedSignature != msgSignature)
       
   650             continue;           // we didn't match them all
       
   651 
       
   652         if (hasMessage)
       
   653             ++i;
       
   654 
       
   655         // make sure that the output parameters have signatures too
       
   656         if (returnType != 0 && QDBusMetaType::typeToSignature(returnType) == 0)
       
   657             continue;
       
   658 
       
   659         bool ok = true;
       
   660         for (int j = i; ok && j < metaTypes.count(); ++j)
       
   661             if (QDBusMetaType::typeToSignature(metaTypes.at(i)) == 0)
       
   662                 ok = false;
       
   663         if (!ok)
       
   664             continue;
       
   665 
       
   666         // consistency check:
       
   667         if (isAsync && metaTypes.count() > i + 1)
       
   668             continue;
       
   669 
       
   670         if (isScriptable && (flags & QDBusConnection::ExportScriptableSlots) == 0)
       
   671             continue;           // not exported
       
   672         if (!isScriptable && (flags & QDBusConnection::ExportNonScriptableSlots) == 0)
       
   673             continue;           // not exported
       
   674 
       
   675         // if we got here, this slot matched
       
   676         return idx;
       
   677     }
       
   678 
       
   679     // no slot matched
       
   680     return -1;
       
   681 }
       
   682 
       
   683 QDBusCallDeliveryEvent* QDBusConnectionPrivate::prepareReply(QDBusConnectionPrivate *target,
       
   684                                                              QObject *object, int idx,
       
   685                                                              const QList<int> &metaTypes,
       
   686                                                              const QDBusMessage &msg)
       
   687 {
       
   688     Q_ASSERT(object);
       
   689     Q_UNUSED(object);
       
   690 
       
   691     int n = metaTypes.count() - 1;
       
   692     if (metaTypes[n] == QDBusMetaTypeId::message)
       
   693         --n;
       
   694 
       
   695     // check that types match
       
   696     for (int i = 0; i < n; ++i)
       
   697         if (metaTypes.at(i + 1) != msg.arguments().at(i).userType() &&
       
   698             msg.arguments().at(i).userType() != qMetaTypeId<QDBusArgument>())
       
   699             return 0;           // no match
       
   700 
       
   701     // we can deliver
       
   702     // prepare for the call
       
   703     return new QDBusCallDeliveryEvent(QDBusConnection(target), idx, target, msg, metaTypes);
       
   704 }
       
   705 
       
   706 void QDBusConnectionPrivate::activateSignal(const QDBusConnectionPrivate::SignalHook& hook,
       
   707                                             const QDBusMessage &msg)
       
   708 {
       
   709     // This is called by QDBusConnectionPrivate::handleSignal to deliver a signal
       
   710     // that was received from D-Bus
       
   711     //
       
   712     // Signals are delivered to slots if the parameters match
       
   713     // Slots can have less parameters than there are on the message
       
   714     // Slots can optionally have one final parameter that is a QDBusMessage
       
   715     // Slots receive read-only copies of the message (i.e., pass by value or by const-ref)
       
   716     QDBusCallDeliveryEvent *call = prepareReply(this, hook.obj, hook.midx, hook.params, msg);
       
   717     if (call)
       
   718         postEventToThread(ActivateSignalAction, hook.obj, call);
       
   719 }
       
   720 
       
   721 bool QDBusConnectionPrivate::activateCall(QObject* object, int flags, const QDBusMessage &msg)
       
   722 {
       
   723     // This is called by QDBusConnectionPrivate::handleObjectCall to place a call
       
   724     // to a slot on the object.
       
   725     //
       
   726     // The call is delivered to the first slot that matches the following conditions:
       
   727     //  - has the same name as the message's target member
       
   728     //  - ALL of the message's types are found in slot's parameter list
       
   729     //  - optionally has one more parameter of type QDBusMessage
       
   730     // If none match, then the slot of the same name as the message target and with
       
   731     // the first type of QDBusMessage is delivered.
       
   732     //
       
   733     // The D-Bus specification requires that all MethodCall messages be replied to, unless the
       
   734     // caller specifically waived this requirement. This means that we inspect if the user slot
       
   735     // generated a reply and, if it didn't, we will. Obviously, if the user slot doesn't take a
       
   736     // QDBusMessage parameter, it cannot generate a reply.
       
   737     //
       
   738     // When a return message is generated, the slot's return type, if any, will be placed
       
   739     // in the message's first position. If there are non-const reference parameters to the
       
   740     // slot, they must appear at the end and will be placed in the subsequent message
       
   741     // positions.
       
   742 
       
   743     static const char cachePropertyName[] = "_qdbus_slotCache";
       
   744 
       
   745     if (!object)
       
   746         return false;
       
   747 
       
   748     Q_ASSERT_X(QThread::currentThread() == object->thread(),
       
   749                "QDBusConnection: internal threading error",
       
   750                "function called for an object that is in another thread!!");
       
   751 
       
   752     QDBusSlotCache slotCache =
       
   753         qvariant_cast<QDBusSlotCache>(object->property(cachePropertyName));
       
   754     QString cacheKey = msg.member(), signature = msg.signature();
       
   755     if (!signature.isEmpty()) {
       
   756         cacheKey.reserve(cacheKey.length() + 1 + signature.length());
       
   757         cacheKey += QLatin1Char('.');
       
   758         cacheKey += signature;
       
   759     }
       
   760 
       
   761     QDBusSlotCache::Hash::ConstIterator cacheIt = slotCache.hash.constFind(cacheKey);
       
   762     while (cacheIt != slotCache.hash.constEnd() && cacheIt->flags != flags &&
       
   763            cacheIt.key() == cacheKey)
       
   764         ++cacheIt;
       
   765     if (cacheIt == slotCache.hash.constEnd() || cacheIt.key() != cacheKey)
       
   766     {
       
   767         // not cached, analyse the meta object
       
   768         const QMetaObject *mo = object->metaObject();
       
   769         QByteArray memberName = msg.member().toUtf8();
       
   770 
       
   771         // find a slot that matches according to the rules above
       
   772         QDBusSlotCache::Data slotData;
       
   773         slotData.flags = flags;
       
   774         slotData.slotIdx = ::findSlot(mo, memberName, flags, msg.signature(), slotData.metaTypes);
       
   775         if (slotData.slotIdx == -1) {
       
   776             // ### this is where we want to add the connection as an arg too
       
   777             // try with no parameters, but with a QDBusMessage
       
   778             slotData.slotIdx = ::findSlot(mo, memberName, flags, QString(), slotData.metaTypes);
       
   779             if (slotData.metaTypes.count() != 2 ||
       
   780                 slotData.metaTypes.at(1) != QDBusMetaTypeId::message) {
       
   781                 // not found
       
   782                 // save the negative lookup
       
   783                 slotData.slotIdx = -1;
       
   784                 slotData.metaTypes.clear();
       
   785                 slotCache.hash.insert(cacheKey, slotData);
       
   786                 object->setProperty(cachePropertyName, qVariantFromValue(slotCache));
       
   787                 return false;
       
   788             }
       
   789         }
       
   790 
       
   791         // save to the cache
       
   792         slotCache.hash.insert(cacheKey, slotData);
       
   793         object->setProperty(cachePropertyName, qVariantFromValue(slotCache));
       
   794 
       
   795         // found the slot to be called
       
   796         deliverCall(object, flags, msg, slotData.metaTypes, slotData.slotIdx);
       
   797         return true;
       
   798     } else if (cacheIt->slotIdx == -1) {
       
   799         // negative cache
       
   800         return false;
       
   801     } else {
       
   802         // use the cache
       
   803         deliverCall(object, flags, msg, cacheIt->metaTypes, cacheIt->slotIdx);
       
   804         return true;
       
   805     }
       
   806 }
       
   807 
       
   808 void QDBusConnectionPrivate::deliverCall(QObject *object, int /*flags*/, const QDBusMessage &msg,
       
   809                                          const QList<int> &metaTypes, int slotIdx)
       
   810 {
       
   811     Q_ASSERT_X(!object || QThread::currentThread() == object->thread(),
       
   812                "QDBusConnection: internal threading error",
       
   813                "function called for an object that is in another thread!!");
       
   814 
       
   815     QVarLengthArray<void *, 10> params;
       
   816     params.reserve(metaTypes.count());
       
   817 
       
   818     QVariantList auxParameters;
       
   819     // let's create the parameter list
       
   820 
       
   821     // first one is the return type -- add it below
       
   822     params.append(0);
       
   823 
       
   824     // add the input parameters
       
   825     int i;
       
   826     int pCount = qMin(msg.arguments().count(), metaTypes.count() - 1);
       
   827     for (i = 1; i <= pCount; ++i) {
       
   828         int id = metaTypes[i];
       
   829         if (id == QDBusMetaTypeId::message)
       
   830             break;
       
   831 
       
   832         const QVariant &arg = msg.arguments().at(i - 1);
       
   833         if (arg.userType() == id)
       
   834             // no conversion needed
       
   835             params.append(const_cast<void *>(arg.constData()));
       
   836         else if (arg.userType() == qMetaTypeId<QDBusArgument>()) {
       
   837             // convert to what the function expects
       
   838             void *null = 0;
       
   839             auxParameters.append(QVariant(id, null));
       
   840 
       
   841             const QDBusArgument &in =
       
   842                 *reinterpret_cast<const QDBusArgument *>(arg.constData());
       
   843             QVariant &out = auxParameters[auxParameters.count() - 1];
       
   844 
       
   845             if (!QDBusMetaType::demarshall(in, out.userType(), out.data()))
       
   846                 qFatal("Internal error: demarshalling function for type '%s' (%d) failed!",
       
   847                        out.typeName(), out.userType());
       
   848 
       
   849             params.append(const_cast<void *>(out.constData()));
       
   850         } else {
       
   851             qFatal("Internal error: got invalid meta type %d (%s) "
       
   852                    "when trying to convert to meta type %d (%s)",
       
   853                    arg.userType(), QMetaType::typeName(arg.userType()),
       
   854                    id, QMetaType::typeName(id));
       
   855         }
       
   856     }
       
   857 
       
   858     bool takesMessage = false;
       
   859     if (metaTypes.count() > i && metaTypes[i] == QDBusMetaTypeId::message) {
       
   860         params.append(const_cast<void*>(static_cast<const void*>(&msg)));
       
   861         takesMessage = true;
       
   862         ++i;
       
   863     }
       
   864 
       
   865     // output arguments
       
   866     QVariantList outputArgs;
       
   867     void *null = 0;
       
   868     if (metaTypes[0] != QMetaType::Void) {
       
   869         QVariant arg(metaTypes[0], null);
       
   870         outputArgs.append( arg );
       
   871         params[0] = const_cast<void*>(outputArgs.at( outputArgs.count() - 1 ).constData());
       
   872     }
       
   873     for ( ; i < metaTypes.count(); ++i) {
       
   874         QVariant arg(metaTypes[i], null);
       
   875         outputArgs.append( arg );
       
   876         params.append(const_cast<void*>(outputArgs.at( outputArgs.count() - 1 ).constData()));
       
   877     }
       
   878 
       
   879     // make call:
       
   880     bool fail;
       
   881     if (!object) {
       
   882         fail = true;
       
   883     } else {
       
   884         // FIXME: save the old sender!
       
   885         QDBusContextPrivate context(QDBusConnection(this), msg);
       
   886         QDBusContextPrivate *old = QDBusContextPrivate::set(object, &context);
       
   887         QDBusConnectionPrivate::setSender(this);
       
   888 
       
   889         QPointer<QObject> ptr = object;
       
   890         fail = object->qt_metacall(QMetaObject::InvokeMetaMethod,
       
   891                                    slotIdx, params.data()) >= 0;
       
   892         QDBusConnectionPrivate::setSender(0);
       
   893 	// the object might be deleted in the slot
       
   894 	if (!ptr.isNull())
       
   895 	    QDBusContextPrivate::set(object, old);
       
   896     }
       
   897 
       
   898     // do we create a reply? Only if the caller is waiting for a reply and one hasn't been sent
       
   899     // yet.
       
   900     if (msg.isReplyRequired() && !msg.isDelayedReply()) {
       
   901         if (!fail) {
       
   902             // normal reply
       
   903             qDBusDebug() << QThread::currentThread() << "Automatically sending reply:" << outputArgs;
       
   904             send(msg.createReply(outputArgs));
       
   905         } else {
       
   906             // generate internal error
       
   907             qWarning("Internal error: Failed to deliver message");
       
   908             send(msg.createErrorReply(QDBusError::InternalError,
       
   909                                       QLatin1String("Failed to deliver message")));
       
   910         }
       
   911     }
       
   912 
       
   913     return;
       
   914 }
       
   915 
       
   916 extern bool qDBusInitThreads();
       
   917 
       
   918 QDBusConnectionPrivate::QDBusConnectionPrivate(QObject *p)
       
   919     : QObject(p), ref(1), mode(InvalidMode), connection(0), server(0), busService(0),
       
   920       watchAndTimeoutLock(QMutex::Recursive),
       
   921       rootNode(QString(QLatin1Char('/')))
       
   922 {
       
   923     static const bool threads = q_dbus_threads_init_default();
       
   924     static const int debugging = ::isDebugging = qgetenv("QDBUS_DEBUG").toInt();
       
   925     Q_UNUSED(threads)
       
   926     Q_UNUSED(debugging)
       
   927 
       
   928 #ifdef QDBUS_THREAD_DEBUG
       
   929     if (debugging > 1)
       
   930         qdbusThreadDebug = qdbusDefaultThreadDebug;
       
   931 #endif
       
   932 
       
   933     QDBusMetaTypeId::init();
       
   934 
       
   935     rootNode.flags = 0;
       
   936 
       
   937     connect(this, SIGNAL(serviceOwnerChanged(QString,QString,QString)),
       
   938             this, SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
       
   939 }
       
   940 
       
   941 QDBusConnectionPrivate::~QDBusConnectionPrivate()
       
   942 {
       
   943     if (thread() && thread() != QThread::currentThread())
       
   944         qWarning("QDBusConnection(name=\"%s\")'s last reference in not in its creation thread! "
       
   945                  "Timer and socket errors will follow and the program will probably crash",
       
   946                  qPrintable(name));
       
   947 
       
   948     closeConnection();
       
   949     rootNode.children.clear();  // free resources
       
   950     qDeleteAll(cachedMetaObjects);
       
   951 
       
   952     if (server)
       
   953         q_dbus_server_unref(server);
       
   954     if (connection)
       
   955         q_dbus_connection_unref(connection);
       
   956 
       
   957     connection = 0;
       
   958     server = 0;
       
   959 }
       
   960 
       
   961 void QDBusConnectionPrivate::deleteYourself()
       
   962 {
       
   963     if (thread() && thread() != QThread::currentThread()) {
       
   964         // last reference dropped while not in the correct thread
       
   965         // ask the correct thread to delete
       
   966 
       
   967         // note: since we're posting an event to another thread, we
       
   968         // must consider deleteLater() to take effect immediately
       
   969         deleteLater();
       
   970     } else {
       
   971         delete this;
       
   972     }
       
   973 }
       
   974 
       
   975 void QDBusConnectionPrivate::closeConnection()
       
   976 {
       
   977     QDBusWriteLocker locker(CloseConnectionAction, this);
       
   978     ConnectionMode oldMode = mode;
       
   979     mode = InvalidMode; // prevent reentrancy
       
   980     baseService.clear();
       
   981 
       
   982     if (oldMode == ServerMode) {
       
   983         if (server) {
       
   984             q_dbus_server_disconnect(server);
       
   985         }
       
   986     } else if (oldMode == ClientMode || oldMode == PeerMode) {
       
   987         if (connection) {
       
   988             q_dbus_connection_close(connection);
       
   989             // send the "close" message
       
   990             while (q_dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS)
       
   991                 ;
       
   992         }
       
   993     }
       
   994 }
       
   995 
       
   996 void QDBusConnectionPrivate::checkThread()
       
   997 {
       
   998     if (!thread()) {
       
   999         if (QCoreApplication::instance())
       
  1000             moveToThread(QCoreApplication::instance()->thread());
       
  1001         else
       
  1002             qWarning("The thread that had QDBusConnection('%s') has died and there is no main thread",
       
  1003                      qPrintable(name));
       
  1004     }
       
  1005 }
       
  1006 
       
  1007 bool QDBusConnectionPrivate::handleError(const QDBusErrorInternal &error)
       
  1008 {
       
  1009     if (!error)
       
  1010         return false;           // no error
       
  1011 
       
  1012     //lock.lockForWrite();
       
  1013     lastError = error;
       
  1014     //lock.unlock();
       
  1015     return true;
       
  1016 }
       
  1017 
       
  1018 void QDBusConnectionPrivate::timerEvent(QTimerEvent *e)
       
  1019 {
       
  1020     {
       
  1021         QDBusWatchAndTimeoutLocker locker(TimerEventAction, this);
       
  1022         DBusTimeout *timeout = timeouts.value(e->timerId(), 0);
       
  1023         if (timeout)
       
  1024             q_dbus_timeout_handle(timeout);
       
  1025     }
       
  1026 
       
  1027     doDispatch();
       
  1028 }
       
  1029 
       
  1030 void QDBusConnectionPrivate::customEvent(QEvent *e)
       
  1031 {
       
  1032     Q_ASSERT(e->type() == QEvent::User);
       
  1033 
       
  1034     QDBusConnectionCallbackEvent *ev = static_cast<QDBusConnectionCallbackEvent *>(e);
       
  1035     QDBusLockerBase::reportThreadAction(int(AddTimeoutAction) + int(ev->subtype),
       
  1036                                         QDBusLockerBase::BeforeDeliver, this);
       
  1037     switch (ev->subtype)
       
  1038     {
       
  1039     case QDBusConnectionCallbackEvent::AddTimeout: {
       
  1040         QDBusWatchAndTimeoutLocker locker(RealAddTimeoutAction, this);
       
  1041         while (!timeoutsPendingAdd.isEmpty()) {
       
  1042             QPair<DBusTimeout *, int> entry = timeoutsPendingAdd.takeFirst();
       
  1043             qDBusRealAddTimeout(this, entry.first, entry.second);
       
  1044         }
       
  1045         break;
       
  1046     }
       
  1047 
       
  1048     case QDBusConnectionCallbackEvent::KillTimer:
       
  1049         killTimer(ev->timerId);
       
  1050         break;
       
  1051 
       
  1052     case QDBusConnectionCallbackEvent::AddWatch:
       
  1053         qDBusRealAddWatch(this, ev->watch, ev->extra, ev->fd);
       
  1054         break;
       
  1055 
       
  1056     case QDBusConnectionCallbackEvent::ToggleWatch:
       
  1057         qDBusRealToggleWatch(this, ev->watch, ev->fd);
       
  1058         break;
       
  1059     }
       
  1060     QDBusLockerBase::reportThreadAction(int(AddTimeoutAction) + int(ev->subtype),
       
  1061                                         QDBusLockerBase::AfterDeliver, this);
       
  1062 }
       
  1063 
       
  1064 void QDBusConnectionPrivate::doDispatch()
       
  1065 {
       
  1066     QDBusDispatchLocker locker(DoDispatchAction, this);
       
  1067     if (mode == ClientMode || mode == PeerMode)
       
  1068         while (q_dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS) ;
       
  1069 }
       
  1070 
       
  1071 void QDBusConnectionPrivate::socketRead(int fd)
       
  1072 {
       
  1073     QVarLengthArray<DBusWatch *, 2> pendingWatches;
       
  1074 
       
  1075     {
       
  1076         QDBusWatchAndTimeoutLocker locker(SocketReadAction, this);
       
  1077         WatcherHash::ConstIterator it = watchers.constFind(fd);
       
  1078         while (it != watchers.constEnd() && it.key() == fd) {
       
  1079             if (it->watch && it->read && it->read->isEnabled())
       
  1080                 pendingWatches.append(it.value().watch);
       
  1081             ++it;
       
  1082         }
       
  1083     }
       
  1084 
       
  1085     for (int i = 0; i < pendingWatches.size(); ++i)
       
  1086         if (!q_dbus_watch_handle(pendingWatches[i], DBUS_WATCH_READABLE))
       
  1087             qDebug("OUT OF MEM");
       
  1088     doDispatch();
       
  1089 }
       
  1090 
       
  1091 void QDBusConnectionPrivate::socketWrite(int fd)
       
  1092 {
       
  1093     QVarLengthArray<DBusWatch *, 2> pendingWatches;
       
  1094 
       
  1095     {
       
  1096         QDBusWatchAndTimeoutLocker locker(SocketWriteAction, this);
       
  1097         WatcherHash::ConstIterator it = watchers.constFind(fd);
       
  1098         while (it != watchers.constEnd() && it.key() == fd) {
       
  1099             if (it->watch && it->write && it->write->isEnabled())
       
  1100                 pendingWatches.append(it.value().watch);
       
  1101             ++it;
       
  1102         }
       
  1103     }
       
  1104 
       
  1105     for (int i = 0; i < pendingWatches.size(); ++i)
       
  1106         if (!q_dbus_watch_handle(pendingWatches[i], DBUS_WATCH_WRITABLE))
       
  1107             qDebug("OUT OF MEM");
       
  1108 }
       
  1109 
       
  1110 void QDBusConnectionPrivate::objectDestroyed(QObject *obj)
       
  1111 {
       
  1112     QDBusWriteLocker locker(ObjectDestroyedAction, this);
       
  1113     huntAndDestroy(obj, rootNode);
       
  1114 
       
  1115     SignalHookHash::iterator sit = signalHooks.begin();
       
  1116     while (sit != signalHooks.end()) {
       
  1117         if (static_cast<QObject *>(sit.value().obj) == obj)
       
  1118             sit = disconnectSignal(sit);
       
  1119         else
       
  1120             ++sit;
       
  1121     }
       
  1122 
       
  1123     obj->disconnect(this);
       
  1124 }
       
  1125 
       
  1126 void QDBusConnectionPrivate::relaySignal(QObject *obj, const QMetaObject *mo, int signalId,
       
  1127                                          const QVariantList &args)
       
  1128 {
       
  1129     QString interface = qDBusInterfaceFromMetaObject(mo);
       
  1130 
       
  1131     QMetaMethod mm = mo->method(signalId);
       
  1132     QByteArray memberName = mm.signature();
       
  1133     memberName.truncate(memberName.indexOf('('));
       
  1134 
       
  1135     // check if it's scriptable
       
  1136     bool isScriptable = mm.attributes() & QMetaMethod::Scriptable;
       
  1137     bool isAdaptor = false;
       
  1138     for ( ; mo; mo = mo->superClass())
       
  1139         if (mo == &QDBusAbstractAdaptor::staticMetaObject) {
       
  1140             isAdaptor = true;
       
  1141             break;
       
  1142         }
       
  1143 
       
  1144     QDBusReadLocker locker(RelaySignalAction, this);
       
  1145     QDBusMessage message = QDBusMessage::createSignal(QLatin1String("/"), interface,
       
  1146                                                       QLatin1String(memberName));
       
  1147     QDBusMessagePrivate::setParametersValidated(message, true);
       
  1148     message.setArguments(args);
       
  1149     QDBusError error;
       
  1150     DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message, &error);
       
  1151     if (!msg) {
       
  1152         qWarning("QDBusConnection: Could not emit signal %s.%s: %s", qPrintable(interface), memberName.constData(),
       
  1153                  qPrintable(error.message()));
       
  1154         lastError = error;
       
  1155         return;
       
  1156     }
       
  1157 
       
  1158     //qDBusDebug() << "Emitting signal" << message;
       
  1159     //qDBusDebug() << "for paths:";
       
  1160     q_dbus_message_set_no_reply(msg, true); // the reply would not be delivered to anything
       
  1161     huntAndEmit(connection, msg, obj, rootNode, isScriptable, isAdaptor);
       
  1162     q_dbus_message_unref(msg);
       
  1163 }
       
  1164 
       
  1165 void QDBusConnectionPrivate::_q_serviceOwnerChanged(const QString &name,
       
  1166                                                     const QString &oldOwner, const QString &newOwner)
       
  1167 {
       
  1168     if (oldOwner == baseService)
       
  1169         unregisterService(name);
       
  1170     if (newOwner == baseService)
       
  1171         registerService(name);
       
  1172 
       
  1173     QDBusWriteLocker locker(UpdateSignalHookOwnerAction, this);
       
  1174     QMutableHashIterator<QString, SignalHook> it(signalHooks);
       
  1175     it.toFront();
       
  1176     while (it.hasNext())
       
  1177         if (it.next().value().service == name)
       
  1178             it.value().owner = newOwner;
       
  1179 }
       
  1180 
       
  1181 int QDBusConnectionPrivate::findSlot(QObject* obj, const QByteArray &normalizedName,
       
  1182                                      QList<int> &params)
       
  1183 {
       
  1184     int midx = obj->metaObject()->indexOfMethod(normalizedName);
       
  1185     if (midx == -1)
       
  1186         return -1;
       
  1187 
       
  1188     int inputCount = qDBusParametersForMethod(obj->metaObject()->method(midx), params);
       
  1189     if ( inputCount == -1 || inputCount + 1 != params.count() )
       
  1190         return -1;              // failed to parse or invalid arguments or output arguments
       
  1191 
       
  1192     return midx;
       
  1193 }
       
  1194 
       
  1195 bool QDBusConnectionPrivate::prepareHook(QDBusConnectionPrivate::SignalHook &hook, QString &key,
       
  1196                                          const QString &service, const QString &owner,
       
  1197                                          const QString &path, const QString &interface, const QString &name,
       
  1198                                          QObject *receiver, const char *signal, int minMIdx,
       
  1199                                          bool buildSignature)
       
  1200 {
       
  1201     QByteArray normalizedName = signal + 1;
       
  1202     hook.midx = findSlot(receiver, signal + 1, hook.params);
       
  1203     if (hook.midx == -1) {
       
  1204         normalizedName = QMetaObject::normalizedSignature(signal + 1);
       
  1205         hook.midx = findSlot(receiver, normalizedName, hook.params);
       
  1206     }
       
  1207     if (hook.midx < minMIdx) {
       
  1208         if (hook.midx == -1)
       
  1209         {}
       
  1210         return false;
       
  1211     }
       
  1212 
       
  1213     hook.service = service;
       
  1214     hook.owner = owner; // we don't care if the service has an owner yet
       
  1215     hook.path = path;
       
  1216     hook.obj = receiver;
       
  1217 
       
  1218     // build the D-Bus signal name and signature
       
  1219     // This should not happen for QDBusConnection::connect, use buildSignature here, since
       
  1220     // QDBusConnection::connect passes false and everything else uses true
       
  1221     QString mname = name;
       
  1222     if (buildSignature && mname.isNull()) {
       
  1223         normalizedName.truncate(normalizedName.indexOf('('));
       
  1224         mname = QString::fromUtf8(normalizedName);
       
  1225     }
       
  1226     key = mname;
       
  1227     key.reserve(interface.length() + 1 + mname.length());
       
  1228     key += QLatin1Char(':');
       
  1229     key += interface;
       
  1230 
       
  1231     if (buildSignature) {
       
  1232         hook.signature.clear();
       
  1233         for (int i = 1; i < hook.params.count(); ++i)
       
  1234             if (hook.params.at(i) != QDBusMetaTypeId::message)
       
  1235                 hook.signature += QLatin1String( QDBusMetaType::typeToSignature( hook.params.at(i) ) );
       
  1236     }
       
  1237 
       
  1238     hook.matchRule = buildMatchRule(service, owner, path, interface, mname, hook.signature);
       
  1239     return true;                // connect to this signal
       
  1240 }
       
  1241 
       
  1242 void QDBusConnectionPrivate::sendError(const QDBusMessage &msg, QDBusError::ErrorType code)
       
  1243 {
       
  1244     if (code == QDBusError::UnknownMethod) {
       
  1245         QString interfaceMsg;
       
  1246         if (msg.interface().isEmpty())
       
  1247             interfaceMsg = QLatin1String("any interface");
       
  1248         else
       
  1249             interfaceMsg = QString::fromLatin1("interface '%1'").arg(msg.interface());
       
  1250 
       
  1251         send(msg.createErrorReply(code,
       
  1252                                   QString::fromLatin1("No such method '%1' in %2 at object path '%3' "
       
  1253                                                       "(signature '%4')")
       
  1254                                   .arg(msg.member(), interfaceMsg, msg.path(), msg.signature())));
       
  1255     } else if (code == QDBusError::UnknownInterface) {
       
  1256         send(msg.createErrorReply(QDBusError::UnknownInterface,
       
  1257                                   QString::fromLatin1("No such interface '%1' at object path '%2'")
       
  1258                                   .arg(msg.interface(), msg.path())));
       
  1259     } else if (code == QDBusError::UnknownObject) {
       
  1260         send(msg.createErrorReply(QDBusError::UnknownObject,
       
  1261                                   QString::fromLatin1("No such object path '%1'").arg(msg.path())));
       
  1262     }
       
  1263 }
       
  1264 
       
  1265 bool QDBusConnectionPrivate::activateInternalFilters(const ObjectTreeNode &node,
       
  1266                                                      const QDBusMessage &msg)
       
  1267 {
       
  1268     // object may be null
       
  1269     const QString interface = msg.interface();
       
  1270 
       
  1271     if (interface.isEmpty() || interface == QLatin1String(DBUS_INTERFACE_INTROSPECTABLE)) {
       
  1272         if (msg.member() == QLatin1String("Introspect") && msg.signature().isEmpty()) {
       
  1273             //qDebug() << "QDBusConnectionPrivate::activateInternalFilters introspect" << msg.d_ptr->msg;
       
  1274             QDBusMessage reply = msg.createReply(qDBusIntrospectObject(node));
       
  1275             send(reply);
       
  1276             return true;
       
  1277         }
       
  1278 
       
  1279         if (!interface.isEmpty()) {
       
  1280             sendError(msg, QDBusError::UnknownMethod);
       
  1281             return true;
       
  1282         }
       
  1283     }
       
  1284 
       
  1285     if (node.obj && (interface.isEmpty() ||
       
  1286                      interface == QLatin1String(DBUS_INTERFACE_PROPERTIES))) {
       
  1287         //qDebug() << "QDBusConnectionPrivate::activateInternalFilters properties" << msg.d_ptr->msg;
       
  1288         if (msg.member() == QLatin1String("Get") && msg.signature() == QLatin1String("ss")) {
       
  1289             QDBusMessage reply = qDBusPropertyGet(node, msg);
       
  1290             send(reply);
       
  1291             return true;
       
  1292         } else if (msg.member() == QLatin1String("Set") && msg.signature() == QLatin1String("ssv")) {
       
  1293             QDBusMessage reply = qDBusPropertySet(node, msg);
       
  1294             send(reply);
       
  1295             return true;
       
  1296         } else if (msg.member() == QLatin1String("GetAll") && msg.signature() == QLatin1String("s")) {
       
  1297             QDBusMessage reply = qDBusPropertyGetAll(node, msg);
       
  1298             send(reply);
       
  1299             return true;
       
  1300         }
       
  1301 
       
  1302         if (!interface.isEmpty()) {
       
  1303             sendError(msg, QDBusError::UnknownMethod);
       
  1304             return true;
       
  1305         }
       
  1306     }
       
  1307 
       
  1308     return false;
       
  1309 }
       
  1310 
       
  1311 void QDBusConnectionPrivate::activateObject(ObjectTreeNode &node, const QDBusMessage &msg,
       
  1312                                             int pathStartPos)
       
  1313 {
       
  1314     // This is called by QDBusConnectionPrivate::handleObjectCall to place a call to a slot
       
  1315     // on the object.
       
  1316     //
       
  1317     // The call is routed through the adaptor sub-objects if we have any
       
  1318 
       
  1319     // object may be null
       
  1320 
       
  1321     if (pathStartPos != msg.path().length()) {
       
  1322         node.flags &= ~QDBusConnection::ExportAllSignals;
       
  1323         node.obj = findChildObject(&node, msg.path(), pathStartPos);
       
  1324         if (!node.obj) {
       
  1325             sendError(msg, QDBusError::UnknownObject);
       
  1326             return;
       
  1327         }
       
  1328     }
       
  1329 
       
  1330     QDBusAdaptorConnector *connector;
       
  1331     if (node.flags & QDBusConnection::ExportAdaptors &&
       
  1332         (connector = qDBusFindAdaptorConnector(node.obj))) {
       
  1333         int newflags = node.flags | QDBusConnection::ExportAllSlots;
       
  1334 
       
  1335         if (msg.interface().isEmpty()) {
       
  1336             // place the call in all interfaces
       
  1337             // let the first one that handles it to work
       
  1338             QDBusAdaptorConnector::AdaptorMap::ConstIterator it =
       
  1339                 connector->adaptors.constBegin();
       
  1340             QDBusAdaptorConnector::AdaptorMap::ConstIterator end =
       
  1341                 connector->adaptors.constEnd();
       
  1342 
       
  1343             for ( ; it != end; ++it)
       
  1344                 if (activateCall(it->adaptor, newflags, msg))
       
  1345                     return;
       
  1346         } else {
       
  1347             // check if we have an interface matching the name that was asked:
       
  1348             QDBusAdaptorConnector::AdaptorMap::ConstIterator it;
       
  1349             it = qLowerBound(connector->adaptors.constBegin(), connector->adaptors.constEnd(),
       
  1350                              msg.interface());
       
  1351             if (it != connector->adaptors.constEnd() && msg.interface() == QLatin1String(it->interface)) {
       
  1352                 if (!activateCall(it->adaptor, newflags, msg))
       
  1353                     sendError(msg, QDBusError::UnknownMethod);
       
  1354                 return;
       
  1355             }
       
  1356         }
       
  1357     }
       
  1358 
       
  1359     // no adaptors matched or were exported
       
  1360     // try our standard filters
       
  1361     if (activateInternalFilters(node, msg))
       
  1362         return;                 // internal filters have already run or an error has been sent
       
  1363 
       
  1364     // try the object itself:
       
  1365     if (node.flags & (QDBusConnection::ExportScriptableSlots|QDBusConnection::ExportNonScriptableSlots)) {
       
  1366         bool interfaceFound = true;
       
  1367         if (!msg.interface().isEmpty())
       
  1368             interfaceFound = qDBusInterfaceInObject(node.obj, msg.interface());
       
  1369 
       
  1370         if (interfaceFound) {
       
  1371             if (!activateCall(node.obj, node.flags, msg))
       
  1372                 sendError(msg, QDBusError::UnknownMethod);
       
  1373             return;
       
  1374         }
       
  1375     }
       
  1376 
       
  1377     // nothing matched, send an error code
       
  1378     if (msg.interface().isEmpty())
       
  1379         sendError(msg, QDBusError::UnknownMethod);
       
  1380     else
       
  1381         sendError(msg, QDBusError::UnknownInterface);
       
  1382 }
       
  1383 
       
  1384 void QDBusConnectionPrivate::handleObjectCall(const QDBusMessage &msg)
       
  1385 {
       
  1386     // if the msg is external, we were called from inside doDispatch
       
  1387     // that means the dispatchLock mutex is locked
       
  1388     // must not call out to user code in that case
       
  1389     //
       
  1390     // however, if the message is internal, handleMessage was called
       
  1391     // directly and no lock is in place. We can therefore call out to
       
  1392     // user code, if necessary
       
  1393     ObjectTreeNode result;
       
  1394     int usedLength;
       
  1395     QThread *objThread = 0;
       
  1396     QSemaphore sem;
       
  1397     bool semWait;
       
  1398 
       
  1399     {
       
  1400         QDBusReadLocker locker(HandleObjectCallAction, this);
       
  1401         if (!findObject(&rootNode, msg.path(), usedLength, result)) {
       
  1402             // qDebug("Call failed: no object found at %s", qPrintable(msg.path()));
       
  1403             sendError(msg, QDBusError::UnknownObject);
       
  1404             return;
       
  1405         }
       
  1406 
       
  1407         if (!result.obj) {
       
  1408             // no object -> no threading issues
       
  1409             // it's either going to be an error, or an internal filter
       
  1410             activateObject(result, msg, usedLength);
       
  1411             return;
       
  1412         }
       
  1413 
       
  1414         objThread = result.obj->thread();
       
  1415         if (!objThread) {
       
  1416             send(msg.createErrorReply(QDBusError::InternalError,
       
  1417                                       QString::fromLatin1("Object '%1' (at path '%2')"
       
  1418                                                           " has no thread. Cannot deliver message.")
       
  1419                                       .arg(result.obj->objectName(), msg.path())));
       
  1420             return;
       
  1421         }
       
  1422 
       
  1423         if (!QDBusMessagePrivate::isLocal(msg)) {
       
  1424             // external incoming message
       
  1425             // post it and forget
       
  1426             postEventToThread(HandleObjectCallPostEventAction, result.obj,
       
  1427                               new QDBusActivateObjectEvent(QDBusConnection(this), this, result,
       
  1428                                                            usedLength, msg));
       
  1429             return;
       
  1430         } else if (objThread != QThread::currentThread()) {
       
  1431             // synchronize with other thread
       
  1432             postEventToThread(HandleObjectCallPostEventAction, result.obj,
       
  1433                               new QDBusActivateObjectEvent(QDBusConnection(this), this, result,
       
  1434                                                            usedLength, msg, &sem));
       
  1435             semWait = true;
       
  1436         } else {
       
  1437             semWait = false;
       
  1438         }
       
  1439     } // release the lock
       
  1440 
       
  1441     if (semWait)
       
  1442         SEM_ACQUIRE(HandleObjectCallSemaphoreAction, sem);
       
  1443     else
       
  1444         activateObject(result, msg, usedLength);
       
  1445 }
       
  1446 
       
  1447 QDBusActivateObjectEvent::~QDBusActivateObjectEvent()
       
  1448 {
       
  1449     if (!handled) {
       
  1450         // we're being destroyed without delivering
       
  1451         // it means the object was deleted between posting and delivering
       
  1452         QDBusConnectionPrivate *that = QDBusConnectionPrivate::d(connection);
       
  1453         that->sendError(message, QDBusError::UnknownObject);
       
  1454     }
       
  1455 
       
  1456     // semaphore releasing happens in ~QMetaCallEvent
       
  1457 }
       
  1458 
       
  1459 int QDBusActivateObjectEvent::placeMetaCall(QObject *)
       
  1460 {
       
  1461     QDBusConnectionPrivate *that = QDBusConnectionPrivate::d(connection);
       
  1462 
       
  1463     QDBusLockerBase::reportThreadAction(HandleObjectCallPostEventAction,
       
  1464                                         QDBusLockerBase::BeforeDeliver, that);
       
  1465     that->activateObject(node, message, pathStartPos);
       
  1466     QDBusLockerBase::reportThreadAction(HandleObjectCallPostEventAction,
       
  1467                                         QDBusLockerBase::AfterDeliver, that);
       
  1468 
       
  1469     handled = true;
       
  1470     return -1;
       
  1471 }
       
  1472 
       
  1473 void QDBusConnectionPrivate::handleSignal(const QString &key, const QDBusMessage& msg)
       
  1474 {
       
  1475     SignalHookHash::const_iterator it = signalHooks.find(key);
       
  1476     SignalHookHash::const_iterator end = signalHooks.constEnd();
       
  1477     //qDebug("looking for: %s", path.toLocal8Bit().constData());
       
  1478     //qDBusDebug() << signalHooks.keys();
       
  1479     for ( ; it != end && it.key() == key; ++it) {
       
  1480         const SignalHook &hook = it.value();
       
  1481         if (!hook.owner.isEmpty() && hook.owner != msg.service())
       
  1482             continue;
       
  1483         if (!hook.path.isEmpty() && hook.path != msg.path())
       
  1484             continue;
       
  1485         if (!hook.signature.isEmpty() && hook.signature != msg.signature())
       
  1486             continue;
       
  1487         if (hook.signature.isEmpty() && !hook.signature.isNull() && !msg.signature().isEmpty())
       
  1488             continue;
       
  1489 
       
  1490         activateSignal(hook, msg);
       
  1491     }
       
  1492 }
       
  1493 
       
  1494 void QDBusConnectionPrivate::handleSignal(const QDBusMessage& msg)
       
  1495 {
       
  1496     // We call handlesignal(QString, QDBusMessage) three times:
       
  1497     //  one with member:interface
       
  1498     //  one with member:
       
  1499     //  one with :interface
       
  1500     // This allows us to match signals with wildcards on member or interface
       
  1501     // (but not both)
       
  1502 
       
  1503     QString key = msg.member();
       
  1504     key.reserve(key.length() + 1 + msg.interface().length());
       
  1505     key += QLatin1Char(':');
       
  1506     key += msg.interface();
       
  1507 
       
  1508     QDBusReadLocker locker(HandleSignalAction, this);
       
  1509     handleSignal(key, msg);                  // one try
       
  1510 
       
  1511     key.truncate(msg.member().length() + 1); // keep the ':'
       
  1512     handleSignal(key, msg);                  // second try
       
  1513 
       
  1514     key = QLatin1Char(':');
       
  1515     key += msg.interface();
       
  1516     handleSignal(key, msg);                  // third try
       
  1517 }
       
  1518 
       
  1519 static dbus_int32_t server_slot = -1;
       
  1520 
       
  1521 void QDBusConnectionPrivate::setServer(DBusServer *s, const QDBusErrorInternal &error)
       
  1522 {
       
  1523     if (!s) {
       
  1524         handleError(error);
       
  1525         return;
       
  1526     }
       
  1527 
       
  1528     server = s;
       
  1529     mode = ServerMode;
       
  1530 
       
  1531     dbus_bool_t data_allocated = q_dbus_server_allocate_data_slot(&server_slot);
       
  1532     if (data_allocated && server_slot < 0)
       
  1533         return;
       
  1534 
       
  1535     dbus_bool_t watch_functions_set = q_dbus_server_set_watch_functions(server,
       
  1536                                                                       qDBusAddWatch,
       
  1537                                                                       qDBusRemoveWatch,
       
  1538                                                                       qDBusToggleWatch,
       
  1539                                                                       this, 0);
       
  1540     //qDebug() << "watch_functions_set" << watch_functions_set;
       
  1541     Q_UNUSED(watch_functions_set);
       
  1542 
       
  1543     dbus_bool_t time_functions_set = q_dbus_server_set_timeout_functions(server,
       
  1544                                                                        qDBusAddTimeout,
       
  1545                                                                        qDBusRemoveTimeout,
       
  1546                                                                        qDBusToggleTimeout,
       
  1547                                                                        this, 0);
       
  1548     //qDebug() << "time_functions_set" << time_functions_set;
       
  1549     Q_UNUSED(time_functions_set);
       
  1550     
       
  1551     q_dbus_server_set_new_connection_function(server, qDBusNewConnection, this, 0);
       
  1552 
       
  1553     dbus_bool_t data_set = q_dbus_server_set_data(server, server_slot, this, 0);
       
  1554     //qDebug() << "data_set" << data_set;
       
  1555     Q_UNUSED(data_set);
       
  1556 }
       
  1557 
       
  1558 void QDBusConnectionPrivate::setPeer(DBusConnection *c, const QDBusErrorInternal &error)
       
  1559 {
       
  1560     if (!c) {
       
  1561         handleError(error);
       
  1562         return;
       
  1563     }
       
  1564 
       
  1565     connection = c;
       
  1566     mode = PeerMode;
       
  1567     
       
  1568     q_dbus_connection_set_exit_on_disconnect(connection, false);
       
  1569     q_dbus_connection_set_watch_functions(connection,
       
  1570                                         qDBusAddWatch,
       
  1571                                         qDBusRemoveWatch,
       
  1572                                         qDBusToggleWatch,
       
  1573                                         this, 0);
       
  1574     q_dbus_connection_set_timeout_functions(connection,
       
  1575                                           qDBusAddTimeout,
       
  1576                                           qDBusRemoveTimeout,
       
  1577                                           qDBusToggleTimeout,
       
  1578                                           this, 0);
       
  1579     q_dbus_connection_set_dispatch_status_function(connection, qDBusUpdateDispatchStatus, this, 0);
       
  1580     q_dbus_connection_add_filter(connection,
       
  1581                                qDBusSignalFilter,
       
  1582                                this, 0);
       
  1583 
       
  1584     QMetaObject::invokeMethod(this, "doDispatch", Qt::QueuedConnection);
       
  1585 }
       
  1586 
       
  1587 void QDBusConnectionPrivate::setConnection(DBusConnection *dbc, const QDBusErrorInternal &error)
       
  1588 {
       
  1589     if (!dbc) {
       
  1590         handleError(error);
       
  1591         return;
       
  1592     }
       
  1593 
       
  1594     connection = dbc;
       
  1595     mode = ClientMode;
       
  1596 
       
  1597     q_dbus_connection_set_exit_on_disconnect(connection, false);
       
  1598     q_dbus_connection_set_watch_functions(connection, qDBusAddWatch, qDBusRemoveWatch,
       
  1599                                           qDBusToggleWatch, this, 0);
       
  1600     q_dbus_connection_set_timeout_functions(connection, qDBusAddTimeout, qDBusRemoveTimeout,
       
  1601                                             qDBusToggleTimeout, this, 0);
       
  1602     q_dbus_connection_set_dispatch_status_function(connection, qDBusUpdateDispatchStatus, this, 0);
       
  1603 
       
  1604     // Initialize the match rules
       
  1605     // We want all messages that have us as destination
       
  1606     // signals don't have destinations, but connectSignal() takes care of them
       
  1607     const char *service = q_dbus_bus_get_unique_name(connection);
       
  1608     if (service) {
       
  1609         QVarLengthArray<char, 56> filter;
       
  1610         filter.append("destination='", 13);
       
  1611         filter.append(service, qstrlen(service));
       
  1612         filter.append("\'\0", 2);
       
  1613 
       
  1614         QDBusErrorInternal error;
       
  1615         q_dbus_bus_add_match(connection, filter.constData(), error);
       
  1616         if (handleError(error)) {
       
  1617             closeConnection();
       
  1618             return;
       
  1619         }
       
  1620 
       
  1621         baseService = QString::fromUtf8(service);
       
  1622     } else {
       
  1623         qWarning("QDBusConnectionPrivate::SetConnection: Unable to get base service");
       
  1624     }
       
  1625 
       
  1626     q_dbus_connection_add_filter(connection, qDBusSignalFilter, this, 0);
       
  1627 
       
  1628     //qDebug("base service: %s", service);
       
  1629 
       
  1630     // schedule a dispatch:
       
  1631     QMetaObject::invokeMethod(this, "doDispatch", Qt::QueuedConnection);
       
  1632 }
       
  1633 
       
  1634 extern "C"{
       
  1635 static void qDBusResultReceived(DBusPendingCall *pending, void *user_data)
       
  1636 {
       
  1637     QDBusPendingCallPrivate *call = reinterpret_cast<QDBusPendingCallPrivate *>(user_data);
       
  1638     Q_ASSERT(call->pending == pending);
       
  1639     Q_UNUSED(pending);
       
  1640     QDBusConnectionPrivate::processFinishedCall(call);
       
  1641 }
       
  1642 }
       
  1643 
       
  1644 void QDBusConnectionPrivate::waitForFinished(QDBusPendingCallPrivate *pcall)
       
  1645 {
       
  1646     Q_ASSERT(pcall->pending);
       
  1647     QDBusDispatchLocker locker(PendingCallBlockAction, this);
       
  1648     q_dbus_pending_call_block(pcall->pending);
       
  1649     // QDBusConnectionPrivate::processFinishedCall() is called automatically
       
  1650 }
       
  1651 
       
  1652 void QDBusConnectionPrivate::processFinishedCall(QDBusPendingCallPrivate *call)
       
  1653 {
       
  1654     QDBusConnectionPrivate *connection = const_cast<QDBusConnectionPrivate *>(call->connection);
       
  1655 
       
  1656     QDBusMessage &msg = call->replyMessage;
       
  1657     if (call->pending) {
       
  1658         // decode the message
       
  1659         DBusMessage *reply = q_dbus_pending_call_steal_reply(call->pending);
       
  1660         msg = QDBusMessagePrivate::fromDBusMessage(reply);
       
  1661         q_dbus_message_unref(reply);
       
  1662     }
       
  1663     qDBusDebug() << QThread::currentThread() << "got message reply (async):" << msg;
       
  1664 
       
  1665     // Check if the reply has the expected signature
       
  1666     call->checkReceivedSignature();
       
  1667 
       
  1668     if (!call->receiver.isNull() && call->methodIdx != -1 && msg.type() == QDBusMessage::ReplyMessage) {
       
  1669         // Deliver the return values of a remote function call.
       
  1670         //
       
  1671         // There is only one connection and it is specified by idx
       
  1672         // The slot must have the same parameter types that the message does
       
  1673         // The slot may have less parameters than the message
       
  1674         // The slot may optionally have one final parameter that is QDBusMessage
       
  1675         // The slot receives read-only copies of the message (i.e., pass by value or by const-ref)
       
  1676 
       
  1677         QDBusCallDeliveryEvent *e = prepareReply(connection, call->receiver, call->methodIdx,
       
  1678                                                  call->metaTypes, msg);
       
  1679         if (e)
       
  1680             connection->postEventToThread(MessageResultReceivedAction, call->receiver, e);
       
  1681         else
       
  1682             qDBusDebug() << "Deliver failed!";
       
  1683     }
       
  1684 
       
  1685     // Are there any watchers?
       
  1686     if (call->watcherHelper)
       
  1687         call->watcherHelper->emitSignals(msg, call->sentMessage);
       
  1688 
       
  1689     if (msg.type() == QDBusMessage::ErrorMessage)
       
  1690         emit connection->callWithCallbackFailed(QDBusError(msg), call->sentMessage);
       
  1691 
       
  1692     if (call->pending)
       
  1693         q_dbus_pending_call_unref(call->pending);
       
  1694     call->pending = 0;
       
  1695 
       
  1696     if (call->autoDelete)
       
  1697         delete call;
       
  1698 }
       
  1699 
       
  1700 int QDBusConnectionPrivate::send(const QDBusMessage& message)
       
  1701 {
       
  1702     if (QDBusMessagePrivate::isLocal(message))
       
  1703         return -1;              // don't send; the reply will be retrieved by the caller
       
  1704                                 // through the d_ptr->localReply link
       
  1705 
       
  1706     QDBusError error;
       
  1707     DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message, &error);
       
  1708     if (!msg) {
       
  1709         if (message.type() == QDBusMessage::MethodCallMessage)
       
  1710             qWarning("QDBusConnection: error: could not send message to service \"%s\" path \"%s\" interface \"%s\" member \"%s\": %s",
       
  1711                      qPrintable(message.service()), qPrintable(message.path()),
       
  1712                      qPrintable(message.interface()), qPrintable(message.member()),
       
  1713                      qPrintable(error.message()));
       
  1714         else if (message.type() == QDBusMessage::SignalMessage)
       
  1715             qWarning("QDBusConnection: error: could not send signal path \"%s\" interface \"%s\" member \"%s\": %s",
       
  1716                      qPrintable(message.path()), qPrintable(message.interface()),
       
  1717                      qPrintable(message.member()),
       
  1718                      qPrintable(error.message()));
       
  1719         else
       
  1720             qWarning("QDBusConnection: error: could not send %s message to service \"%s\": %s",
       
  1721                      message.type() == QDBusMessage::ReplyMessage ? "reply" :
       
  1722                      message.type() == QDBusMessage::ErrorMessage ? "error" :
       
  1723                      "invalid", qPrintable(message.service()),
       
  1724                      qPrintable(error.message()));
       
  1725         lastError = error;
       
  1726         return 0;
       
  1727     }
       
  1728 
       
  1729     q_dbus_message_set_no_reply(msg, true); // the reply would not be delivered to anything
       
  1730 
       
  1731     qDBusDebug() << QThread::currentThread() << "sending message (no reply):" << message;
       
  1732     checkThread();
       
  1733     bool isOk = q_dbus_connection_send(connection, msg, 0);
       
  1734     int serial = 0;
       
  1735     if (isOk)
       
  1736         serial = q_dbus_message_get_serial(msg);
       
  1737 
       
  1738     q_dbus_message_unref(msg);
       
  1739     return serial;
       
  1740 }
       
  1741 
       
  1742 QDBusMessage QDBusConnectionPrivate::sendWithReply(const QDBusMessage &message,
       
  1743                                                    int sendMode, int timeout)
       
  1744 {
       
  1745     checkThread();
       
  1746     if ((sendMode == QDBus::BlockWithGui || sendMode == QDBus::Block)
       
  1747          && isServiceRegisteredByThread(message.service()))
       
  1748         // special case for synchronous local calls
       
  1749         return sendWithReplyLocal(message);
       
  1750 
       
  1751     if (!QCoreApplication::instance() || sendMode == QDBus::Block) {
       
  1752         QDBusError err;
       
  1753         DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message, &err);
       
  1754         if (!msg) {
       
  1755             qWarning("QDBusConnection: error: could not send message to service \"%s\" path \"%s\" interface \"%s\" member \"%s\": %s",
       
  1756                      qPrintable(message.service()), qPrintable(message.path()),
       
  1757                      qPrintable(message.interface()), qPrintable(message.member()),
       
  1758                      qPrintable(err.message()));
       
  1759             lastError = err;
       
  1760             return QDBusMessage::createError(err);
       
  1761         }
       
  1762 
       
  1763         qDBusDebug() << QThread::currentThread() << "sending message (blocking):" << message;
       
  1764         QDBusErrorInternal error;
       
  1765         DBusMessage *reply = q_dbus_connection_send_with_reply_and_block(connection, msg, timeout, error);
       
  1766 
       
  1767         q_dbus_message_unref(msg);
       
  1768 
       
  1769         if (!!error) {
       
  1770             lastError = err = error;
       
  1771             return QDBusMessage::createError(err);
       
  1772         }
       
  1773 
       
  1774         QDBusMessage amsg = QDBusMessagePrivate::fromDBusMessage(reply);
       
  1775         q_dbus_message_unref(reply);
       
  1776         qDBusDebug() << QThread::currentThread() << "got message reply (blocking):" << amsg;
       
  1777 
       
  1778         return amsg;
       
  1779     } else { // use the event loop
       
  1780         QDBusPendingCallPrivate *pcall = sendWithReplyAsync(message, timeout);
       
  1781         Q_ASSERT(pcall);
       
  1782 
       
  1783         if (pcall->replyMessage.type() != QDBusMessage::InvalidMessage) {
       
  1784             pcall->watcherHelper = new QDBusPendingCallWatcherHelper;
       
  1785             QEventLoop loop;
       
  1786             loop.connect(pcall->watcherHelper, SIGNAL(reply(QDBusMessage)), SLOT(quit()));
       
  1787             loop.connect(pcall->watcherHelper, SIGNAL(error(QDBusError,QDBusMessage)), SLOT(quit()));
       
  1788 
       
  1789             // enter the event loop and wait for a reply
       
  1790             loop.exec(QEventLoop::ExcludeUserInputEvents | QEventLoop::WaitForMoreEvents);
       
  1791         }
       
  1792 
       
  1793         QDBusMessage reply = pcall->replyMessage;
       
  1794         lastError = reply;      // set or clear error
       
  1795 
       
  1796         delete pcall;
       
  1797         return reply;
       
  1798     }
       
  1799 }
       
  1800 
       
  1801 QDBusMessage QDBusConnectionPrivate::sendWithReplyLocal(const QDBusMessage &message)
       
  1802 {
       
  1803     qDBusDebug() << QThread::currentThread() << "sending message via local-loop:" << message;
       
  1804 
       
  1805     QDBusMessage localCallMsg = QDBusMessagePrivate::makeLocal(*this, message);
       
  1806     bool handled = handleMessage(localCallMsg);
       
  1807 
       
  1808     if (!handled) {
       
  1809         QString interface = message.interface();
       
  1810         if (interface.isEmpty())
       
  1811             interface = QLatin1String("<no-interface>");
       
  1812         return QDBusMessage::createError(QDBusError::InternalError,
       
  1813                                          QString::fromLatin1("Internal error trying to call %1.%2 at %3 (signature '%4'")
       
  1814                                          .arg(interface, message.member(),
       
  1815                                               message.path(), message.signature()));
       
  1816     }
       
  1817 
       
  1818     // if the message was handled, there might be a reply
       
  1819     QDBusMessage localReplyMsg = QDBusMessagePrivate::makeLocalReply(*this, localCallMsg);
       
  1820     if (localReplyMsg.type() == QDBusMessage::InvalidMessage) {
       
  1821         qWarning("QDBusConnection: cannot call local method '%s' at object %s (with signature '%s') "
       
  1822                  "on blocking mode", qPrintable(message.member()), qPrintable(message.path()),
       
  1823                  qPrintable(message.signature()));
       
  1824         return QDBusMessage::createError(
       
  1825             QDBusError(QDBusError::InternalError,
       
  1826                        QLatin1String("local-loop message cannot have delayed replies")));
       
  1827     }
       
  1828 
       
  1829     // there is a reply
       
  1830     qDBusDebug() << QThread::currentThread() << "got message via local-loop:" << localReplyMsg;
       
  1831     return localReplyMsg;
       
  1832 }
       
  1833 
       
  1834 QDBusPendingCallPrivate *QDBusConnectionPrivate::sendWithReplyAsync(const QDBusMessage &message,
       
  1835                                                                     int timeout)
       
  1836 {
       
  1837     if (isServiceRegisteredByThread(message.service())) {
       
  1838         // special case for local calls
       
  1839         QDBusPendingCallPrivate *pcall = new QDBusPendingCallPrivate;
       
  1840         pcall->sentMessage = message;
       
  1841         pcall->replyMessage = sendWithReplyLocal(message);
       
  1842         pcall->connection = this;
       
  1843 
       
  1844         return pcall;
       
  1845     }
       
  1846 
       
  1847     checkThread();
       
  1848     QDBusPendingCallPrivate *pcall = new QDBusPendingCallPrivate;
       
  1849     pcall->sentMessage = message;
       
  1850     pcall->ref = 0;
       
  1851 
       
  1852     QDBusError error;
       
  1853     DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message, &error);
       
  1854     if (!msg) {
       
  1855         qWarning("QDBusConnection: error: could not send message to service \"%s\" path \"%s\" interface \"%s\" member \"%s\": %s",
       
  1856                  qPrintable(message.service()), qPrintable(message.path()),
       
  1857                  qPrintable(message.interface()), qPrintable(message.member()),
       
  1858                  qPrintable(error.message()));
       
  1859         pcall->replyMessage = QDBusMessage::createError(error);
       
  1860         lastError = error;
       
  1861         return pcall;
       
  1862     }
       
  1863 
       
  1864     qDBusDebug() << QThread::currentThread() << "sending message (async):" << message;
       
  1865     DBusPendingCall *pending = 0;
       
  1866 
       
  1867     QDBusDispatchLocker locker(SendWithReplyAsyncAction, this);
       
  1868     if (q_dbus_connection_send_with_reply(connection, msg, &pending, timeout)) {
       
  1869         if (pending) {
       
  1870             q_dbus_message_unref(msg);
       
  1871 
       
  1872             pcall->pending = pending;
       
  1873             pcall->connection = this;
       
  1874             q_dbus_pending_call_set_notify(pending, qDBusResultReceived, pcall, 0);
       
  1875 
       
  1876             return pcall;
       
  1877         } else {
       
  1878             // we're probably disconnected at this point
       
  1879             lastError = error = QDBusError(QDBusError::Disconnected, QLatin1String("Not connected to server"));
       
  1880         }
       
  1881     } else {
       
  1882         lastError = error = QDBusError(QDBusError::NoMemory, QLatin1String("Out of memory"));
       
  1883     }
       
  1884 
       
  1885     q_dbus_message_unref(msg);
       
  1886     pcall->replyMessage = QDBusMessage::createError(error);
       
  1887     return pcall;
       
  1888 }
       
  1889 
       
  1890 int QDBusConnectionPrivate::sendWithReplyAsync(const QDBusMessage &message, QObject *receiver,
       
  1891                                                const char *returnMethod, const char *errorMethod,
       
  1892                                                int timeout)
       
  1893 {
       
  1894     QDBusPendingCallPrivate *pcall = sendWithReplyAsync(message, timeout);
       
  1895     Q_ASSERT(pcall);
       
  1896 
       
  1897     // has it already finished (dispatched locally)?
       
  1898     if (pcall->replyMessage.type() == QDBusMessage::ReplyMessage) {
       
  1899         pcall->setReplyCallback(receiver, returnMethod);
       
  1900         processFinishedCall(pcall);
       
  1901         delete pcall;
       
  1902         return 1;
       
  1903     }
       
  1904 
       
  1905     // has it already finished and is an error reply message?
       
  1906     if (pcall->replyMessage.type() == QDBusMessage::ErrorMessage) {
       
  1907         if (errorMethod) {
       
  1908             pcall->watcherHelper = new QDBusPendingCallWatcherHelper;
       
  1909             connect(pcall->watcherHelper, SIGNAL(error(QDBusError,QDBusMessage)), receiver, errorMethod);
       
  1910             pcall->watcherHelper->moveToThread(thread());
       
  1911         }
       
  1912         processFinishedCall(pcall);
       
  1913         delete pcall;
       
  1914         return 1;
       
  1915     }
       
  1916 
       
  1917     // has it already finished with error?
       
  1918     if (pcall->replyMessage.type() != QDBusMessage::InvalidMessage) {
       
  1919         delete pcall;
       
  1920         return 0;
       
  1921     }
       
  1922 
       
  1923     pcall->autoDelete = true;
       
  1924     pcall->ref.ref();
       
  1925 
       
  1926     pcall->setReplyCallback(receiver, returnMethod);
       
  1927     if (errorMethod) {
       
  1928         pcall->watcherHelper = new QDBusPendingCallWatcherHelper;
       
  1929         connect(pcall->watcherHelper, SIGNAL(error(QDBusError,QDBusMessage)), receiver, errorMethod);
       
  1930         pcall->watcherHelper->moveToThread(thread());
       
  1931     }
       
  1932 
       
  1933     return 1;
       
  1934 }
       
  1935 
       
  1936 void QDBusConnectionPrivate::connectSignal(const QString &key, const SignalHook &hook)
       
  1937 {
       
  1938     signalHooks.insertMulti(key, hook);
       
  1939     connect(hook.obj, SIGNAL(destroyed(QObject*)), SLOT(objectDestroyed(QObject*)),
       
  1940             Qt::DirectConnection);
       
  1941 
       
  1942     MatchRefCountHash::iterator it = matchRefCounts.find(hook.matchRule);
       
  1943 
       
  1944     if (it != matchRefCounts.end()) { // Match already present
       
  1945         it.value() = it.value() + 1;
       
  1946         return;
       
  1947     }
       
  1948 
       
  1949     matchRefCounts.insert(hook.matchRule, 1);
       
  1950 
       
  1951     if (connection) {
       
  1952         qDBusDebug("Adding rule: %s", hook.matchRule.constData());
       
  1953         QDBusErrorInternal error;
       
  1954         q_dbus_bus_add_match(connection, hook.matchRule, error);
       
  1955         if (!!error) {
       
  1956             QDBusError qerror = error;
       
  1957             qWarning("QDBusConnectionPrivate::connectSignal: received error from D-Bus server "
       
  1958                      "while connecting signal to %s::%s: %s (%s)",
       
  1959                      hook.obj->metaObject()->className(),
       
  1960                      hook.obj->metaObject()->method(hook.midx).signature(),
       
  1961                      qPrintable(qerror.name()), qPrintable(qerror.message()));
       
  1962             Q_ASSERT(false);
       
  1963         }
       
  1964     }
       
  1965 }
       
  1966 
       
  1967 QDBusConnectionPrivate::SignalHookHash::Iterator
       
  1968 QDBusConnectionPrivate::disconnectSignal(SignalHookHash::Iterator &it)
       
  1969 {
       
  1970     const SignalHook &hook = it.value();
       
  1971 
       
  1972     bool erase = false;
       
  1973     MatchRefCountHash::iterator i = matchRefCounts.find(hook.matchRule);
       
  1974     if (i == matchRefCounts.end()) {
       
  1975         qWarning("QDBusConnectionPrivate::disconnectSignal: MatchRule not found in matchRefCounts!!");
       
  1976     } else {
       
  1977         if (i.value() == 1) {
       
  1978             erase = true;
       
  1979             matchRefCounts.erase(i);
       
  1980         }
       
  1981         else {
       
  1982             i.value() = i.value() - 1;
       
  1983         }
       
  1984     }
       
  1985 
       
  1986     // we don't care about errors here
       
  1987     if (connection && erase) {
       
  1988         qDBusDebug("Removing rule: %s", hook.matchRule.constData());
       
  1989         q_dbus_bus_remove_match(connection, hook.matchRule, NULL);
       
  1990     }
       
  1991 
       
  1992     return signalHooks.erase(it);
       
  1993 }
       
  1994 
       
  1995 void QDBusConnectionPrivate::registerObject(const ObjectTreeNode *node)
       
  1996 {
       
  1997     connect(node->obj, SIGNAL(destroyed(QObject*)), SLOT(objectDestroyed(QObject*)),
       
  1998             Qt::DirectConnection);
       
  1999 
       
  2000     if (node->flags & (QDBusConnection::ExportAdaptors
       
  2001                        | QDBusConnection::ExportScriptableSignals
       
  2002                        | QDBusConnection::ExportNonScriptableSignals)) {
       
  2003         QDBusAdaptorConnector *connector = qDBusCreateAdaptorConnector(node->obj);
       
  2004 
       
  2005         if (node->flags & (QDBusConnection::ExportScriptableSignals
       
  2006                            | QDBusConnection::ExportNonScriptableSignals)) {
       
  2007             connector->disconnectAllSignals(node->obj);
       
  2008             connector->connectAllSignals(node->obj);
       
  2009         }
       
  2010 
       
  2011         // disconnect and reconnect to avoid duplicates
       
  2012         connector->disconnect(SIGNAL(relaySignal(QObject*,const QMetaObject*,int,QVariantList)),
       
  2013                               this, SLOT(relaySignal(QObject*,const QMetaObject*,int,QVariantList)));
       
  2014         connect(connector, SIGNAL(relaySignal(QObject*,const QMetaObject*,int,QVariantList)),
       
  2015                 this, SLOT(relaySignal(QObject*,const QMetaObject*,int,QVariantList)),
       
  2016                 Qt::DirectConnection);
       
  2017     }
       
  2018 }
       
  2019 
       
  2020 void QDBusConnectionPrivate::connectRelay(const QString &service, const QString &owner,
       
  2021                                           const QString &path, const QString &interface,
       
  2022                                           QDBusAbstractInterface *receiver,
       
  2023                                           const char *signal)
       
  2024 {
       
  2025     // this function is called by QDBusAbstractInterface when one of its signals is connected
       
  2026     // we set up a relay from D-Bus into it
       
  2027     SignalHook hook;
       
  2028     QString key;
       
  2029 
       
  2030     if (!prepareHook(hook, key, service, owner, path, interface, QString(), receiver, signal,
       
  2031                      QDBusAbstractInterface::staticMetaObject.methodCount(), true))
       
  2032         return;                 // don't connect
       
  2033 
       
  2034     // add it to our list:
       
  2035     QDBusWriteLocker locker(ConnectRelayAction, this);
       
  2036     SignalHookHash::ConstIterator it = signalHooks.find(key);
       
  2037     SignalHookHash::ConstIterator end = signalHooks.constEnd();
       
  2038     for ( ; it != end && it.key() == key; ++it) {
       
  2039         const SignalHook &entry = it.value();
       
  2040         if (entry.service == hook.service &&
       
  2041             entry.owner == hook.owner &&
       
  2042             entry.path == hook.path &&
       
  2043             entry.signature == hook.signature &&
       
  2044             entry.obj == hook.obj &&
       
  2045             entry.midx == hook.midx)
       
  2046             return;             // already there, no need to re-add
       
  2047     }
       
  2048 
       
  2049     connectSignal(key, hook);
       
  2050 }
       
  2051 
       
  2052 void QDBusConnectionPrivate::disconnectRelay(const QString &service, const QString &owner,
       
  2053                                              const QString &path, const QString &interface,
       
  2054                                              QDBusAbstractInterface *receiver,
       
  2055                                              const char *signal)
       
  2056 {
       
  2057     // this function is called by QDBusAbstractInterface when one of its signals is disconnected
       
  2058     // we remove relay from D-Bus into it
       
  2059     SignalHook hook;
       
  2060     QString key;
       
  2061 
       
  2062     if (!prepareHook(hook, key, service, owner, path, interface, QString(), receiver, signal,
       
  2063                      QDBusAbstractInterface::staticMetaObject.methodCount(), true))
       
  2064         return;                 // don't connect
       
  2065 
       
  2066     // remove it from our list:
       
  2067     QDBusWriteLocker locker(DisconnectRelayAction, this);
       
  2068     SignalHookHash::Iterator it = signalHooks.find(key);
       
  2069     SignalHookHash::Iterator end = signalHooks.end();
       
  2070     for ( ; it != end && it.key() == key; ++it) {
       
  2071         const SignalHook &entry = it.value();
       
  2072         if (entry.service == hook.service &&
       
  2073             entry.owner == hook.owner &&
       
  2074             entry.path == hook.path &&
       
  2075             entry.signature == hook.signature &&
       
  2076             entry.obj == hook.obj &&
       
  2077             entry.midx == hook.midx) {
       
  2078             // found it
       
  2079             disconnectSignal(it);
       
  2080             return;
       
  2081         }
       
  2082     }
       
  2083 
       
  2084     qWarning("QDBusConnectionPrivate::disconnectRelay called for a signal that was not found");
       
  2085 }
       
  2086 
       
  2087 QString QDBusConnectionPrivate::getNameOwner(const QString& serviceName)
       
  2088 {
       
  2089     if (QDBusUtil::isValidUniqueConnectionName(serviceName))
       
  2090         return serviceName;
       
  2091     if (!connection || !QDBusUtil::isValidBusName(serviceName))
       
  2092         return QString();
       
  2093 
       
  2094     QDBusMessage msg = QDBusMessage::createMethodCall(QLatin1String(DBUS_SERVICE_DBUS),
       
  2095             QLatin1String(DBUS_PATH_DBUS), QLatin1String(DBUS_INTERFACE_DBUS),
       
  2096             QLatin1String("GetNameOwner"));
       
  2097     QDBusMessagePrivate::setParametersValidated(msg, true);
       
  2098     msg << serviceName;
       
  2099     QDBusMessage reply = sendWithReply(msg, QDBus::Block);
       
  2100     if (reply.type() == QDBusMessage::ReplyMessage)
       
  2101         return reply.arguments().at(0).toString();
       
  2102     return QString();
       
  2103 }
       
  2104 
       
  2105 QDBusMetaObject *
       
  2106 QDBusConnectionPrivate::findMetaObject(const QString &service, const QString &path,
       
  2107                                        const QString &interface, QDBusError &error)
       
  2108 {
       
  2109     // service must be a unique connection name
       
  2110     if (!interface.isEmpty()) {
       
  2111         QDBusReadLocker locker(FindMetaObject1Action, this);
       
  2112         QDBusMetaObject *mo = cachedMetaObjects.value(interface, 0);
       
  2113         if (mo)
       
  2114             return mo;
       
  2115     }
       
  2116 
       
  2117     // introspect the target object
       
  2118     QDBusMessage msg = QDBusMessage::createMethodCall(service, path,
       
  2119                                                 QLatin1String(DBUS_INTERFACE_INTROSPECTABLE),
       
  2120                                                 QLatin1String("Introspect"));
       
  2121     QDBusMessagePrivate::setParametersValidated(msg, true);
       
  2122 
       
  2123     QDBusMessage reply = sendWithReply(msg, QDBus::Block);
       
  2124 
       
  2125     // it doesn't exist yet, we have to create it
       
  2126     QDBusWriteLocker locker(FindMetaObject2Action, this);
       
  2127     QDBusMetaObject *mo = 0;
       
  2128     if (!interface.isEmpty())
       
  2129         mo = cachedMetaObjects.value(interface, 0);
       
  2130     if (mo)
       
  2131         // maybe it got created when we switched from read to write lock
       
  2132         return mo;
       
  2133 
       
  2134     QString xml;
       
  2135     if (reply.type() == QDBusMessage::ReplyMessage) {
       
  2136         if (reply.signature() == QLatin1String("s"))
       
  2137             // fetch the XML description
       
  2138             xml = reply.arguments().at(0).toString();
       
  2139     } else {
       
  2140         error = reply;
       
  2141         lastError = error;
       
  2142         if (reply.type() != QDBusMessage::ErrorMessage || error.type() != QDBusError::UnknownMethod)
       
  2143             return 0; // error
       
  2144     }
       
  2145 
       
  2146     // release the lock and return
       
  2147     QDBusMetaObject *result = QDBusMetaObject::createMetaObject(interface, xml,
       
  2148                                                                 cachedMetaObjects, error);
       
  2149     lastError = error;
       
  2150     return result;
       
  2151 }
       
  2152 
       
  2153 void QDBusConnectionPrivate::registerService(const QString &serviceName)
       
  2154 {
       
  2155     QDBusWriteLocker locker(RegisterServiceAction, this);
       
  2156     serviceNames.append(serviceName);
       
  2157 }
       
  2158 
       
  2159 void QDBusConnectionPrivate::unregisterService(const QString &serviceName)
       
  2160 {
       
  2161     QDBusWriteLocker locker(UnregisterServiceAction, this);
       
  2162     serviceNames.removeAll(serviceName);
       
  2163 }
       
  2164 
       
  2165 bool QDBusConnectionPrivate::isServiceRegisteredByThread(const QString &serviceName) const
       
  2166 {
       
  2167     if (serviceName == baseService)
       
  2168         return true;
       
  2169     QStringList copy = serviceNames;
       
  2170     return copy.contains(serviceName);
       
  2171 }
       
  2172 
       
  2173 void QDBusConnectionPrivate::postEventToThread(int action, QObject *object, QEvent *ev)
       
  2174 {
       
  2175     QDBusLockerBase::reportThreadAction(action, QDBusLockerBase::BeforePost, this);
       
  2176     QCoreApplication::postEvent(object, ev);
       
  2177     QDBusLockerBase::reportThreadAction(action, QDBusLockerBase::AfterPost, this);
       
  2178 }
       
  2179 
       
  2180 QT_END_NAMESPACE