• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

KDECore

DBusHelperProxy.cpp

Go to the documentation of this file.
00001 /*
00002 *   Copyright (C) 2008 Nicola Gigante <nicola.gigante@gmail.com>
00003 *   Copyright (C) 2009-2010 Dario Freddi <drf@kde.org>
00004 *
00005 *   This program is free software; you can redistribute it and/or modify
00006 *   it under the terms of the GNU Lesser General Public License as published by
00007 *   the Free Software Foundation; either version 2.1 of the License, or
00008 *   (at your option) any later version.
00009 *
00010 *   This program is distributed in the hope that it will be useful,
00011 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 *   GNU General Public License for more details.
00014 *
00015 *   You should have received a copy of the GNU Lesser General Public License
00016 *   along with this program; if not, write to the
00017 *   Free Software Foundation, Inc.,
00018 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA .
00019 */
00020 
00021 #include "DBusHelperProxy.h"
00022 
00023 #include <QtCore/qplugin.h>
00024 #include <QObject>
00025 #include <QMap>
00026 #include <QtDBus/QDBusMessage>
00027 #include <QtDBus/QDBusConnection>
00028 #include <QDebug>
00029 #include <QTimer>
00030 
00031 #include <klocalizedstring.h>
00032 
00033 #include <syslog.h>
00034 
00035 #include "BackendsManager.h"
00036 #include "authadaptor.h"
00037 
00038 Q_DECLARE_METATYPE(QTimer*)
00039 
00040 namespace KAuth
00041 {
00042 
00043 static void debugMessageReceived(int t, const QString &message);
00044 
00045 void DBusHelperProxy::stopAction(const QString &action, const QString &helperID)
00046 {
00047     QDBusMessage message;
00048     message = QDBusMessage::createMethodCall(helperID, QLatin1String("/"), QLatin1String("org.kde.auth"), QLatin1String("stopAction"));
00049 
00050     QList<QVariant> args;
00051     args << action;
00052     message.setArguments(args);
00053 
00054     QDBusConnection::systemBus().asyncCall(message);
00055 }
00056 
00057 bool DBusHelperProxy::executeActions(const QList<QPair<QString, QVariantMap> > &list, const QString &helperID)
00058 {
00059     QByteArray blob;
00060     QDataStream stream(&blob, QIODevice::WriteOnly);
00061 
00062     stream << list;
00063 
00064     QDBusConnection::systemBus().interface()->startService(helperID);
00065 
00066     if (!QDBusConnection::systemBus().connect(helperID, QLatin1String("/"), QLatin1String("org.kde.auth"), QLatin1String("remoteSignal"), this, SLOT(remoteSignalReceived(int, const QString &, QByteArray)))) {
00067         return false;
00068     }
00069 
00070     QDBusMessage message;
00071     message = QDBusMessage::createMethodCall(helperID, QLatin1String("/"), QLatin1String("org.kde.auth"), QLatin1String("performActions"));
00072 
00073     QList<QVariant> args;
00074     args << blob << BackendsManager::authBackend()->callerID();
00075     message.setArguments(args);
00076 
00077     QDBusPendingCall reply = QDBusConnection::systemBus().asyncCall(message); // This is a NO_REPLY method
00078     if (reply.reply().type() == QDBusMessage::ErrorMessage) {
00079         return false;
00080     }
00081 
00082     return true;
00083 }
00084 
00085 ActionReply DBusHelperProxy::executeAction(const QString &action, const QString &helperID, const QVariantMap &arguments)
00086 {
00087     if (!m_actionsInProgress.isEmpty()) {
00088         return ActionReply::HelperBusyReply;
00089     }
00090 
00091     QByteArray blob;
00092     QDataStream stream(&blob, QIODevice::WriteOnly);
00093 
00094     stream << arguments;
00095 
00096     QDBusConnection::systemBus().interface()->startService(helperID);
00097 
00098     if (!QDBusConnection::systemBus().connect(helperID, QLatin1String("/"), QLatin1String("org.kde.auth"), QLatin1String("remoteSignal"), this, SLOT(remoteSignalReceived(int, const QString &, QByteArray)))) {
00099         ActionReply errorReply = ActionReply::DBusErrorReply;
00100         errorReply.setErrorDescription(i18n("DBus Backend error: connection to helper failed. %1",
00101                                             QDBusConnection::systemBus().lastError().message()));
00102         return errorReply;
00103     }
00104 
00105     QDBusMessage message;
00106     message = QDBusMessage::createMethodCall(helperID, QLatin1String("/"), QLatin1String("org.kde.auth"), QLatin1String("performAction"));
00107 
00108     QList<QVariant> args;
00109     args << action << BackendsManager::authBackend()->callerID() << blob;
00110     message.setArguments(args);
00111 
00112     m_actionsInProgress.push_back(action);
00113 
00114     QEventLoop e;
00115     QDBusPendingCall pendingCall = QDBusConnection::systemBus().asyncCall(message);
00116     QDBusPendingCallWatcher watcher(pendingCall, this);
00117     connect(&watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), &e, SLOT(quit()));
00118     e.exec();
00119 
00120     QDBusMessage reply = pendingCall.reply();
00121 
00122     if (reply.type() == QDBusMessage::ErrorMessage) {
00123         ActionReply r = ActionReply::DBusErrorReply;
00124         r.setErrorDescription(i18n("DBus Backend error: could not contact the helper. "
00125                                    "Connection error: %1. Message error: %2", QDBusConnection::systemBus().lastError().message(),
00126                                    reply.errorMessage()));
00127         qDebug() << reply.errorMessage();
00128 
00129         // The remote signal will never arrive: so let's erase the action from the list ourselves
00130         m_actionsInProgress.removeOne(action);
00131 
00132         return r;
00133     }
00134 
00135     if (reply.arguments().size() != 1) {
00136         ActionReply errorReply = ActionReply::DBusErrorReply;
00137         errorReply.setErrorDescription(i18n("DBus Backend error: received corrupt data from helper %1 %2",
00138                                             reply.arguments().size(), QDBusConnection::systemBus().lastError().message()));
00139 
00140         // The remote signal may never arrive: so let's erase the action from the list ourselves
00141         m_actionsInProgress.removeOne(action);
00142 
00143         return errorReply;
00144     }
00145 
00146     return ActionReply::deserialize(reply.arguments().first().toByteArray());
00147 }
00148 
00149 Action::AuthStatus DBusHelperProxy::authorizeAction(const QString& action, const QString& helperID)
00150 {
00151     if (!m_actionsInProgress.isEmpty()) {
00152         return Action::Error;
00153     }
00154 
00155     QDBusConnection::systemBus().interface()->startService(helperID);
00156 
00157     QDBusMessage message;
00158     message = QDBusMessage::createMethodCall(helperID, QLatin1String("/"), QLatin1String("org.kde.auth"), QLatin1String("authorizeAction"));
00159 
00160     QList<QVariant> args;
00161     args << action << BackendsManager::authBackend()->callerID();
00162     message.setArguments(args);
00163 
00164     m_actionsInProgress.push_back(action);
00165 
00166     QEventLoop e;
00167     QDBusPendingCall pendingCall = QDBusConnection::systemBus().asyncCall(message);
00168     QDBusPendingCallWatcher watcher(pendingCall, this);
00169     connect(&watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), &e, SLOT(quit()));
00170     e.exec();
00171 
00172     m_actionsInProgress.removeOne(action);
00173 
00174     QDBusMessage reply = pendingCall.reply();
00175 
00176     if (reply.type() == QDBusMessage::ErrorMessage || reply.arguments().size() != 1) {
00177         return Action::Error;
00178     }
00179 
00180     return static_cast<Action::AuthStatus>(reply.arguments().first().toUInt());
00181 }
00182 
00183 bool DBusHelperProxy::initHelper(const QString &name)
00184 {
00185     new AuthAdaptor(this);
00186 
00187     if (!QDBusConnection::systemBus().registerService(name)) {
00188         return false;
00189     }
00190 
00191     if (!QDBusConnection::systemBus().registerObject(QLatin1String("/"), this)) {
00192         return false;
00193     }
00194 
00195     m_name = name;
00196 
00197     return true;
00198 }
00199 
00200 void DBusHelperProxy::setHelperResponder(QObject *o)
00201 {
00202     responder = o;
00203 }
00204 
00205 void DBusHelperProxy::remoteSignalReceived(int t, const QString &action, QByteArray blob)
00206 {
00207     SignalType type = (SignalType)t;
00208     QDataStream stream(&blob, QIODevice::ReadOnly);
00209 
00210     if (type == ActionStarted) {
00211         emit actionStarted(action);
00212     } else if (type == ActionPerformed) {
00213         ActionReply reply = ActionReply::deserialize(blob);
00214 
00215         m_actionsInProgress.removeOne(action);
00216         emit actionPerformed(action, reply);
00217     } else if (type == DebugMessage) {
00218         int level;
00219         QString message;
00220 
00221         stream >> level >> message;
00222 
00223         debugMessageReceived(level, message);
00224     } else if (type == ProgressStepIndicator) {
00225         int step;
00226         stream >> step;
00227 
00228         emit progressStep(action, step);
00229     } else if (type == ProgressStepData) {
00230         QVariantMap data;
00231         stream >> data;
00232 
00233         emit progressStep(action, data);
00234     }
00235 }
00236 
00237 void DBusHelperProxy::stopAction(const QString &action)
00238 {
00239     Q_UNUSED(action)
00240 #ifdef __GNUC__
00241 #warning FIXME: The stop request should be action-specific rather than global
00242 #endif
00243     m_stopRequest = true;
00244 }
00245 
00246 bool DBusHelperProxy::hasToStopAction()
00247 {
00248     QEventLoop loop;
00249     loop.processEvents(QEventLoop::AllEvents);
00250 
00251     return m_stopRequest;
00252 }
00253 
00254 void DBusHelperProxy::performActions(QByteArray blob, const QByteArray &callerID)
00255 {
00256     QDataStream stream(&blob, QIODevice::ReadOnly);
00257     QList< QPair< QString, QVariantMap > > actions;
00258 
00259     stream >> actions;
00260 
00261     QList< QPair< QString, QVariantMap > >::const_iterator i = actions.constBegin();
00262     while (i != actions.constEnd()) {
00263         QByteArray blob;
00264         QDataStream stream(&blob, QIODevice::WriteOnly);
00265 
00266         stream << i->second;
00267 
00268         performAction(i->first, callerID, blob);
00269 
00270         i++;
00271     }
00272 }
00273 
00274 QByteArray DBusHelperProxy::performAction(const QString &action, const QByteArray &callerID, QByteArray arguments)
00275 {
00276     if (!responder) {
00277         return ActionReply::NoResponderReply.serialized();
00278     }
00279 
00280     if (!m_currentAction.isEmpty()) {
00281         return ActionReply::HelperBusyReply.serialized();
00282     }
00283 
00284     QVariantMap args;
00285     QDataStream s(&arguments, QIODevice::ReadOnly);
00286     s >> args;
00287 
00288     m_currentAction = action;
00289     emit remoteSignal(ActionStarted, action, QByteArray());
00290     QEventLoop e;
00291     e.processEvents(QEventLoop::AllEvents);
00292 
00293     ActionReply retVal;
00294 
00295     QTimer *timer = responder->property("__KAuth_Helper_Shutdown_Timer").value<QTimer*>();
00296     timer->stop();
00297 
00298     if (BackendsManager::authBackend()->isCallerAuthorized(action, callerID)) {
00299         QString slotname = action;
00300         if (slotname.startsWith(m_name + QLatin1Char('.'))) {
00301             slotname = slotname.right(slotname.length() - m_name.length() - 1);
00302         }
00303 
00304         slotname.replace(QLatin1Char('.'), QLatin1Char('_'));
00305 
00306         bool success = QMetaObject::invokeMethod(responder, slotname.toAscii(), Qt::DirectConnection,
00307                                                  Q_RETURN_ARG(ActionReply, retVal), Q_ARG(QVariantMap, args));
00308 
00309         if (!success) {
00310             retVal = ActionReply::NoSuchActionReply;
00311         }
00312 
00313     } else {
00314         retVal = ActionReply::AuthorizationDeniedReply;
00315     }
00316 
00317     timer->start();
00318 
00319     emit remoteSignal(ActionPerformed, action, retVal.serialized());
00320     e.processEvents(QEventLoop::AllEvents);
00321     m_currentAction.clear();
00322     m_stopRequest = false;
00323 
00324     return retVal.serialized();
00325 }
00326 
00327 
00328 uint DBusHelperProxy::authorizeAction(const QString& action, const QByteArray& callerID)
00329 {
00330     if (!m_currentAction.isEmpty()) {
00331         return static_cast<uint>(Action::Error);
00332     }
00333 
00334     m_currentAction = action;
00335 
00336     uint retVal;
00337 
00338     QTimer *timer = responder->property("__KAuth_Helper_Shutdown_Timer").value<QTimer*>();
00339     timer->stop();
00340 
00341     if (BackendsManager::authBackend()->isCallerAuthorized(action, callerID)) {
00342         retVal = static_cast<uint>(Action::Authorized);
00343     } else {
00344         retVal = static_cast<uint>(Action::Denied);
00345     }
00346 
00347     timer->start();
00348     m_currentAction.clear();
00349 
00350     return retVal;
00351 }
00352 
00353 
00354 void DBusHelperProxy::sendDebugMessage(int level, const char *msg)
00355 {
00356     QByteArray blob;
00357     QDataStream stream(&blob, QIODevice::WriteOnly);
00358 
00359     stream << level << QString::fromLocal8Bit(msg);
00360 
00361     emit remoteSignal(DebugMessage, m_currentAction, blob);
00362 }
00363 
00364 void DBusHelperProxy::sendProgressStep(int step)
00365 {
00366     QByteArray blob;
00367     QDataStream stream(&blob, QIODevice::WriteOnly);
00368 
00369     stream << step;
00370 
00371     emit remoteSignal(ProgressStepIndicator, m_currentAction, blob);
00372 }
00373 
00374 void DBusHelperProxy::sendProgressStep(const QVariantMap &data)
00375 {
00376     QByteArray blob;
00377     QDataStream stream(&blob, QIODevice::WriteOnly);
00378 
00379     stream << data;
00380 
00381     emit remoteSignal(ProgressStepData, m_currentAction, blob);
00382 }
00383 
00384 void debugMessageReceived(int t, const QString &message)
00385 {
00386     QtMsgType type = (QtMsgType)t;
00387     switch (type) {
00388     case QtDebugMsg:
00389         qDebug("Debug message from helper: %s", message.toAscii().data());
00390         break;
00391     case QtWarningMsg:
00392         qWarning("Warning from helper: %s", message.toAscii().data());
00393         break;
00394     case QtCriticalMsg:
00395         qCritical("Critical warning from helper: %s", message.toAscii().data());
00396         break;
00397     case QtFatalMsg:
00398         qFatal("Fatal error from helper: %s", message.toAscii().data());
00399         break;
00400     }
00401 }
00402 
00403 } // namespace Auth
00404 
00405 Q_EXPORT_PLUGIN2(kauth_helper_backend, KAuth::DBusHelperProxy)

KDECore

Skip menu "KDECore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal