diff --git a/CMakeLists.txt b/CMakeLists.txt index e1aa52f40..81eee0fc7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,3 @@ - include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_BINARY_DIR}/kdecore/ ${CMAKE_SOURCE_DIR}/kdecore/ @@ -31,7 +30,19 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_BINARY_DIR}/solid/ ${CMAKE_SOURCE_DIR}/solid/ ${CMAKE_SOURCE_DIR}/threadweaver/ - ${KDE4_INCLUDES}) + ${CMAKE_SOURCE_DIR}/plasma/private/qtjolie-branch/qtjolie + ${CMAKE_SOURCE_DIR}/plasma/private/qtjolie-branch + ${CMAKE_SOURCE_DIR}/plasma/private/qtjolie-branch/includes + ${KDE4_INCLUDES} + #/mnt/data/kde/include + ) + +#find_package(QtJolie REQUIRED) +find_package(QCA2 REQUIRED) +#find_package(DNSSD REQUIRED) +include_directories(${QCA2_INCLUDES}) +include_directories(${QTJOLIE_INCLUDE_DIRS}) + if(QT_QTOPENGL_FOUND AND OPENGL_FOUND) # libGL needs dlopen() and friends from the dl library find_library(DL_LIBRARY dl) @@ -39,8 +50,6 @@ if(QT_QTOPENGL_FOUND AND OPENGL_FOUND) include_directories(${OPENGL_INCLUDE_DIR}) endif(QT_QTOPENGL_FOUND AND OPENGL_FOUND) -find_package(libQtJolie REQUIRED) - add_subdirectory(tests) add_definitions(-DKDE_DEFAULT_DEBUG_AREA=1209) @@ -59,6 +68,11 @@ set(plasma_LIB_SRCS animationdriver.cpp animator.cpp applet.cpp + authorizationinterface.cpp + authorizationmanager.cpp + authorizationrule.cpp + clientpinrequest.cpp + credentials.cpp configloader.cpp containment.cpp containmentactions.cpp @@ -68,6 +82,7 @@ set(plasma_LIB_SRCS dataengine.cpp dataenginemanager.cpp delegate.cpp + private/denyallauthorization.cpp dialog.cpp extender.cpp extendergroup.cpp @@ -75,20 +90,31 @@ set(plasma_LIB_SRCS paintutils.cpp framesvg.cpp plasma.cpp + accessappletjob.cpp popupapplet.cpp private/applethandle.cpp private/datacontainer_p.cpp + private/dataengineconsumer.cpp + private/dataengineservice.cpp private/desktoptoolbox.cpp private/extenderapplet.cpp private/extenderitemmimedata.cpp + private/getpublickey.cpp + private/getsource.cpp private/nativetabbar.cpp private/packages.cpp private/paneltoolbox.cpp + private/pinpairingauthorization.cpp + private/pinpairingdialog.cpp + private/plasmoidservice.cpp + private/publickeyservice.cpp + private/remotedataengine.cpp private/remoteservice.cpp private/remoteservicejob.cpp private/runnerjobs.cpp private/serviceprovider.cpp private/style.cpp + private/trustedonlyauthorization.cpp private/toolbox.cpp private/tooltip.cpp private/wallpaperrenderthread.cpp @@ -138,8 +164,25 @@ set(plasma_LIB_SRCS widgets/treeview.cpp widgets/textedit.cpp widgets/webview.cpp + + #Temporary QtJolie branch + private/qtjolie-branch/qtjolie/abstractadaptor.cpp + private/qtjolie-branch/qtjolie/client.cpp + private/qtjolie-branch/qtjolie/clientthread.cpp + private/qtjolie-branch/qtjolie/value.cpp + private/qtjolie-branch/qtjolie/fault.cpp + private/qtjolie-branch/qtjolie/message.cpp + private/qtjolie-branch/qtjolie/metaservice.cpp + private/qtjolie-branch/qtjolie/pendingcall.cpp + private/qtjolie-branch/qtjolie/pendingcallwatcher.cpp + private/qtjolie-branch/qtjolie/pendingreply.cpp + private/qtjolie-branch/qtjolie/server.cpp + private/qtjolie-branch/qtjolie/serverthread.cpp ) +kde4_add_ui_files(plasma_LIB_SRCS + private/pinpairing.ui + private/publish.ui) #NEPOMUK_GENERATE_FROM_ONTOLOGY( # nwc.nrl # ${metadata_test_BINARY_DIR} @@ -164,9 +207,9 @@ endif(PHONON_FOUND) kde4_add_library(plasma SHARED ${plasma_LIB_SRCS}) -target_link_libraries(plasma ${KDE4_KIO_LIBS} ${KDE4_KFILE_LIBS} knewstuff2 libQtJolie +target_link_libraries(plasma ${KDE4_KIO_LIBS} ${KDE4_KFILE_LIBS} knewstuff2 ${QCA2_LIBRARIES} ${QT_QTUITOOLS_LIBRARY} ${QT_QTWEBKIT_LIBRARY} - threadweaver ${KDE4_SOLID_LIBS} ) + kdnssd threadweaver ${KDE4_SOLID_LIBS} ) if(X11_FOUND) target_link_libraries(plasma ${X11_LIBRARIES}) endif(X11_FOUND) @@ -207,14 +250,19 @@ install(FILES ${plasmagik_HEADERS} DESTINATION ${INCLUDE_INSTALL_DIR}/plasma/ CO set(plasma_LIB_INCLUDES abstractrunner.h accessmanager.h + authorizationmanager.h + authorizationrule.h + authorizationinterface.h animationdriver.h animator.h applet.h + clientpinrequest.h configloader.h containment.h containmentactions.h context.h corona.h + credentials.h datacontainer.h dataengine.h dataenginemanager.h @@ -228,6 +276,7 @@ set(plasma_LIB_INCLUDES framesvg.h plasma.h plasma_export.h + accessappletjob.h popupapplet.h querymatch.h runnercontext.h @@ -318,3 +367,5 @@ install(FILES scripting/plasmoids.knsrc DESTINATION ${CONFIG_INSTALL_DIR}) install(FILES plasma_popupapplet_fix_groups.upd DESTINATION ${KCONF_UPDATE_INSTALL_DIR}) install(PROGRAMS plasma_popupapplet_fix_groups.pl DESTINATION ${KCONF_UPDATE_INSTALL_DIR}) +install(FILES dataengineservice.operations DESTINATION ${DATA_INSTALL_DIR}/plasma/services) +install(FILES plasmoidservice.operations DESTINATION ${DATA_INSTALL_DIR}/plasma/services) diff --git a/accessappletjob.cpp b/accessappletjob.cpp new file mode 100644 index 000000000..bd4c4dbd9 --- /dev/null +++ b/accessappletjob.cpp @@ -0,0 +1,159 @@ +/* + * Copyright 2009 Rob Scheepmaker + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "accessappletjob.h" + +#include "service.h" +#include "servicejob.h" +#include "applet.h" + +#include +#include +#include +#include +#include "package.h" +#include +#include "private/applet_p.h" + +namespace Plasma +{ + +class AccessAppletJobPrivate +{ +public: + AccessAppletJobPrivate(const KUrl &location, AccessAppletJob *owner) + : q(owner), + location(location) + { + } + + void slotStart() + { + q->start(); + } + + void slotServiceReady(Plasma::Service *service) + { + KConfigGroup op = service->operationDescription("GetPackage"); + service->startOperationCall(op); + q->connect(service, SIGNAL(finished(Plasma::ServiceJob*)), + q, SLOT(slotPackageDownloaded(Plasma::ServiceJob*))); + } + + void slotPackageDownloaded(Plasma::ServiceJob *job) + { + if (job->error()) { + kDebug() << "Plasmoid Access Job triggers an error."; + q->setError(job->error()); + q->setErrorText(job->errorText()); + } + + //TODO: there's some duplication with installPackage, but we don't want to actually install + //the fetched package. Just extract the archive somewhere in a temp directory. + if (job->result().type() == QVariant::String) { + QString pluginName = job->result().toString(); + kDebug() << "Server responded with a pluginname, trying to load: " << pluginName; + + applet = Applet::load(pluginName); + if (applet) { + applet->d->remoteLocation = location.prettyUrl(); + } else { + q->setError(-1); + q->setErrorText(i18n("You don't got the widget %1 installed.", pluginName)); + } + + q->emitResult(); + } else { + kDebug() << "Server responded with a plasmoid package"; + //read, and extract the plasmoid package to a temporary directory + QByteArray package = job->result().toByteArray(); + QDataStream stream(&package, QIODevice::ReadOnly); + + KZip archive(stream.device()); + if (!archive.open(QIODevice::ReadOnly)) { + kWarning() << "Could not open package file"; + q->setError(-1); + q->setErrorText(i18n("Server sent an invalid plasmoid package.")); + q->emitResult(); + return; + } + + const KArchiveDirectory *source = archive.directory(); + + KTempDir tempDir; + tempDir.setAutoRemove(false); + QString path = tempDir.name(); + source->copyTo(path); + + /** + QString metadataFilename = path + "/metadata.desktop"; + KDesktopFile cfg(metadataFilename); + KConfigGroup config = cfg.desktopGroup(); + config.writeEntry("EngineLocation", location.prettyUrl()); + config.sync(); + */ + + applet = Applet::loadPlasmoid(path); + applet->d->remoteLocation = location.prettyUrl(); + q->emitResult(); + } + } + + void slotTimeout() + { + kWarning() << "Plasmoid access job timed out"; + q->setError(-1); + q->setErrorText(i18n("Timeout")); + q->emitResult(); + } + + AccessAppletJob *q; + KUrl location; + Applet *applet; +}; + +AccessAppletJob::AccessAppletJob(const KUrl &location, QObject *parent) + : KJob(parent), + d(new AccessAppletJobPrivate(location, this)) +{ + QTimer::singleShot(30000, this, SLOT(slotTimeout())); +} + +AccessAppletJob::~AccessAppletJob() +{ + delete d; +} + +Applet *AccessAppletJob::applet() const +{ + return d->applet; +} + +void AccessAppletJob::start() +{ + kDebug() << "fetching a plasmoid from location = " << d->location.prettyUrl(); + Service *service = Service::access(d->location); + connect(service, SIGNAL(serviceReady(Plasma::Service*)), + this, SLOT(slotServiceReady(Plasma::Service*))); +} + +} // namespace Plasma + +#include "accessappletjob.moc" + diff --git a/accessappletjob.h b/accessappletjob.h new file mode 100644 index 000000000..94065fc75 --- /dev/null +++ b/accessappletjob.h @@ -0,0 +1,80 @@ +/* + * Copyright 2009 Rob Scheepmaker + +#include + +class KUrl; + +namespace Plasma +{ + +class Applet; +class AccessAppletJobPrivate; + +/** + * @class AccessAppletJob plasma/accessappletjob.h + * + * @short This class is used for asynchronously accessing an applet published on a remote system. + * After calling AccessManager::accessApplet, monitor this job to track when the remote applet + * is ready to be used, and to obtain the service when finished. + */ +class PLASMA_EXPORT AccessAppletJob : public KJob +{ + Q_OBJECT + +public: + ~AccessAppletJob(); + + Applet *applet() const; + +protected: + /** + * Default constructor + * + * @arg location the location of the service + * @arg parent the parent object for this service + */ + AccessAppletJob(const KUrl &location, QObject *parent = 0); + + void start(); + +private: + AccessAppletJob(); + + Q_PRIVATE_SLOT(d, void slotPackageDownloaded(Plasma::ServiceJob*)) + Q_PRIVATE_SLOT(d, void slotStart()) + Q_PRIVATE_SLOT(d, void slotServiceReady(Plasma::Service*)) + Q_PRIVATE_SLOT(d, void slotTimeout()) + + AccessAppletJobPrivate * const d; + + friend class AccessManager; + friend class AccessManagerPrivate; + friend class AccessAppletJobPrivate; +}; + +} // namespace Plasma + +#endif // multiple inclusion guard + diff --git a/accessmanager.cpp b/accessmanager.cpp index 623747e2e..3630ed845 100644 --- a/accessmanager.cpp +++ b/accessmanager.cpp @@ -18,6 +18,7 @@ */ #include "accessmanager.h" +#include "private/accessmanager_p.h" #include "service.h" #include "serviceaccessjob.h" @@ -25,48 +26,29 @@ #include #include -#include #include +#include #include +#include +#include +#include +#include +#include +#include +#include namespace Plasma { -class AccessManagerPrivate -{ - public: - AccessManagerPrivate() - { - //TODO: store at a sensible place... kwallet keyring for private key maybe? - privateKey = QCA::PrivateKey::fromPemFile("/home/rob/plasma_private_key.pem"); - publicKey = QCA::PrivateKey::fromPemFile("/home/rob/plasma_public_key.pem"); - if (privateKey.isNull()) { - //generate public/private key pair - QCA::KeyGenerator generator; - privateKey = generator.createRSA(2048); - publicKey = privateKey.toPublicKey(); - privateKey.toPEMFile("/home/rob/plasma_private_key.pem"); - publicKey.toPEMFile("/home/rob/plasma_public_key.pem"); - } - }; - - ~AccessManagerPrivate() {}; - - //TODO: is this bool based authorisation management detailed enough? - QMap >; - //Needed for QCA support - QCA::Initializer initializer; - QCA:PrivateKey privateKey; - QCA:PrivateKey publicKey; -}; - class AccessManagerSingleton { public: AccessManager self; }; +//FIXME: AccessManagerSignleton could be removed to remove a friend. +//see kdelibs/kutils/kidletime/xsyncbasedpoller.cpp K_GLOBAL_STATIC(AccessManagerSingleton, privateAccessManagerSelf) AccessManager *AccessManager::self() @@ -75,8 +57,10 @@ AccessManager *AccessManager::self() } AccessManager::AccessManager() - : d(new AccessManagerPrivate) + : QObject(), + d(new AccessManagerPrivate(this)) { + KGlobal::dirs()->addResourceType("trustedkeys", "config", "trustedkeys/"); } AccessManager::~AccessManager() @@ -84,30 +68,101 @@ AccessManager::~AccessManager() delete d; } -Jolie::Message AccessManager::signMessage(Jolie::Message message) const +AccessAppletJob *AccessManager::accessRemoteApplet(const KUrl &location) const { - //TODO:what about multiple interfaces? - QString host = QNetworkInterface::allAddresses().first(); - message.children("host") << Jolie::Value(host); - QByteArray serializedMessage = //serialize sodep message - QByteArray signature = d->privateKey->signMessage(MemoryRegion(serializedMessage)); - message.children("signature") << Jolie::Value(signature); - return message; -} + kDebug() << "unresolved location = " << location.prettyUrl(); -ServiceAccessJob* AccessManager::accessService(KUrl location) const -{ - ServiceAccesJob *job = new ServiceAccessJob(location); + KUrl resolvedLocation; + if (location.protocol() == "zeroconf") { + if (d->zeroconfServices.contains(location.host())) { + resolvedLocation = d->services[location.host()].remoteLocation(); + } else { + kDebug() << "not in the map"; + } + } else { + resolvedLocation = location; + } + + AccessAppletJob *job = new AccessAppletJob(resolvedLocation); + connect(job, SIGNAL(finished(KJob*)), this, SLOT(slotJobFinished(KJob*))); QTimer::singleShot(0, job, SLOT(slotStart())); return job; } -ServiceAccessJob* AccessManager::accessService(const QString &jolieScript, - const QMap &initValues) const +QList AccessManager::remoteApplets() const { - ServiceAccesJob *job = new ServiceAccessJob(jolieScript, initValues); - QTimer::singleShot(0, job, SLOT(slotStart())); - return job; + return d->services.values(); +} + +AccessManagerPrivate::AccessManagerPrivate(AccessManager *manager) + : q(manager), + browser(new DNSSD::ServiceBrowser("_plasma._tcp")) +{ + q->connect(browser, SIGNAL(serviceAdded(DNSSD::RemoteService::Ptr)), + q, SLOT(slotAddService(DNSSD::RemoteService::Ptr))); + q->connect(browser, SIGNAL(serviceRemoved(DNSSD::RemoteService::Ptr)), + q, SLOT(slotRemoveService(DNSSD::RemoteService::Ptr))); + browser->startBrowse(); +} + +AccessManagerPrivate::~AccessManagerPrivate() +{ + delete browser; +} + +void AccessManagerPrivate::slotJobFinished(KJob *job) +{ + emit q->finished(static_cast(job)); +} + +void AccessManagerPrivate::slotAddService(DNSSD::RemoteService::Ptr service) +{ + kDebug(); + if (!service->resolve()) { + kDebug() << "can't be resolved"; + return; + } + + if (!services.contains(service->serviceName())) { + PackageMetadata metadata; + kDebug() << "textdata = " << service->textData(); + kDebug() << "hostname: " << service->hostName(); + QHostAddress address = DNSSD::ServiceBrowser::resolveHostName(service->hostName()); + QString ip = address.toString(); + kDebug() << "result for resolve = " << ip; + + KUrl url(QString("plasma://%1:%2/%3").arg(ip) + .arg(service->port()) + .arg(service->serviceName())); + + if (!service->textData().isEmpty()) { + kDebug() << "service has got textdata"; + QMap textData = service->textData(); + metadata.setName(textData["name"]); + metadata.setDescription(textData["description"]); + metadata.setRemoteLocation(url.prettyUrl()); + } else { + kDebug() << "no textdata?"; + metadata.setName(service->serviceName()); + metadata.setRemoteLocation(url.prettyUrl()); + } + + kDebug() << "location = " << metadata.remoteLocation(); + kDebug() << "name = " << metadata.name(); + kDebug() << "description = " << metadata.name(); + + services[service->serviceName()] = metadata; + zeroconfServices[service->serviceName()] = service; + emit q->remoteAppletAnnounced(metadata); + } +} + +void AccessManagerPrivate::slotRemoveService(DNSSD::RemoteService::Ptr service) +{ + kDebug(); + emit q->remoteAppletUnannounced(services[service->serviceName()]); + services.remove(service->serviceName()); + zeroconfServices.remove(service->serviceName()); } } // Plasma namespace diff --git a/accessmanager.h b/accessmanager.h index e65036704..c81bf44e8 100644 --- a/accessmanager.h +++ b/accessmanager.h @@ -22,38 +22,39 @@ #include "plasma_export.h" +#include #include +#include + +#include +#include "accessappletjob.h" +#include "packagemetadata.h" class QString; -class QMap; class KUrl; namespace Plasma { +class AccessManagerPrivate; class ServiceAccessJob; /** * @class AccessManager plasma/accessmanager.h * - * @short Allows access to remote Plasma::Service, Plasma::DataEngine and Plasma::Applet classes. + * @short Allows access to remote Plasma::Applet classes. * - * This manager provides a way to access a Plasma::Service, Plasma::DataEngine or Plasma::Applet - * that is hosted on another machine. Besides functions to access those resources, this class is - * also the place that tracks which remote computers are allowed to access each published resource, - * and it provides a mechanism to discover services announced to the network through zeroconf or + * This manager provides a way to access a plasmoid that is hosted on another machine. It also + * provides a mechanism to discover services announced to the network through zeroconf or * bluetooth. - * All url's passed to the access functions need to be valid JOLIE urls, that have this format: - * plasma://:/!/ - * All access function are asynchronous. The services need to be accessed over the network, and - * might even have to be authorized by the user of that machine first. All access functions - * therefore return a job that can be monitored to see when the service is ready for use. * - * @since 4.4? + * @since 4.4 */ + class PLASMA_EXPORT AccessManager : public QObject { Q_OBJECT + public: /** * Singleton pattern accessor. @@ -61,43 +62,35 @@ class PLASMA_EXPORT AccessManager : public QObject static AccessManager *self(); /** - * Access a native Plasma::Service hosted on another machine. - * - * @param location a valid JOLIE url - * @returns a job that can be monitored to see when access to the remote service is - * obtained, or if it failed. + * Access a native plasmoid hosted on another machine. + * @param location the location of the remote plasmoids. Exmples of valid urls: + * plasma://ip:port/resourceName + * zeroconf://PlasmoidName + * @returns a job that can be used to track when a remote plasmoid is ready for use, and to + * obtain the applet when the package is sent over. */ - ServiceAccessJob* accessService(KUrl location) const; + AccessAppletJob *accessRemoteApplet(const KUrl &location) const; /** - * TODO: I think there should be a more elegant way to access SOAP services right? Plus if - * we want this to work with RemoteService, the JOLIE script is required to have the exact - * native plasma service interface.... which means, amonst others: provide an - * operationsDescription operation which returns valid ConfigXml. This way of accessing is - * easy enough, but I fear the creation of the jolieScript will become more complicated then - * it needs to be.... or we need to have some utility in the feature that automagically - * creates JOLIE script from WSDL... which would be totally awesome. - * Create a Plasma::Service that accesses a not native Plasma::Service like a SOAP service. - * To accomplish this you'll need to provide the name of a JOLIE script that accesses this - * service and has a valid interface (TODO: I'll need to provide a include for jolie scripts - * for this) and optionally a map that will be passed to the JOLIE script's init function, - * and can contain things like username/password, url etc. - * @param jolieScript filename of the jolie script. TODO: which path's to look? - * @param initValues map of strings>variants that will get passed to the jolie script's init - * function. - * @returns a job that can be monitored to see when access to the remote service is - * obtained, or if it failed. + * @returns a map mapping service names to the plasmoid's metadata. */ - ServiceAccessJob* accessService(const QString &jolieScript, - const QMap &initValues) const; + QList remoteApplets() const; - Jolie::Message signMessage(Jolie::Message message) const; + Q_SIGNALS: + /** + * fires when a AccessAppletJob is finished. + */ + void finished(Plasma::AccessAppletJob*); - //TODO: access functions for engines and applets... which are higher level things built on - //top of Plasma::Service, which means I'll first need to get services working and - //everything. + /** + * fires when a new plasmoid is announced on the network. + */ + void remoteAppletAnnounced(Plasma::PackageMetadata metadata); - //TODO: functions for service discovery through bluetooth and zeroconf + /** + * fires when an announced plasmoid disappears from the network. + */ + void remoteAppletUnannounced(Plasma::PackageMetadata metadata); private: AccessManager(); @@ -105,6 +98,11 @@ class PLASMA_EXPORT AccessManager : public QObject AccessManagerPrivate * const d; + Q_PRIVATE_SLOT(d, void slotJobFinished(KJob*)) + Q_PRIVATE_SLOT(d, void slotAddService(DNSSD::RemoteService::Ptr service)) + Q_PRIVATE_SLOT(d, void slotRemoveService(DNSSD::RemoteService::Ptr service)) + + friend class AccessManagerPrivate; friend class AccessManagerSingleton; }; } // Plasma namespace diff --git a/applet.cpp b/applet.cpp index 951b2a0db..c7618adca 100644 --- a/applet.cpp +++ b/applet.cpp @@ -62,6 +62,7 @@ #include +#include "authorizationmanager.h" #include "configloader.h" #include "containment.h" #include "corona.h" @@ -85,11 +86,17 @@ #include "wallpaper.h" #include "paintutils.h" +#include "private/authorizationmanager_p.h" #include "private/containment_p.h" #include "private/extenderapplet_p.h" +#include "private/package_p.h" #include "private/packages_p.h" +#include "private/plasmoidservice.h" #include "private/popupapplet_p.h" +#include "private/service_p.h" +#include "private/remotedataengine.h" #include "private/toolbox_p.h" +#include "ui_publish.h" namespace Plasma { @@ -299,6 +306,10 @@ void Applet::restore(KConfigGroup &group) // local shortcut, if any //TODO: implement; the shortcut will need to be registered with the containment /* +#include "accessmanager.h" +#include "private/plasmoidservice.h" +#include "authorizationmanager.h" +#include "authorizationmanager.h" shortcutText = shortcutConfig.readEntryUntranslated("local", QString()); if (!shortcutText.isEmpty()) { //TODO: implement; the shortcut @@ -590,7 +601,6 @@ void AppletPrivate::destroyMessageOverlay() buttonCode = ButtonNo; } if (button->text() == i18n("Cancel")) { - buttonCode = ButtonCancel; } emit q->messageButtonPressed(buttonCode); @@ -604,7 +614,15 @@ ConfigLoader *Applet::configScheme() const DataEngine *Applet::dataEngine(const QString &name) const { - return d->dataEngine(name); + if (!d->remoteLocation.isEmpty()) { + return d->remoteDataEngine(KUrl(d->remoteLocation), name); + } + + if (!package() || package()->metadata().remoteLocation().isEmpty()) { + return d->dataEngine(name); + } else { + return d->remoteDataEngine(KUrl(package()->metadata().remoteLocation()), name); + } } const Package *Applet::package() const @@ -1435,6 +1453,38 @@ bool Applet::hasConfigurationInterface() const return d->hasConfigurationInterface; } +void Applet::publish(AnnouncementMethods methods) +{ + if (!d->service) { + d->service = new PlasmoidService(this); + } + + QString resourceName = + i18nc("%1 is the name of a plasmoid, %2 the name of the machine that plasmoid is published on", + "%1 on %2", name(), AuthorizationManager::self()->d->myCredentials.name()); + kDebug() << "publishing package under name " << resourceName; + d->service->d->publish(methods, resourceName, PackageMetadata()); +} + +void Applet::unpublish() +{ + if (d->service) { + d->service->d->unpublish(); + } +} + +bool Applet::isPublished() const +{ + if (d->service) { + return d->service->d->isPublished(); + } else { + return false; + } +} + + +//it bugs me that this can get turned on and off at will. I don't see it being useful and it just +//makes more work for me and more code duplication. void Applet::setHasConfigurationInterface(bool hasInterface) { if (d->hasConfigurationInterface == hasInterface) { @@ -1589,6 +1639,9 @@ void Applet::showConfigurationInterface() } d->addGlobalShortcutsPage(dialog); + d->addPublishPage(dialog); + //connect(dialog, SIGNAL(applyClicked()), this, SLOT(configDialogFinished())); + //connect(dialog, SIGNAL(okClicked()), this, SLOT(configDialogFinished())); dialog->show(); } else if (d->script) { d->script->showConfigurationInterface(); @@ -1646,6 +1699,13 @@ KConfigDialog *AppletPrivate::generateGenericConfigDialog() dialog->setFaceType(KPageDialog::Auto); dialog->setWindowTitle(configWindowTitle()); dialog->setAttribute(Qt::WA_DeleteOnClose, true); + q->createConfigurationInterface(dialog); + addGlobalShortcutsPage(dialog); + addPublishPage(dialog); + //TODO: Apply button does not correctly work for now, so do not show it + dialog->showButton(KDialog::Apply, false); + QObject::connect(dialog, SIGNAL(applyClicked()), q, SLOT(configDialogFinished())); + QObject::connect(dialog, SIGNAL(okClicked()), q, SLOT(configDialogFinished())); QObject::connect(dialog, SIGNAL(finished()), nullManager, SLOT(deleteLater())); return dialog; } @@ -1675,6 +1735,20 @@ void AppletPrivate::addGlobalShortcutsPage(KConfigDialog *dialog) QObject::connect(dialog, SIGNAL(okClicked()), q, SLOT(configDialogFinished())); } +void AppletPrivate::addPublishPage(KConfigDialog *dialog) +{ + /** + if (!package) { + return; + } + */ + + QWidget *page = new QWidget; + publishUI.setupUi(page); + publishUI.publishCheckbox->setChecked(q->config().readEntry("Publish", false)); + dialog->addPage(page, i18n("Publish"), "applications-internet"); +} + void AppletPrivate::clearShortcutEditorPtr() { shortcutEditor = 0; @@ -1690,6 +1764,21 @@ void AppletPrivate::configDialogFinished() } } + q->config().writeEntry("Publish", publishUI.publishCheckbox->isChecked()); + if (package) { + if (publishUI.publishCheckbox->isChecked()) { + package->d->publish(Plasma::ZeroconfAnnouncement); + } else { + package->d->unpublish(); + } + } else { + if (publishUI.publishCheckbox->isChecked()) { + q->publish(Plasma::ZeroconfAnnouncement); + } else { + q->unpublish(); + } + } + if (!configLoader) { // the config loader will trigger this for us, so we don't need to. q->configChanged(); @@ -2185,12 +2274,13 @@ bool Applet::isContainment() const AppletPrivate::AppletPrivate(KService::Ptr service, int uniqueID, Applet *applet) : appletId(uniqueID), q(applet), - backgroundHints(Applet::NoBackground), + extender(0), + service(0), preferredBackgroundHints(Applet::StandardBackground), + backgroundHints(Applet::StandardBackground), aspectRatioMode(Plasma::KeepAspectRatio), immutability(Mutable), appletDescription(service), - extender(0), background(0), mainConfig(0), pendingConstraints(NoConstraint), @@ -2333,6 +2423,20 @@ void AppletPrivate::init(const QString &packagePath) configAction->setText(i18nc("%1 is the name of the applet", "%1 Settings", q->name())); } + if (package) { + if (q->config().readEntry("Publish", false)) { + package->d->publish(Plasma::ZeroconfAnnouncement); + } else { + package->d->unpublish(); + } + } else { + if (q->config().readEntry("Publish", false)) { + q->publish(Plasma::ZeroconfAnnouncement); + } else { + q->unpublish(); + } + } + QObject::connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), q, SLOT(themeChanged())); QObject::connect(q, SIGNAL(activate()), q, SLOT(setFocus())); } @@ -2419,6 +2523,7 @@ KConfigGroup *AppletPrivate::mainConfigGroup() return mainConfig; } + bool newGroup = false; if (isContainment) { Corona *corona = qobject_cast(q->scene()); KConfigGroup containmentConfig; @@ -2430,6 +2535,10 @@ KConfigGroup *AppletPrivate::mainConfigGroup() containmentConfig = KConfigGroup(KGlobal::config(), "Containments"); } + if (!containmentConfig.hasGroup(QString::number(appletId))) { + newGroup = true; + } + mainConfig = new KConfigGroup(&containmentConfig, QString::number(appletId)); } else { KConfigGroup appletConfig; @@ -2451,9 +2560,21 @@ KConfigGroup *AppletPrivate::mainConfigGroup() appletConfig = KConfigGroup(KGlobal::config(), "Applets"); } + if (!appletConfig.hasGroup(QString::number(appletId))) { + newGroup = true; + } + mainConfig = new KConfigGroup(&appletConfig, QString::number(appletId)); } + if (newGroup && q->package()) { + //see if we have a default configuration in our package + kDebug() << "copying default config: " << q->package()->filePath("defaultconfig"); + KConfigGroup defaultConfig(KSharedConfig::openConfig(q->package()->filePath("config", + "default-configrc"))->group("Configuration")); + defaultConfig.copyTo(mainConfig); + } + return mainConfig; } diff --git a/applet.h b/applet.h index 4905c8697..5cc228af0 100644 --- a/applet.h +++ b/applet.h @@ -788,6 +788,12 @@ class PLASMA_EXPORT Applet : public QGraphicsWidget */ void setStatus(const ItemStatus stat); + void publish(Plasma::AnnouncementMethods method); + + void unpublish(); + + bool isPublished() const; + protected: /** * This constructor is to be used with the plugin loading systems @@ -1002,6 +1008,7 @@ class PLASMA_EXPORT Applet : public QGraphicsWidget friend class AppletScript; friend class AppletHandle; friend class AppletPrivate; + friend class AccessAppletJobPrivate; friend class PopupApplet; friend class PopupAppletPrivate; diff --git a/authorizationinterface.cpp b/authorizationinterface.cpp new file mode 100644 index 000000000..10cc5b2be --- /dev/null +++ b/authorizationinterface.cpp @@ -0,0 +1,37 @@ +/* + * Copyright 2009 by Rob Scheepmaker + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "authorizationinterface.h" + +#include "authorizationrule.h" + + +namespace Plasma +{ + +AuthorizationInterface::AuthorizationInterface() +{ +} + +AuthorizationInterface::~AuthorizationInterface() +{ +} + +} // Plasma namespace + diff --git a/authorizationinterface.h b/authorizationinterface.h new file mode 100644 index 000000000..289ec7d24 --- /dev/null +++ b/authorizationinterface.h @@ -0,0 +1,79 @@ +/* + * Copyright 2009 by Rob Scheepmaker + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef PLASMA_AUTHORIZATIONINTERFACE_H +#define PLASMA_AUTHORIZATIONINTERFACE_H + +#include "plasma_export.h" + +#include + +class QString; +class KUrl; + +namespace Plasma +{ + +class AuthorizationRule; +class ClientPinRequest; + +/** + * @class AuthorizationInterface plasma/authorizationinterface.h + * + * @short Allows authorization of access to plasma services. + * + * This class is only needed when you create a plasma shell. When you implement it and register it + * with the AuthorizationManager class, it allows you to respond to incoming service access + * attempts. Whenever a message is received that does not match any of the AuthorizationRules, + * AuthorizationManager creates a new rule matching it, and passes it to the authorize function. + * Change the rule from Unspecified to something else like Allow or Deny to continue processing the + * message. + * It also allows you to outgoing access attempts that require pin pairing, to allow your shell to + * show a dialog to ask the user for a password. + * + * @since 4.4 + */ +class PLASMA_EXPORT AuthorizationInterface +{ + public: + virtual ~AuthorizationInterface(); + + /** + * implement this function to respond to an incoming request that doesn't match any rule. + * @param rule a new AuthorizationRule matching an incoming operation. Call setRules on this + * rule to allow/deny the operation. + */ + virtual void authorizationRequest(AuthorizationRule &rule) = 0; + + /** + * Implement this function to respond to an outgoing connection that needs a password to + * connect succesfully. As a response to this you'll probably want to show a dialog. + * @param request a ClientPinRequest where you can call setPin on to set the pin for the + * outgoing connection. + */ + virtual void clientPinRequest(ClientPinRequest &request) = 0; + + protected: + AuthorizationInterface(); +}; + +} // Plasma namespace + +#endif + diff --git a/authorizationmanager.cpp b/authorizationmanager.cpp new file mode 100644 index 000000000..2cbee62e6 --- /dev/null +++ b/authorizationmanager.cpp @@ -0,0 +1,288 @@ +/* + * Copyright 2009 by Rob Scheepmaker + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "authorizationmanager.h" +#include "private/authorizationmanager_p.h" + +#include "authorizationinterface.h" +#include "authorizationrule.h" +#include "credentials.h" +#include "service.h" +#include "servicejob.h" + +#include "private/authorizationrule_p.h" +#include "private/denyallauthorization.h" +#include "private/pinpairingauthorization.h" +#include "private/trustedonlyauthorization.h" +#include "private/joliemessagehelper_p.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace Plasma +{ + +class AuthorizationManagerSingleton +{ + public: + AuthorizationManager self; +}; + +K_GLOBAL_STATIC(AuthorizationManagerSingleton, privateAuthorizationManagerSelf) + +AuthorizationManager *AuthorizationManager::self() +{ + return &privateAuthorizationManagerSelf->self; +} + +AuthorizationManager::AuthorizationManager() + : QObject(), + d(new AuthorizationManagerPrivate(this)) +{ + qRegisterMetaTypeStreamOperators("Plasma::Credentials"); +} + +AuthorizationManager::~AuthorizationManager() +{ + delete d; +} + +void AuthorizationManager::setAuthorizationPolicy(AuthorizationPolicy policy) +{ + if (d->locked) { + kDebug() << "Can't change AuthorizationPolicy: interface locked."; + return; + } + + if (policy == d->authorizationPolicy) { + return; + } + + d->authorizationPolicy = policy; + + if (d->authorizationInterface != d->customAuthorizationInterface) { + delete d->authorizationInterface; + } + + switch (policy) { + case DenyAll: + d->authorizationInterface = new DenyAllAuthorization(); + break; + case PinPairing: + d->authorizationInterface = new PinPairingAuthorization(); + break; + case TrustedOnly: + d->authorizationInterface = new TrustedOnlyAuthorization(); + break; + case Custom: + d->authorizationInterface = d->customAuthorizationInterface; + break; + } + + d->locked = true; +} + +void AuthorizationManager::setAuthorizationInterface(AuthorizationInterface *interface) +{ + if (d->authorizationInterface) { + kDebug() << "Can't change AuthorizationInterface: interface locked."; + return; + } + + delete d->customAuthorizationInterface; + d->customAuthorizationInterface = interface; + + if (d->authorizationPolicy == Custom) { + d->authorizationInterface = interface; + } +} + +AuthorizationManagerPrivate::AuthorizationManagerPrivate(AuthorizationManager *manager) + : q(manager), + authorizationPolicy(AuthorizationManager::DenyAll), + authorizationInterface(new DenyAllAuthorization()), + customAuthorizationInterface(0), + identitiesConfig(KSharedConfig::openConfig("plasma-identityrc")->group("Identitites")), + rulesConfig(KSharedConfig::openConfig("plasma-rulesrc")->group("Rules")), + locked(false) +{ + wallet = KWallet::Wallet::openWallet("Plasma", 0, KWallet::Wallet::Asynchronous); + q->connect(wallet, SIGNAL(walletOpened(bool)), q, SLOT(slotWalletOpened())); + + //Let's set up plasma for remote service support. Since most of the set up involves crypto, + //AuthorizationManager seems the sensible place. + //First, let's start the JOLIE server: + server = new Jolie::Server(4000); + + /** + //Actually: storing identities isn't really necesarry. TODO: remove this and see if stuff + //breaks. + foreach (const QString &groupName, identitiesConfig.groupList()) { + QByteArray identityByteArray = + identitiesConfig.group(groupName).readEntry("Credentials", QByteArray()); + QDataStream stream(&identityByteArray, QIODevice::ReadOnly); + Credentials storedCredentials; + stream >> storedCredentials; + //Credentials storedCredentials = identityVariant.value(); + if (storedCredentials.isNull()) { + kDebug() << "stored identity is null"; + } else { + identities[storedCredentials.id()] = storedCredentials; + } + } + */ + + QTimer::singleShot(0, q, SLOT(loadRules())); +}; + +AuthorizationManagerPrivate::~AuthorizationManagerPrivate() +{ + int i = 0; + foreach (AuthorizationRule *rule, rules) { + kDebug() << "adding rule " << i; + rulesConfig.group(QString::number(i)).writeEntry("CredentialsID", rule->credentials().id()); + rulesConfig.group(QString::number(i)).writeEntry("serviceName", rule->serviceName()); + rulesConfig.group(QString::number(i)).writeEntry("Policy", (uint)rule->policy()); + rulesConfig.group(QString::number(i)).writeEntry("Targets", (uint)rule->targets()); + rulesConfig.group(QString::number(i)).writeEntry("Persistence", (uint)rule->persistence()); + i++; + } + rulesConfig.sync(); + + delete authorizationInterface; + delete customAuthorizationInterface; + delete server; + delete wallet; +} + +void AuthorizationManagerPrivate::slotWalletOpened() +{ + QByteArray identity; + + if (!wallet->readEntry("Credentials", identity)) { + kDebug() << "Existing identity found"; + QDataStream stream(&identity, QIODevice::ReadOnly); + stream >> myCredentials; + } + + if (!myCredentials.isValid()) { + kDebug() << "Creating a new identity"; + myCredentials = Credentials::createCredentials(QHostInfo::localHostName()); + QDataStream stream(&identity, QIODevice::WriteOnly); + stream << myCredentials; + wallet->writeEntry("Credentials", identity); + } + + emit q->readyForRemoteAccess(); +} + +void AuthorizationManagerPrivate::loadRules() +{ + //TODO: at some point we're probably going to use kauth for this stuff, by which time this will + //become kind of obsolete. + foreach (const QString &groupName, rulesConfig.groupList()) { + QString identityID = rulesConfig.group(groupName).readEntry("CredentialsID", ""); + QString serviceName = rulesConfig.group(groupName).readEntry("serviceName", ""); + uint policy = rulesConfig.group(groupName).readEntry("Policy", 0); + uint targets = rulesConfig.group(groupName).readEntry("Targets", 0); + uint persistence = rulesConfig.group(groupName).readEntry("Persistence", 0); + //Credentials storedCredentials = identities[identityID]; + if (serviceName.isEmpty()) { + kDebug() << "Invalid rule"; + } else { + AuthorizationRule *rule = new AuthorizationRule(serviceName, identityID); + rule->setPolicy(static_cast(policy)); + rule->setTargets(static_cast(targets)); + rule->setPersistence(static_cast(persistence)); + rules.append(rule); + } + } +} + +AuthorizationRule *AuthorizationManagerPrivate::matchingRule(const QString &serviceName, + const Credentials &identity) const +{ + AuthorizationRule *matchingRule = 0; + foreach (AuthorizationRule *rule, rules) { + if (rule->d->matches(serviceName, identity.id())) { + //a message can have multiple matching rules, consider priorities: the more specific the + //rule is, the higher it's priority + if (!matchingRule) { + matchingRule = rule; + } else { + if (!matchingRule->targets().testFlag(AuthorizationRule::AllServices) && + !matchingRule->targets().testFlag(AuthorizationRule::AllUsers)) { + matchingRule = rule; + } + } + } + } + + if (!matchingRule) { + kDebug() << "no matching rule"; + } else { + kDebug() << "matching rule found: " << matchingRule->description(); + } + return matchingRule; +} + +Credentials AuthorizationManagerPrivate::getCredentials(const QString &id) +{ + if (identities.contains(id)) { + return identities[id]; + } else { + return Credentials(); + } +} + +void AuthorizationManagerPrivate::addCredentials(const Credentials &identity) +{ + if (identities.contains(identity.id())) { + return; + } else if (identity.isValid()) { + kDebug() << "Adding a new identity for " << identity.id(); + identities[identity.id()] = identity; + /** + QByteArray identityByteArray; + QDataStream stream(&identityByteArray, QIODevice::WriteOnly); + stream << identity; + + identitiesConfig.group(identity.id()).writeEntry("Credentials", identityByteArray); + identitiesConfig.sync(); + */ + } +} + +} // Plasma namespace + +#include "authorizationmanager.moc" diff --git a/authorizationmanager.h b/authorizationmanager.h new file mode 100644 index 000000000..be4454853 --- /dev/null +++ b/authorizationmanager.h @@ -0,0 +1,116 @@ +/* + * Copyright 2009 by Rob Scheepmaker + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef PLASMA_AUTHORIZATIONMANAGER_H +#define PLASMA_AUTHORIZATIONMANAGER_H + +#include "plasma_export.h" + +#include + +class QString; +class KUrl; + +namespace Plasma +{ + +class AuthorizationInterface; +class AuthorizationManagerPrivate; +class ServiceAccessJob; +class ServiceJob; + +/** + * @class AuthorizationManager plasma/authorizationmanager.h + * + * @short Allows authorization of access to plasma services. + * + * This is the class where every message to or from another machine passes through. + * It's responsibilities are: + * - creating/keeping a public/private key pair for message signing. + * - signing and verifying signatures. + * - testing whether or not the sender is allowed to access the requested resource by testing the + * request to a set of rules. + * - allowing the shell the shell to respond to a remote request that doesn't match any of the + * rules that are in effect. + * Besides internal use in libplasma, the only moment you'll need to access this class is when you + * implement a plasma shell. + * + * @since 4.4? + */ +class PLASMA_EXPORT AuthorizationManager : public QObject +{ + Q_OBJECT + public: + enum AuthorizationPolicy { + DenyAll= 0, /** < Don't allow any incoming connections */ + TrustedOnly= 1, /**< Standard PIN pairing for untrusted connections */ + PinPairing= 2, /** < Only allow connections from trusted machines */ + Custom= 256 /** < Specify a custom AuthorizationInterface */ + }; + + /** + * Singleton pattern accessor. + */ + static AuthorizationManager *self(); + + /** + * Set a policy used for authorizing incoming connections. You can either use one of the + * included policies, Default is to deny all incoming connections. + */ + void setAuthorizationPolicy(AuthorizationPolicy policy); + + /** + * Register an implementation of AuthorizationInterface. Use this to make your shell + * handle authorization requests. + */ + void setAuthorizationInterface(AuthorizationInterface *interface); + + Q_SIGNALS: + /** + * fires when the AuthorizationManager is ready for accesssing remote plasmoids, meaning the + * private key has been unlocked by the user. + */ + void readyForRemoteAccess(); + + private: + AuthorizationManager(); + ~AuthorizationManager(); + + AuthorizationManagerPrivate *const d; + + Q_PRIVATE_SLOT(d, void loadRules()) + Q_PRIVATE_SLOT(d, void slotWalletOpened()) + + friend class AuthorizationManagerPrivate; + friend class AuthorizationManagerSingleton; + friend class AuthorizationRule; + friend class Applet; + friend class DataEngine; + friend class GetSource; + friend class Credentials; + friend class PackagePrivate; + friend class PlasmoidServiceJob; + friend class RemoteService; + friend class RemoteServiceJob; + friend class ServiceProvider; +}; +} // Plasma namespace + +#endif + diff --git a/authorizationrule.cpp b/authorizationrule.cpp new file mode 100644 index 000000000..0ac0d7e72 --- /dev/null +++ b/authorizationrule.cpp @@ -0,0 +1,150 @@ +/* + * Copyright 2009 by Rob Scheepmaker + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "authorizationrule.h" +#include "authorizationmanager.h" +#include "private/authorizationmanager_p.h" +#include "private/authorizationrule_p.h" + +#include + +#include +#include + +#include +#include "credentials.h" + +namespace Plasma +{ + +AuthorizationRulePrivate::AuthorizationRulePrivate(const QString &serviceName, const QString &credentialID) + : serviceName(serviceName), + credentialID(credentialID), + policy(AuthorizationRule::Deny), + targets(AuthorizationRule::Default), + persistence(AuthorizationRule::Transient) +{ +} + +AuthorizationRulePrivate::~AuthorizationRulePrivate() {} + +bool AuthorizationRulePrivate::matches(const QString &name, const QString &id) const +{ + if (serviceName == name && (credentialID == id)) { + return true; + } + + if (targets.testFlag(AuthorizationRule::AllUsers) && (serviceName == name)) { + return true; + } + + if (targets.testFlag(AuthorizationRule::AllServices) && (credentialID == id)) { + return true; + } + + return false; +} + +AuthorizationRule::AuthorizationRule(const QString &serviceName, const QString &credentialID) + : QObject(AuthorizationManager::self()), + d(new AuthorizationRulePrivate(serviceName, credentialID)) +{ +} + +AuthorizationRule::~AuthorizationRule() +{ + delete d; +} + +QString AuthorizationRule::description() const +{ + //i18n megafest :p + if (d->targets.testFlag(AllUsers) && d->policy == Allow) { + return i18n("Allow everybody access to %1.", d->serviceName); + } else if (d->targets.testFlag(AllUsers) && d->policy == Deny) { + return i18n("Deny everybody access to %1", d->serviceName); + } else if (d->targets.testFlag(AllServices) && d->policy == Allow) { + return i18n("Allow %1 access to all services.", credentials().name()); + } else if (d->targets.testFlag(AllServices) && d->policy == Deny) { + return i18n("Deny %1 access to all services.", credentials().name()); + } else if (d->policy == Allow) { + return i18n("Allow access to %1, by %2.", d->serviceName, credentials().name()); + } else if (d->policy == Deny) { + return i18n("Deny access to %1, by %2.", d->serviceName, credentials().name()); + } else { + return i18n("Allow access to %1, by %2?", d->serviceName, credentials().name()); + } +} + + +void AuthorizationRule::setPolicy(Policy policy) +{ + d->policy = policy; + emit changed(this); +} + +AuthorizationRule::Policy AuthorizationRule::policy() +{ + return d->policy; +} + +void AuthorizationRule::setTargets(Targets targets) +{ + d->targets = targets; + emit changed(this); +} + +AuthorizationRule::Targets AuthorizationRule::targets() +{ + return d->targets; +} + +void AuthorizationRule::setPersistence(Persistence persistence) +{ + d->persistence = persistence; + emit changed(this); +} + +AuthorizationRule::Persistence AuthorizationRule::persistence() +{ + return d->persistence; +} + +void AuthorizationRule::setPin(const QString &pin) +{ + d->pin = pin; +} + +QString AuthorizationRule::pin() const +{ + return d->pin; +} + +Credentials AuthorizationRule::credentials() const +{ + return AuthorizationManager::self()->d->getCredentials(d->credentialID); +} + +QString AuthorizationRule::serviceName() const +{ + return d->serviceName; +} + +} // Plasma namespace + diff --git a/authorizationrule.h b/authorizationrule.h new file mode 100644 index 000000000..26280da56 --- /dev/null +++ b/authorizationrule.h @@ -0,0 +1,169 @@ +/* + * Copyright 2009 by Rob Scheepmaker + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef PLASMA_AUTHORIZATIONRULE_H +#define PLASMA_AUTHORIZATIONRULE_H + +#include "plasma_export.h" + +#include + +class QString; +class KUrl; + +namespace QCA +{ + class PublicKey; +} + +namespace Plasma +{ + +class AuthorizationManager; +class AuthorizationRulePrivate; +class Credentials; + +/** + * @class AuthorizationRule plasma/authorizationrule.h + * + * @short Defines a rule indicating whether or not a certain service can be accessed by a certain + * machine. + * + * Rules allow you to have control over which computers are allowed to access which + * services. Everytime a message get's in, AuthorizationManager validates it's sender, and then + * checks it's list of rules for rules matching the sender and/or the service. If no rules match, + * or all matching rules have the value Unspecified, AuthorizationManager will create a new rule + * for this message, and invoke authorize on your shells implementation of AuthorizationInterface. + * Here, you can change that rule to either allow or deny that request. + * This class can be used to specify different types of rules: + * - Rules matching only a user + * - Rules matching only a service + * - Rules matching both a service, and a user. + * A more specific rule always takes precedence over a more global rule: so if for example you have + * a rule for "myAwesomeService" specifying Deny, and a rule for "myAwesomeService" in combination + * with "130.42.120.146" as caller specifying Allow, only 130.42.120.146 can access + * myAwesomeService. + * By setting the PinRequired flag in setRules in an AuthorizationInterface implementation, you + * trigger Pin pairing (user will be asked to enter the same password on both machines). + * + * @since 4.4? + */ +class PLASMA_EXPORT AuthorizationRule : public QObject +{ + Q_OBJECT + public: + ~AuthorizationRule(); + /** + * Defines this rule's behavior. + */ + enum Policy { + Deny = 0, /**< access for messages matching this rule is denied. */ + Allow = 1, /**< access for messages matching this rule is allowed. */ + PinRequired = 2, /**< specify that the user will need to enter a pin at both sides */ + }; + + enum Persistence { + Transient = 0, + Persistent = 1 + }; + + enum Target { + Default = 0, + AllUsers = 1, /**< specify that this rule is valid for all users */ + AllServices = 2, /**< specify that this rule is valid for all services */ + }; + Q_DECLARE_FLAGS(Targets, Target) + + /** + * @returns a friendly and i18n'd description of the current rule, useful for creating a + * GUI to allow editing rules, or asking permission for an access attempt. + */ + QString description() const; + + /** + * @param rules the flags describing this rule. + */ + void setPolicy(Policy policy); + + /** + * @returns the flags describing this rule. + */ + Policy policy(); + + /** + * @param rules the flags describing this rule. + */ + void setPersistence(Persistence persistence); + + /** + * @returns the flags describing this rule. + */ + Persistence persistence(); + + /** + * @param rules the flags describing this rule. + */ + void setTargets(Targets targets); + + /** + * @returns the flags describing this rule. + */ + Targets targets(); + + /** + * @param pin set pin for pin pairing. You'll need to call this bevore setting the rule. + */ + void setPin(const QString &pin); + + /** + * @returns the pin for pin pairing. + */ + QString pin() const; + + /** + * @returns the identity of the caller. + */ + Credentials credentials() const; + + /** + * @returns the name of the service this rule applies to. + */ + QString serviceName() const; + + Q_SIGNALS: + void changed(Plasma::AuthorizationRule *); + + private: + AuthorizationRule(); + AuthorizationRule(const QString &serviceName, const QString &identityID); + + AuthorizationRulePrivate * const d; + + friend class AuthorizationManager; + friend class AuthorizationManagerPrivate; + friend class ServiceProvider; + friend class GetSource; + friend class PlasmoidServiceJob; +}; +} // Plasma namespace + +Q_DECLARE_OPERATORS_FOR_FLAGS(Plasma::AuthorizationRule::Targets) + +#endif + diff --git a/clientpinrequest.cpp b/clientpinrequest.cpp new file mode 100644 index 000000000..fbe6780b3 --- /dev/null +++ b/clientpinrequest.cpp @@ -0,0 +1,76 @@ +/* + * Copyright 2009 by Rob Scheepmaker + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "clientpinrequest.h" + +#include +#include + +#include +#include + +namespace Plasma +{ + +class ClientPinRequestPrivate { +public: + ClientPinRequestPrivate(RemoteService *service) + : service(service) + { + } + + ~ClientPinRequestPrivate() {} + + RemoteService *service; + QString pin; +}; + +ClientPinRequest::ClientPinRequest(RemoteService *service) + : QObject(service), + d(new ClientPinRequestPrivate(service)) +{ +} + +ClientPinRequest::~ClientPinRequest() +{ + delete d; +} + +QString ClientPinRequest::description() const +{ + return i18n("You've requested access to the %1 hosted at %2.", d->service->name(), + d->service->location()); +} + +void ClientPinRequest::setPin(const QString &pin) +{ + kDebug() << "pin = " << pin; + d->pin = pin; + emit changed(this); +} + +QString ClientPinRequest::pin() const +{ + return d->pin; +} + +} // Plasma namespace + +#include "clientpinrequest.moc" + diff --git a/clientpinrequest.h b/clientpinrequest.h new file mode 100644 index 000000000..e4186cece --- /dev/null +++ b/clientpinrequest.h @@ -0,0 +1,79 @@ +/* + * Copyright 2009 by Rob Scheepmaker + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef PLASMA_CLIENTPINREQUEST_H +#define PLASMA_CLIENTPINREQUEST_H + +#include "plasma_export.h" + +#include + +class QString; +class KUrl; + +namespace Plasma +{ + +class ClientPinRequestPrivate; +class RemoteService; +class Service; + +/** + * @class ClientPinRequest plasma/clientpinrequest.h + * + * describes an outgoing connection. + * + * @since 4.4? + */ +class PLASMA_EXPORT ClientPinRequest : public QObject +{ + Q_OBJECT + public: + /** + * @returns nice i18n'ed description of this outgoing connection. + */ + QString description() const; + + /** + * @param pin set a pin for pin pairing. + */ + void setPin(const QString &pin); + + /** + * @returns the pin for pin pairing. + */ + QString pin() const; + + Q_SIGNALS: + void changed(Plasma::ClientPinRequest *); + + private: + ClientPinRequest(); + ClientPinRequest(RemoteService *service); + ~ClientPinRequest(); + + ClientPinRequestPrivate * const d; + + friend class RemoteService; + +}; +} // Plasma namespace + +#endif + diff --git a/credentials.cpp b/credentials.cpp new file mode 100644 index 000000000..56380b187 --- /dev/null +++ b/credentials.cpp @@ -0,0 +1,220 @@ +/* + Copyright (C) 2009 Rob Scheepmaker + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "credentials.h" + +#include +#include + +#include +#include "authorizationmanager.h" +#include + +namespace Plasma { + +class CredentialsPrivate { +public: + CredentialsPrivate() + { + } + + CredentialsPrivate(const QString &id, const QString &name, + const QString &pemKey, bool isPrivateKey) + : id(id), + name(name) + { + if (isPrivateKey) { + privateKey = QCA::PrivateKey::fromPEM(pemKey); + publicKey = privateKey.toPublicKey(); + } else { + publicKey = QCA::PublicKey::fromPEM(pemKey); + } + } + + ~CredentialsPrivate() + { + } + + QString id; + QString name; + QCA::PublicKey publicKey; + QCA::PrivateKey privateKey; +}; + +Credentials::Credentials(const QString &id, const QString &name, + const QString &key, bool isPrivateKey) + : d(new CredentialsPrivate(id, name, key, isPrivateKey)) +{ +} + +Credentials::Credentials() + : d(new CredentialsPrivate()) +{ +} + +Credentials::Credentials(const Credentials &other) + : d(new CredentialsPrivate()) +{ + *d = *other.d; +} + +Credentials::~Credentials() +{ + delete d; +} + +Credentials &Credentials::operator=(const Credentials &other) +{ + *d = *other.d; + return *this; +} + +Credentials Credentials::createCredentials(const QString &name) +{ + QCA::KeyGenerator generator; + QCA::PrivateKey key = generator.createRSA(2048); + QString pemKey(key.toPublicKey().toPEM()); + //TODO: is using a md5 hash for the id a good idea? + QString id = QCA::Hash("sha1").hashToString(pemKey.toAscii()); + return Credentials(id, name, key.toPEM(), true); +} + +TrustLevel Credentials::trustLevel() const +{ + /** + QString pemFile = KStandardDirs::locate("trustedkeys", id()); + + if (!pemFile.isEmpty()) { + QCA::PublicKey pubKey = QCA::PublicKey::fromPEMFile(pemFile); + if (pubKey == d->publicKey) { + return true; + } + } + */ + //Trust noone ;) + return ValidCredentials; +} + +bool Credentials::isValid() const +{ + if (d->publicKey.isNull()) { + return false; + } else { + QString id = QCA::Hash("sha1").hashToString(d->publicKey.toPEM().toAscii()); + return (id == d->id); + } +} + +QString Credentials::name() const +{ + return d->name; +} + +QString Credentials::id() const +{ + return d->id; +} + +bool Credentials::isValidSignature(const QByteArray &signature, const QByteArray &payload) +{ + if (d->publicKey.canVerify()) { + if (!isValid()) { + kDebug() << "Key is null?"; + } + QCA::PublicKey publicKey = QCA::PublicKey::fromPEM(d->publicKey.toPEM()); + publicKey.startVerify( QCA::EMSA3_MD5 ); + publicKey.update(payload); + return ( publicKey.validSignature( signature ) ); + } else { + kDebug() << "Can't verify?"; + return false; + } +} + +bool Credentials::canSign() const +{ + return d->privateKey.canSign(); +} + +QByteArray Credentials::signMessage(const QByteArray &message) +{ + if(!QCA::isSupported("pkey") || + !QCA::PKey::supportedIOTypes().contains(QCA::PKey::RSA)) { + kDebug() << "RSA not supported"; + return QByteArray(); + } else if (canSign()) { + //QCA::PrivateKey privateKey = QCA::PrivateKey::fromPEM(d->privateKey.toPEM()); + d->privateKey.startSign( QCA::EMSA3_MD5 ); + d->privateKey.update( message ); + QByteArray signature = d->privateKey.signature(); + return signature; + } else { + kDebug() << "can't sign?"; + return QByteArray(); + } +} + +Credentials Credentials::toPublicCredentials() const +{ + kDebug(); + Credentials result(*this); + result.d->privateKey = QCA::PrivateKey(); + return result; +} + +QDataStream &operator<<(QDataStream &out, const Credentials &myObj) +{ + QString privateKeyPem; + QString publicKeyPem; + + if (!myObj.d->privateKey.isNull()) { + privateKeyPem = myObj.d->privateKey.toPEM(); + } + if (!myObj.d->publicKey.isNull()) { + publicKeyPem = myObj.d->publicKey.toPEM(); + } + + out << 1 << myObj.d->id << myObj.d->name << privateKeyPem << publicKeyPem; + + return out; +} + +QDataStream &operator>>(QDataStream &in, Credentials &myObj) +{ + QString privateKeyString; + QString publicKeyString; + uint version; + + in >> version >> myObj.d->id >> myObj.d->name >> privateKeyString >> publicKeyString; + QCA::ConvertResult conversionResult; + + if (!privateKeyString.isEmpty()) { + myObj.d->privateKey = QCA::PrivateKey::fromPEM(privateKeyString, + QByteArray(), &conversionResult); + } + if (!publicKeyString.isEmpty()) { + myObj.d->publicKey = QCA::PublicKey::fromPEM(publicKeyString, &conversionResult); + } + + if (conversionResult != QCA::ConvertGood) { + kDebug() << "Unsuccessfull conversion of key?"; + } + + return in; +} + +} diff --git a/credentials.h b/credentials.h new file mode 100644 index 000000000..9589e30d9 --- /dev/null +++ b/credentials.h @@ -0,0 +1,135 @@ +/* + Copyright (C) 2009 Rob Scheepmaker + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef IDENTITY_H +#define IDENTITY_H + +#include + +#include +#include +#include + +#include + +namespace Plasma { + +class CredentialsPrivate; + +/** + * @class Credentials plasma/credentials.h + * + * This class encapsules someone's identity. + * It contains a unique id that identifies the machine an incoming connection is coming from, it's + * name (which is not necesarily unique and/or trusted), a public key used to validate messages + * coming from the machine with this identity, and in the future the possibility to determine + * whether or not this identity can be trusted based on mechanisms different then pin pairing, e.g. + * a signature of the key that can be verified by a gpg trusted key. + */ +class Credentials +{ +public: + /** + * Default constructor. + */ + Credentials(); + + /** + * Copy constructor. + */ + Credentials(const Credentials &other); + + ~Credentials(); + + Credentials &operator=(const Credentials &other); + + /** + * Create a new identity with a new set of random public/private keys. + */ + static Credentials createCredentials(const QString &name); + + /** + * @return whether or not this identity can be trusted based on e.g. having the key signed with + * a trusted GPG key (not yet implemented) or having the key in a designated folder on disk + * (about to be impl.). If this function returns false, your shell should always instatiate + * pin pairing before allowing a connection from an untrusted source + * (AuthorizationRule::PinRequired flag should be set on the rule with setRules). + */ + TrustLevel trustLevel() const; + + /** + * @return whether or not this is a null identity or an invalid one (hash of key doesn't match + * id). Maybe isValid() is a better name? + */ + bool isValid() const; + + /** + * @return the name of this identity. There's however no guarantee that if the name returns e.g. + * "Santa Claus", this message is actually from Mr. Claus, except if isTrusted is true. + */ + QString name() const; + + /** + * @return an id to identify this identity. I use a Hash of the public key as ID. This way we + * don't have to send the complete public key with every message. + */ + QString id() const; + + /** + * @return wheter or not @p signature is correct for @p message. + */ + bool isValidSignature(const QByteArray &signature, const QByteArray &message); + + /** + * @return whether or not this identity can be used for signing a message (whether or not it + * includes a public key) + */ + bool canSign() const; + + /** + * @return the signature for the message. + */ + QByteArray signMessage(const QByteArray &message); + + /** + * @return a Credentials stripped from any private key, so you can be sure it is save to send to + * somebody. + */ + Credentials toPublicCredentials() const; + + friend QDataStream &operator<<(QDataStream &, const Credentials &); + friend QDataStream &operator>>(QDataStream &, Credentials &); + +private: + Credentials(const QString &id, const QString &name, const QString &key, + bool privateKey = false); + + CredentialsPrivate *const d; + + friend class AuthorizationManagerPrivate; + friend class CredentialsPrivate; +}; + +/** + * Streaming operators for sending/storing identities. + */ +QDataStream &operator<<(QDataStream &, const Credentials &); +QDataStream &operator>>(QDataStream &, Credentials &); + +} + +#endif // IDENTITY_H diff --git a/dataengine.cpp b/dataengine.cpp index 29102d546..7fef79076 100644 --- a/dataengine.cpp +++ b/dataengine.cpp @@ -31,11 +31,14 @@ #include #include +#include "authorizationmanager.h" #include "datacontainer.h" #include "package.h" #include "service.h" #include "scripting/dataenginescript.h" +#include "private/authorizationmanager_p.h" +#include "private/dataengineservice.h" #include "private/service_p.h" namespace Plasma @@ -358,16 +361,17 @@ DataEngine::SourceDict DataEngine::containerDict() const void DataEngine::timerEvent(QTimerEvent *event) { + kDebug(); if (event->timerId() == d->updateTimerId) { // if the freq update is less than 0, don't bother if (d->minPollingInterval < 0) { - //kDebug() << "uh oh.. no polling allowed!"; + kDebug() << "uh oh.. no polling allowed!"; return; } // minPollingInterval if (d->updateTimestamp.elapsed() < d->minPollingInterval) { - //kDebug() << "hey now.. slow down!"; + kDebug() << "hey now.. slow down!"; return; } @@ -426,6 +430,36 @@ QString DataEngine::pluginName() const return d->dataEngineDescription.pluginName(); } +void DataEnginePrivate::publish(AnnouncementMethods methods, const QString &name) +{ + if (!publishedService) { + publishedService = new DataEngineService(q); + } + + //QString resourceName = + //i18nc("%1 is the name of a dataengine, %2 the name of the machine that engine is published +//on", + //"%1 dataengine on %2", name(), AuthorizationManager::self()->d->myCredentials.name()); + kDebug() << "name: " << name; + publishedService->d->publish(methods, name); +} + +void DataEnginePrivate::unpublish(const QString &name) +{ + if (publishedService) { + publishedService->d->unpublish(); + } +} + +bool DataEnginePrivate::isPublished() const +{ + if (publishedService) { + return publishedService->d->isPublished(); + } else { + return false; + } +} + const Package *DataEngine::package() const { return d->package; @@ -462,7 +496,8 @@ DataEnginePrivate::DataEnginePrivate(DataEngine *e, KService::Ptr service) limit(0), valid(true), script(0), - package(0) + package(0), + publishedService(0) { updateTimestamp.start(); diff --git a/dataengine.h b/dataengine.h index 1a60c2aba..1e0d8f551 100644 --- a/dataengine.h +++ b/dataengine.h @@ -29,6 +29,7 @@ #include #include +#include namespace Plasma { @@ -160,7 +161,8 @@ class PLASMA_EXPORT DataEngine : public QObject * @param intervalAlignment the number of ms to align the interval to **/ Q_INVOKABLE void connectAllSources(QObject *visualization, uint pollingInterval = 0, - Plasma::IntervalAlignment intervalAlignment = NoAlignment) const; + Plasma::IntervalAlignment intervalAlignment = +NoAlignment) const; /** * Disconnects a source to an object that was receiving data updates. @@ -231,7 +233,6 @@ class PLASMA_EXPORT DataEngine : public QObject */ QString pluginName() const; - Q_SIGNALS: /** * Emitted when a new data source is created @@ -459,6 +460,7 @@ class PLASMA_EXPORT DataEngine : public QObject friend class DataEnginePrivate; friend class DataEngineScript; friend class DataEngineManager; + friend class PlasmoidServiceJob; friend class NullEngine; Q_PRIVATE_SLOT(d, void internalUpdateSource(DataContainer *source)) diff --git a/dataengineservice.operations b/dataengineservice.operations new file mode 100644 index 000000000..48e783f6c --- /dev/null +++ b/dataengineservice.operations @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + diff --git a/package.cpp b/package.cpp index 56f5405c3..7b80f15d1 100644 --- a/package.cpp +++ b/package.cpp @@ -40,29 +40,16 @@ #include #include +#include "authorizationmanager.h" #include "packagemetadata.h" +#include "private/authorizationmanager_p.h" +#include "private/package_p.h" +#include "private/plasmoidservice.h" +#include "private/service_p.h" namespace Plasma { -class PackagePrivate -{ -public: - PackagePrivate(const PackageStructure::Ptr st, const QString &p) - : structure(st) - { - structure->setPath(p); - valid = !structure->path().isEmpty(); - } - - ~PackagePrivate() - { - } - - PackageStructure::Ptr structure; - bool valid; -}; - Package::Package(const QString &packageRoot, const QString &package, PackageStructure::Ptr structure) : d(new PackagePrivate(structure, packageRoot + '/' + package)) @@ -470,4 +457,45 @@ bool Package::createPackage(const PackageMetadata &metadata, return true; } +PackagePrivate::PackagePrivate(const PackageStructure::Ptr st, const QString &p) + : structure(st), + service(0) +{ + structure->setPath(p); + valid = !structure->path().isEmpty(); +} + +PackagePrivate::~PackagePrivate() +{ +} + +void PackagePrivate::publish(AnnouncementMethods methods) +{ + if (service) { + service = new PlasmoidService(structure->path()); + } + + QString resourceName = + i18nc("%1 is the name of a plasmoid, %2 the name of the machine that plasmoid is published on", + "%1 on %2", structure->metadata().name(), AuthorizationManager::self()->d->myCredentials.name()); + kDebug() << "publishing package under name " << resourceName; + service->d->publish(methods, resourceName, structure->metadata()); +} + +void PackagePrivate::unpublish() +{ + if (service) { + service->d->unpublish(); + } +} + +bool PackagePrivate::isPublished() const +{ + if (service) { + return service->d->isPublished(); + } else { + return false; + } +} + } // Namespace diff --git a/package.h b/package.h index 7eb12632a..f85aa8531 100644 --- a/package.h +++ b/package.h @@ -23,8 +23,9 @@ #include -#include +#include #include +#include namespace Plasma { @@ -108,6 +109,22 @@ class PLASMA_EXPORT Package */ void setPath(const QString &path); + /** + * Publish this package on the network. + * @param methods the ways to announce this package on the network. + */ + void publish(AnnouncementMethods methods, const QString &name); + + /** + * Remove this package from the network. + */ + void unpublish(const QString &name = QString()); + + /** + * @returns whether or not this service is currently published on the network. + */ + bool isPublished() const; + /** * @return the path to the root of this particular package */ @@ -192,6 +209,9 @@ class PLASMA_EXPORT Package private: Q_DISABLE_COPY(Package) PackagePrivate * const d; + + friend class Applet; + friend class AppletPrivate; }; } // Namespace diff --git a/packagemetadata.cpp b/packagemetadata.cpp index 63eff4aa2..967a83b5c 100644 --- a/packagemetadata.cpp +++ b/packagemetadata.cpp @@ -50,6 +50,7 @@ class PackageMetadataPrivate QString type; QString serviceType; QString api; + KUrl location; }; PackageMetadata::PackageMetadata(const PackageMetadata &other) @@ -57,6 +58,12 @@ PackageMetadata::PackageMetadata(const PackageMetadata &other) { } +PackageMetadata &PackageMetadata::operator=(const PackageMetadata &other) +{ + *d = *other.d; + return *this; +} + PackageMetadata::PackageMetadata(const QString &path) : d(new PackageMetadataPrivate) { @@ -96,6 +103,7 @@ void PackageMetadata::write(const QString &filename) const config.writeEntry("X-Plasma-API", d->api); config.writeEntry("X-KDE-ParentApp", d->app); config.writeEntry("Type", d->type); + config.writeEntry("X-Plasma-RemoteLocation", d->location); } void PackageMetadata::read(const QString &filename) @@ -121,6 +129,7 @@ void PackageMetadata::read(const QString &filename) d->api = config.readEntry("X-Plasma-API", d->api); d->app = config.readEntry("X-KDE-ParentApp", d->app); d->type = config.readEntry("Type", d->type); + d->location = config.readEntry("X-Plasma-RemoteLocation", d->location); } QString PackageMetadata::name() const @@ -188,6 +197,11 @@ QString PackageMetadata::requiredVersion() const return d->requiredVersion; } +KUrl PackageMetadata::remoteLocation() const +{ + return d->location; +} + QString PackageMetadata::type() const { return d->type; @@ -268,6 +282,11 @@ void PackageMetadata::setRequiredVersion(const QString &requiredVersion) d->requiredVersion = requiredVersion; } +void PackageMetadata::setRemoteLocation(const KUrl &location) +{ + d->location = location; +} + void PackageMetadata::setType(const QString &type) { d->type = type; diff --git a/packagemetadata.h b/packagemetadata.h index c44332f5d..43cdd3623 100644 --- a/packagemetadata.h +++ b/packagemetadata.h @@ -24,6 +24,8 @@ #include +#include + namespace Plasma { @@ -51,6 +53,8 @@ public: ~PackageMetadata(); + PackageMetadata &operator=(const PackageMetadata &other); + bool isValid() const; /** @@ -87,6 +91,7 @@ public: QString requiredVersion() const; QString pluginName() const; QString implementationApi() const; + KUrl remoteLocation() const; QString type() const; @@ -161,6 +166,8 @@ public: */ void setRequiredVersion(const QString &); + void setRemoteLocation(const KUrl &); + /** * Set the type of the package. If not defined this * defaults to "Service" in the desktop file. diff --git a/plasma.h b/plasma.h index 53fbb92d2..25e007760 100644 --- a/plasma.h +++ b/plasma.h @@ -264,6 +264,21 @@ enum ItemStatus { }; Q_ENUMS(ItemStatus) +enum AnnouncementMethod { + NoAnnouncement = 0, + ZeroconfAnnouncement = 1 +}; +Q_DECLARE_FLAGS(AnnouncementMethods, AnnouncementMethod) + +enum TrustLevel { + InvalidCredentials = 0, + UnknownCredentials = 1, + ValidCredentials = 2, + TrustedCredentials = 3, + UltimateCredentials = 4 +}; +Q_ENUMS(TrustLevel) + /** * @return the scaling factor (0..1) for a ZoomLevel **/ diff --git a/plasma.kdev4 b/plasma.kdev4 new file mode 100644 index 000000000..cce194dee --- /dev/null +++ b/plasma.kdev4 @@ -0,0 +1,3 @@ +[Project] +Manager=KDevCMakeManager +Name=plasma diff --git a/plasma.notifyrc b/plasma.notifyrc new file mode 100644 index 000000000..7f1ab57db --- /dev/null +++ b/plasma.notifyrc @@ -0,0 +1,10 @@ +[Global] +IconName=application-plasma +Comment=KDE desktop shell +Name=Plasma + +[Event/authorize] +Name=Authorize remote access +Comment=A remote computer tries to access a service +Action=Popup +Persistent=True diff --git a/plasmoidservice.operations b/plasmoidservice.operations new file mode 100644 index 000000000..e3a3ea79c --- /dev/null +++ b/plasmoidservice.operations @@ -0,0 +1,12 @@ + + + + + + + + + + + diff --git a/private/accessmanager_p.h b/private/accessmanager_p.h new file mode 100644 index 000000000..402c3ecf7 --- /dev/null +++ b/private/accessmanager_p.h @@ -0,0 +1,53 @@ +/* + * Copyright 2009 by Rob Scheepmaker + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef ACCESSMANAGER_P_H +#define ACCESSMANAGER_P_H + +#include "../accessmanager.h" +#include + +class KJob; + +namespace DNSSD +{ + class ServiceBrowser; +} + +namespace Plasma +{ + +class AccessManagerPrivate +{ + public: + AccessManagerPrivate(AccessManager *manager); + ~AccessManagerPrivate(); + void slotJobFinished(KJob *job); + void slotAddService(DNSSD::RemoteService::Ptr service); + void slotRemoveService(DNSSD::RemoteService::Ptr service); + + AccessManager *q; + DNSSD::ServiceBrowser *browser; + QMap services; + QMap zeroconfServices; +}; + +} + +#endif diff --git a/private/applet_p.h b/private/applet_p.h index cd96925fb..587e80442 100644 --- a/private/applet_p.h +++ b/private/applet_p.h @@ -28,6 +28,7 @@ #include "plasma/animator.h" #include "plasma/private/dataengineconsumer_p.h" +#include "plasma/ui_publish.h" class KKeySequenceWidget; @@ -91,6 +92,7 @@ public: void positionMessageOverlay(); void destroyMessageOverlay(); void addGlobalShortcutsPage(KConfigDialog *dialog); + void addPublishPage(KConfigDialog *dialog); void clearShortcutEditorPtr(); void configDialogFinished(); KConfigDialog *generateGenericConfigDialog(); @@ -113,8 +115,10 @@ public: Applet *q; // applet attributes - Applet::BackgroundHints backgroundHints; + Extender *extender; + Service *service; Applet::BackgroundHints preferredBackgroundHints; + Applet::BackgroundHints backgroundHints; Plasma::AspectRatioMode aspectRatioMode; ImmutabilityType immutability; @@ -123,7 +127,6 @@ public: QVariantList args; // bookkeeping - Extender *extender; QSet registeredAsDragHandle; Plasma::FrameSvg *background; KConfigGroup *mainConfig; @@ -147,6 +150,8 @@ public: KKeySequenceWidget *shortcutEditor; //TODO: subclass KConfigDialog and encapsulate this in there ItemStatus itemStatus; + QString remoteLocation; + Ui::publishWidget publishUI; // timerEvent bookkeeping int constraintsTimerId; diff --git a/private/authorizationmanager_p.h b/private/authorizationmanager_p.h new file mode 100644 index 000000000..02aaae41e --- /dev/null +++ b/private/authorizationmanager_p.h @@ -0,0 +1,95 @@ +/* + * Copyright 2009 by Rob Scheepmaker + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef AUTHORIZATIONMANAGER_P_H +#define AUTHORIZATIONMANAGER_P_H + +#include +#include +#include + +#include +#include +#include + +class QByteArray; + +namespace KWallet +{ + class Wallet; +} // namespace KWallet + +namespace Jolie +{ + class Server; +} // namespace Jolie + +namespace Plasma +{ + +class AuthorizationInterface; +class AuthorizationRule; +class Credentials; + +class AuthorizationManagerPrivate +{ + public: + AuthorizationManagerPrivate(AuthorizationManager *manager); + ~AuthorizationManagerPrivate(); + + void loadRules(); + + /** + * @returns the rule matching the parameters with the highest priority. + */ + AuthorizationRule *matchingRule(const QString &serviceName, const Credentials &key) const; + + /** + * @returns the identity with @p id. Or 0 well there's no identity with that ID. + */ + Credentials getCredentials(const QString &id = QString()); + + /** + * @param identity the identity to be added to the identity ring. + */ + void addCredentials(const Credentials &identity); + + void slotWalletOpened(); + + QCA::Initializer initializer; + + AuthorizationManager *q; + Jolie::Server *server; + AuthorizationManager::AuthorizationPolicy + authorizationPolicy; + AuthorizationInterface *authorizationInterface; + AuthorizationInterface *customAuthorizationInterface; + KWallet::Wallet *wallet; + + Credentials myCredentials; + QMap identities; + QList rules; + KConfigGroup identitiesConfig; + KConfigGroup rulesConfig; + bool locked; +}; + +} + +#endif diff --git a/private/authorizationrule_p.h b/private/authorizationrule_p.h new file mode 100644 index 000000000..9c5cacd67 --- /dev/null +++ b/private/authorizationrule_p.h @@ -0,0 +1,21 @@ +#include + +namespace Plasma +{ + +class AuthorizationRulePrivate { +public: + AuthorizationRulePrivate(const QString &serviceName, const QString &credentialID); + ~AuthorizationRulePrivate(); + bool matches(const QString &serviceName, const QString &credentialID) const; + + QString serviceName; + QString credentialID; + bool PINvalidated; + QString pin; + AuthorizationRule::Policy policy; + AuthorizationRule::Targets targets; + AuthorizationRule::Persistence persistence; +}; + +} diff --git a/private/dataengine_p.h b/private/dataengine_p.h index a6b1943f9..c62913b78 100644 --- a/private/dataengine_p.h +++ b/private/dataengine_p.h @@ -30,6 +30,8 @@ class QTime; namespace Plasma { +class Service; + class DataEnginePrivate { public: @@ -60,6 +62,21 @@ class DataEnginePrivate * @return true if the reference count is non-zero **/ bool isUsed() const; + + /** + * @param methods ways to announce this engine on the network. + */ + void publish(AnnouncementMethods methods, const QString &name); + + /** + * remove this engine from the network. + */ + void unpublish(const QString &name = QString()); + + /** + * @return whether or not this engine is published. + */ + bool isPublished() const; DataEngine *q; KPluginInfo dataEngineDescription; @@ -76,6 +93,7 @@ class DataEnginePrivate DataEngineScript *script; QString engineName; Package *package; + Service *publishedService; }; } // Plasma namespace diff --git a/private/dataengineconsumer.cpp b/private/dataengineconsumer.cpp new file mode 100644 index 000000000..5fbcb6cf2 --- /dev/null +++ b/private/dataengineconsumer.cpp @@ -0,0 +1,118 @@ +/* + * Copyright 2005 by Aaron Seigo + * Copyright 2007 by Riccardo Iaconelli + * Copyright 2008 by Ménard Alexis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "dataengineconsumer_p.h" + +#include + +#include + +#include "plasma/dataenginemanager.h" +#include "plasma/private/remotedataengine.h" +#include + +namespace Plasma +{ + +DataEngineConsumer::~DataEngineConsumer() +{ + foreach (const QString &engine, m_loadedEngines) { + DataEngineManager::self()->unloadEngine(engine); + } +} + +DataEngine *DataEngineConsumer::dataEngine(const QString &name) +{ + if (m_loadedEngines.contains(name)) { + return DataEngineManager::self()->engine(name); + } + + DataEngine *engine = DataEngineManager::self()->loadEngine(name); + if (engine->isValid()) { + m_loadedEngines.insert(name); + } + + return engine; +} + +DataEngine *DataEngineConsumer::remoteDataEngine(const KUrl &location, const QString &name) +{ + QPair pair(location.prettyUrl(), name); + kDebug() << "pair = " << pair; + if (m_remoteEngines.contains(pair)) { + kDebug() << "existing remote dataengine at " << location; + return m_remoteEngines[pair]; + } + + kDebug() << "new remote dataengine at " << location; + RemoteDataEngine *engine = new RemoteDataEngine(KUrl()); + m_remoteEngines[pair] = engine; + Service *plasmoidService = Service::access(location); + plasmoidService->setDestination(location.prettyUrl()); + m_engineNameForService[plasmoidService] = name; + kDebug() << "name = " << name; + connect(plasmoidService, SIGNAL(serviceReady(Plasma::Service*)), + this, SLOT(slotServiceReady(Plasma::Service*))); + return engine; +} + +void DataEngineConsumer::slotJobFinished(Plasma::ServiceJob *job) +{ + kDebug() << "engine ready!"; + QString engineName = job->parameters()["EngineName"].toString(); + QString location = job->destination(); + QPair pair(location, engineName); + kDebug() << "pair = " << pair; + if (!m_remoteEngines.contains(pair)) { + kDebug() << "engine doesnt exist yet!"; + } else { + KUrl engineLocation(location); + engineLocation.setFileName(job->result().toString()); + kDebug() << "setting location : " + << engineLocation.prettyUrl(); + m_remoteEngines[pair]->setLocation(engineLocation); + } +} + +void DataEngineConsumer::slotServiceReady(Plasma::Service *plasmoidService) +{ + kDebug() << "service ready!"; + if (!m_engineNameForService.contains(plasmoidService)) { + kDebug() << "no engine name for service!"; + kDebug() << "amount of services in map: " << m_engineNameForService.count(); + } else { + kDebug() << "value = " << m_engineNameForService.value(plasmoidService); + } + + kDebug() << "requesting dataengine!"; + KConfigGroup op = plasmoidService->operationDescription("DataEngine"); + op.writeEntry("EngineName", m_engineNameForService.value(plasmoidService)); + //m_engineNameForService.remove(service); + plasmoidService->startOperationCall(op); + connect(plasmoidService, SIGNAL(finished(Plasma::ServiceJob*)), + this, SLOT(slotJobFinished(Plasma::ServiceJob*))); +} + +} // namespace Plasma + +#include "dataengineconsumer_p.moc" + + diff --git a/private/dataengineconsumer_p.h b/private/dataengineconsumer_p.h index 97b5358a2..e35746cc3 100644 --- a/private/dataengineconsumer_p.h +++ b/private/dataengineconsumer_p.h @@ -27,36 +27,29 @@ #include #include "plasma/dataenginemanager.h" +#include "plasma/private/remotedataengine.h" +#include namespace Plasma { -class DataEngineConsumer +class DataEngineConsumer : public QObject { + Q_OBJECT + public: - ~DataEngineConsumer() - { - foreach (const QString &engine, m_loadedEngines) { - DataEngineManager::self()->unloadEngine(engine); - } - } + ~DataEngineConsumer(); + DataEngine *dataEngine(const QString &name); + DataEngine *remoteDataEngine(const KUrl &location, const QString &name); - DataEngine *dataEngine(const QString &name) - { - if (m_loadedEngines.contains(name)) { - return DataEngineManager::self()->engine(name); - } - - DataEngine *engine = DataEngineManager::self()->loadEngine(name); - if (engine->isValid()) { - m_loadedEngines.insert(name); - } - - return engine; - } +private Q_SLOTS: + void slotJobFinished(Plasma::ServiceJob *job); + void slotServiceReady(Plasma::Service *service); private: QSet m_loadedEngines; + QMap, RemoteDataEngine*> m_remoteEngines; + QMap m_engineNameForService; }; } // namespace Plasma diff --git a/private/dataengineservice.cpp b/private/dataengineservice.cpp new file mode 100644 index 000000000..439483c85 --- /dev/null +++ b/private/dataengineservice.cpp @@ -0,0 +1,59 @@ +/* + * Copyright © 2009 Rob Scheepmaker + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "dataengineservice.h" +#include "getsource.h" +#include "../dataengine.h" + +#include + +namespace Plasma +{ + +DataEngineService::DataEngineService(DataEngine *engine) + : Plasma::Service(engine), + m_engine(engine) +{ + setName("dataengineservice"); + engine->connectAllSources(this, 1000); + connect(engine, SIGNAL(sourceAdded(QString)), this, SLOT(sourceAdded(QString))); +} + +Plasma::ServiceJob* DataEngineService::createJob(const QString& operation, + QMap& parameters) +{ + return new GetSource(m_engine, operation, parameters, this); +} + +void DataEngineService::dataUpdated(QString source, Plasma::DataEngine::Data data) +{ + if (data != m_data[source]) { + m_data[source] = data; + m_peersAlreadyUpdated[source] = QStringList(); + } +} + +void DataEngineService::sourceAdded(QString source) +{ + m_engine->connectSource(source, this, 1000); +} + +} + +#include "dataengineservice.moc" + diff --git a/private/dataengineservice.h b/private/dataengineservice.h new file mode 100644 index 000000000..ddf3e2d9f --- /dev/null +++ b/private/dataengineservice.h @@ -0,0 +1,59 @@ +/* + * Copyright © 2009 Rob Scheepmaker + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef PUBLICKEYSERVICE_H +#define PUBLICKEYSERVICE_H + +#include +#include +#include "../service.h" + +namespace Plasma +{ + +class DataEngine; +class GetSource; + +class DataEngineService : public Plasma::Service +{ + Q_OBJECT + + public: + DataEngineService(DataEngine *engine); + + public Q_SLOTS: + void dataUpdated(QString source, Plasma::DataEngine::Data data); + + protected: + Plasma::ServiceJob* createJob(const QString& operation, + QMap& parameters); + + private Q_SLOTS: + void sourceAdded(QString source); + + private: + DataEngine *m_engine; + QMap m_peersAlreadyUpdated; + QMap m_data; + + friend class GetSource; +}; + +} + +#endif diff --git a/private/denyallauthorization.cpp b/private/denyallauthorization.cpp new file mode 100644 index 000000000..e167bfdef --- /dev/null +++ b/private/denyallauthorization.cpp @@ -0,0 +1,53 @@ +/* + * Copyright 2009 by Rob Scheepmaker + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "denyallauthorization.h" + +#include "authorizationrule.h" +#include "clientpinrequest.h" + +#include + + +namespace Plasma +{ + +DenyAllAuthorization::DenyAllAuthorization() +{ +} + +DenyAllAuthorization::~DenyAllAuthorization() +{ +} + +void DenyAllAuthorization::clientPinRequest(ClientPinRequest &request) +{ + kDebug(); + request.setPin(""); +} + +void DenyAllAuthorization::authorizationRequest(AuthorizationRule &rule) +{ + kDebug(); + rule.setPolicy(AuthorizationRule::Deny); + rule.setTargets(AuthorizationRule::AllServices | AuthorizationRule::AllUsers); +} + +} // Plasma namespace + diff --git a/private/denyallauthorization.h b/private/denyallauthorization.h new file mode 100644 index 000000000..70bc40fb7 --- /dev/null +++ b/private/denyallauthorization.h @@ -0,0 +1,50 @@ +/* + * Copyright 2009 by Rob Scheepmaker + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef PLASMA_DENYALLAUTHORIZATION_H +#define PLASMA_DENYALLAUTHORIZATION_H + +#include "plasma_export.h" +#include "authorizationinterface.h" + +#include + +namespace Plasma +{ + +/** + * @class DenyAllAuthorization plasma/denyallauthorization.h + * + * @short Implementation of AuthorizationInterface that you can use if you don't want to allow + * any remote access in your shell. + * + * @since 4.4? + */ +class PLASMA_EXPORT DenyAllAuthorization : public AuthorizationInterface +{ + public: + DenyAllAuthorization(); + ~DenyAllAuthorization(); + virtual void authorizationRequest(AuthorizationRule &rule); + virtual void clientPinRequest(ClientPinRequest &request); +}; +} // Plasma namespace + +#endif + diff --git a/private/getpublickey.cpp b/private/getpublickey.cpp new file mode 100644 index 000000000..e0b2e0b7a --- /dev/null +++ b/private/getpublickey.cpp @@ -0,0 +1,35 @@ +/* + * Copyright © 2008 Rob Scheepmaker + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "getpublickey.h" + +#include + +void GetPublicKey::start() +{ + kDebug() << "Trying to perform the action" << operationName(); + + //TODO: check with capabilities before performing actions. + if (operationName() == "GetPublicKey") { + kDebug() << "setting result: " << m_pemKey; + setResult(m_pemKey); + } +} + +#include "getpublickey.moc" + diff --git a/private/getpublickey.h b/private/getpublickey.h new file mode 100644 index 000000000..d537538c1 --- /dev/null +++ b/private/getpublickey.h @@ -0,0 +1,44 @@ +/* + * Copyright © 2009 Rob Scheepmaker + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef GETPUBLICKEY_H +#define GETPUBLICKEY_H + +#include + +class GetPublicKey : public Plasma::ServiceJob +{ + Q_OBJECT + + public: + GetPublicKey(const QString &pemKey, + const QString& operation, + QMap& parameters, + QObject* parent = 0) + : ServiceJob(QString("publickey"), operation, parameters, parent), + m_pemKey(pemKey) + { + } + + void start(); + + private: + QString m_pemKey; +}; + +#endif //JOBVIEW_H diff --git a/private/getsource.cpp b/private/getsource.cpp new file mode 100644 index 000000000..ac908edb9 --- /dev/null +++ b/private/getsource.cpp @@ -0,0 +1,66 @@ +/* + * Copyright © 2008 Rob Scheepmaker + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "getsource.h" +#include "service_p.h" +#include "../dataengine.h" +#include +#include +#include +#include + +#include + +namespace Plasma +{ + +void GetSource::start() +{ + kDebug() << "Trying to perform the action" << operationName(); + + //TODO: check with capabilities before performing actions. + if (operationName() == "GetSource") { + QString source = parameters().value("SourceName").toString(); + QString UUID = parameters().value("UUID").toString(); + if (!m_service->m_peersAlreadyUpdated[source].contains(UUID)) { + m_service->m_peersAlreadyUpdated[source].append(UUID); + setResult(m_service->m_data[source]); + } else { + setResult(false); //no update needed + } + } else if (operationName() == "GetSourceNames") { + setResult(m_engine->sources()); + } else if (operationName() == "ServiceForSource") { + QString source = parameters().value("SourceName").toString(); + Service *service = m_engine->serviceForSource(source); + QString serviceName = "plasma-service-" + service->name(); + + kDebug() << "serviceForSource: getting source " << serviceName; + service->d->publish(Plasma::NoAnnouncement, serviceName); + if (!AuthorizationManager::self()->d->matchingRule(serviceName, identity())) { + AuthorizationRule *rule = new AuthorizationRule(serviceName, identity().id()); + AuthorizationManager::self()->d->rules.append(rule); + } + setResult(serviceName); + } +} + +} + +#include "getsource.moc" + diff --git a/private/getsource.h b/private/getsource.h new file mode 100644 index 000000000..b811c26e9 --- /dev/null +++ b/private/getsource.h @@ -0,0 +1,54 @@ +/* + * Copyright © 2009 Rob Scheepmaker + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef GETSOURCE_H +#define GETSOURCE_H + +#include +#include "../dataengine.h" +#include "dataengineservice.h" + +namespace Plasma +{ + +class DataEngine; + +class GetSource : public Plasma::ServiceJob +{ + Q_OBJECT + + public: + GetSource(DataEngine *engine, + const QString& operation, + QMap& parameters, + DataEngineService *service = 0) + : ServiceJob(QString("publickey"), operation, parameters, service), + m_engine(engine), + m_service(service) + { + } + + void start(); + + private: + DataEngine *m_engine; + DataEngineService *m_service; +}; +} + +#endif //JOBVIEW_H diff --git a/private/joliemessagehelper_p.h b/private/joliemessagehelper_p.h new file mode 100644 index 000000000..68ba2eabd --- /dev/null +++ b/private/joliemessagehelper_p.h @@ -0,0 +1,124 @@ +/* + * Copyright 2009 Rob Scheepmaker + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef JOLIEMESSAGEHELPER_H +#define JOLIEMESSAGEHELPER_H + +#include +#include +#include +#include +#include +#include + +namespace Message { + namespace Field { + static const QByteArray DESTINATION = "Destination"; + static const QByteArray ENABLEDOPERATIONS + = "EnabledOperations"; + static const QByteArray IDENTITY = "Credentials"; + static const QByteArray IDENTITYID = "CredentialsID"; + static const QByteArray PARAMETERS = "Parameters"; + static const QByteArray PIN = "PIN"; + static const QByteArray RESULT = "Result"; + static const QByteArray SIGNATURE = "Signature"; + static const QByteArray TOKEN = "Token"; + static const QByteArray UUID = "UUID"; + static const QByteArray OPERATION = "Operation"; + static const QByteArray OPERATIONSDESCRIPTION + = "OperationsDescription"; + } + + namespace Error { + static const QByteArray INVALIDTOKEN = "InvalidToken"; + static const QByteArray REQUIREPIN = "RequirePIN"; + static const QByteArray ACCESSDENIED = "AccessDenied"; + } + + inline QString errorMessage(const QByteArray &error) + { + if (error == Error::INVALIDTOKEN) { + return i18nc("Error message, access to a remote service failed.", + "Invalid token."); + } else if (error == Error::REQUIREPIN) { + return i18nc("Error message, access to a remote service failed.", + "Matching password required."); + } else if (error == Error::ACCESSDENIED) { + return i18nc("Error message, access to a remote service failed.", + "Access denied."); + } + return i18n("Unknown error."); + } + + inline QByteArray field(const QByteArray &fieldName, const Jolie::Message &message) + { + if (!message.data().children(fieldName).isEmpty()) { + return message.data().children(fieldName).first().toByteArray(); + } else { + return QByteArray(); + } + } + + inline QByteArray payload(const Jolie::Message &message) + { + QByteArray result; + //result = "payload!"; + result.append(message.operationName()); + result.append(field(Field::PARAMETERS, message)); + result.append(field(Field::IDENTITY, message)); + result.append(field(Field::IDENTITYID, message)); + result.append(field(Field::OPERATION, message)); + result.append(field(Field::OPERATIONSDESCRIPTION, message)); + result.append(field(Field::PIN, message)); + result.append(field(Field::TOKEN, message)); + return result; + } + + inline QString print(const Jolie::Message &message) + { + QString result; + result = + QString("\n=== JOLIE MESSAGE ===\nId = %1\nOperation = %2\nResource = %3\nData= %4\n") + .arg(QString::number(message.id())) + .arg(QString(message.operationName())) + .arg(QString(message.resourcePath())) + .arg(QString(message.data().toByteArray())); + + result += "=====================\n"; + + foreach (const QByteArray &child, message.data().childrenNames()) { + result += "\n******" + child + "******\n"; + foreach (const Jolie::Value &value, message.data().children(child)) { + if (child == Field::TOKEN || child == Field::PARAMETERS + || child == Field::SIGNATURE) { + result += value.toByteArray().toBase64(); + } else { + result += value.toByteArray(); + } + } + } + + result += "\n== END OF MESSAGE ==\n"; + + return result; + } +} + +#endif + diff --git a/private/package_p.h b/private/package_p.h new file mode 100644 index 000000000..369498223 --- /dev/null +++ b/private/package_p.h @@ -0,0 +1,38 @@ +#include +#include +#include + +#include + +namespace Plasma +{ + +class PackagePrivate +{ +public: + PackagePrivate(const PackageStructure::Ptr st, const QString &p); + ~PackagePrivate(); + + /** + * Publish this package on the network. + * @param methods the ways to announce this package on the network. + */ + void publish(AnnouncementMethods methods); + + /** + * Remove this package from the network. + */ + void unpublish(); + + /** + * @returns whether or not this service is currently published on the network. + */ + bool isPublished() const; + + PackageStructure::Ptr structure; + Service *service; + bool valid; +}; + +} + diff --git a/private/packages.cpp b/private/packages.cpp index d6eaeb2a5..53a8f9686 100644 --- a/private/packages.cpp +++ b/private/packages.cpp @@ -47,7 +47,7 @@ PlasmoidPackage::PlasmoidPackage(QObject *parent) addDirectoryDefinition("config", "config/", i18n("Configuration Definitions")); mimetypes.clear(); - mimetypes << "text/xml"; + mimetypes << "text/\*"; setMimetypes("config", mimetypes); setMimetypes("configui", mimetypes); @@ -64,6 +64,7 @@ PlasmoidPackage::PlasmoidPackage(QObject *parent) addFileDefinition("mainconfigui", "ui/config.ui", i18n("Main Config UI File")); addFileDefinition("mainconfigxml", "config/main.xml", i18n("Configuration XML file")); addFileDefinition("mainscript", "code/main", i18n("Main Script File")); + addFileDefinition("defaultconfig", "config/default-configrc", i18n("Default configuration")); setRequired("mainscript", true); } diff --git a/private/pinpairing.ui b/private/pinpairing.ui new file mode 100644 index 000000000..94f3b56a9 --- /dev/null +++ b/private/pinpairing.ui @@ -0,0 +1,78 @@ + + + pairingDialog + + + + 0 + 0 + 362 + 150 + + + + + + + + + + + + + + + + + 0 + 0 + + + + + 800 + 16777215 + + + + Enter a password below. Enter the same password on the device you're trying to connect with. + + + Qt::RichText + + + false + + + true + + + + + + + true + + + + + + + Always allow this user access to any service. + + + + + + + + + + KLineEdit + QLineEdit +
klineedit.h
+
+
+ + +
diff --git a/private/pinpairingauthorization.cpp b/private/pinpairingauthorization.cpp new file mode 100644 index 000000000..f5c78fc35 --- /dev/null +++ b/private/pinpairingauthorization.cpp @@ -0,0 +1,60 @@ +/* + * Copyright 2009 by Rob Scheepmaker + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "pinpairingauthorization.h" + +#include "authorizationrule.h" +#include "clientpinrequest.h" +#include "pinpairingdialog.h" + +#include +#include + + +namespace Plasma +{ + +PinPairingAuthorization::PinPairingAuthorization() +{ +} + +PinPairingAuthorization::~PinPairingAuthorization() +{ + //TODO: cleanup +} + +void PinPairingAuthorization::clientPinRequest(ClientPinRequest &request) +{ + kDebug(); + new PinPairingDialog(request); +} + +void PinPairingAuthorization::authorizationRequest(AuthorizationRule &rule) +{ + kDebug(); + if (rule.credentials().trustLevel() > TrustedCredentials) { + rule.setPolicy(AuthorizationRule::Allow); + rule.setTargets(AuthorizationRule::AllServices); + } else { + new PinPairingDialog(rule); + } +} + +} // Plasma namespace + diff --git a/private/pinpairingauthorization.h b/private/pinpairingauthorization.h new file mode 100644 index 000000000..4b868d793 --- /dev/null +++ b/private/pinpairingauthorization.h @@ -0,0 +1,52 @@ +/* + * Copyright 2009 by Rob Scheepmaker + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef PLASMA_PINPAIRINGAUTHORIZATION_H +#define PLASMA_PINPAIRINGAUTHORIZATION_H + +#include "plasma_export.h" +#include "pinpairingauthorization.h" +#include "authorizationinterface.h" + +#include + +namespace Plasma +{ + +/** + * @class PinPairingAuthorization plasma/pinpairingauthorization.h + * + * @short Implementation of AuthorizationInterface that you can use if you want to use standard + * pin pairing authorization (let the user type the same password at both sides) in your shell for + * every rule that doesn't match. + * + * @since 4.4? + */ +class PLASMA_EXPORT PinPairingAuthorization : public AuthorizationInterface +{ + public: + PinPairingAuthorization(); + ~PinPairingAuthorization(); + virtual void authorizationRequest(AuthorizationRule &rule); + virtual void clientPinRequest(ClientPinRequest &request); +}; +} // Plasma namespace + +#endif + diff --git a/private/pinpairingdialog.cpp b/private/pinpairingdialog.cpp new file mode 100644 index 000000000..2d6ad5505 --- /dev/null +++ b/private/pinpairingdialog.cpp @@ -0,0 +1,115 @@ +/* + Copyright (C) 2009 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "pinpairingdialog.h" + +#include "authorizationrule.h" +#include "clientpinrequest.h" +#include "ui_pinpairing.h" + +#include +#include + +namespace Plasma +{ + +class PinPairingDialogPrivate +{ +public: + PinPairingDialogPrivate(AuthorizationRule *rule, ClientPinRequest *request, PinPairingDialog *q) + : q(q), + rule(rule), + request(request), + dialog(new KDialog(0)) + { + QWidget *widget = new QWidget(dialog); + pairingUI.setupUi(widget); + dialog->setMainWidget(widget); + if (rule) { + dialog->setCaption(i18n("Incoming connection request")); + pairingUI.descriptionLabel->setText(rule->description()); + } + + if (request) { + dialog->setCaption(i18n("Connect with remote widget")); + pairingUI.alwaysAllowCheckbox->setVisible(false); + pairingUI.descriptionLabel->setText(request->description()); + } + + dialog->setButtons(KDialog::Ok | KDialog::Cancel); + dialog->show(); + + q->connect(dialog, SIGNAL(okClicked()), q, SLOT(slotAccept())); + q->connect(dialog, SIGNAL(cancelClicked()), q, SLOT(slotReject())); + } + + ~PinPairingDialogPrivate() + { + } + + void slotAccept() + { + kDebug(); + if (rule) { + rule->setPin(pairingUI.password->text()); + if (pairingUI.alwaysAllowCheckbox->isChecked()) { + rule->setPolicy(AuthorizationRule::PinRequired); + rule->setTargets(AuthorizationRule::AllServices); + } else { + rule->setPolicy(AuthorizationRule::PinRequired); + } + } + + if (request) { + request->setPin(pairingUI.password->text()); + } + + q->deleteLater(); + } + + void slotReject() + { + q->deleteLater(); + } + + PinPairingDialog *q; + AuthorizationRule *rule; + ClientPinRequest *request; + Ui::pairingDialog pairingUI; + KDialog *dialog; +}; + +PinPairingDialog::PinPairingDialog(AuthorizationRule &rule, QObject *parent) + : QObject(parent), + d(new PinPairingDialogPrivate(&rule, 0, this)) +{ +} + +PinPairingDialog::PinPairingDialog(ClientPinRequest &request, QObject *parent) + : QObject(parent), + d(new PinPairingDialogPrivate(0, &request, this)) +{ +} + +PinPairingDialog::~PinPairingDialog() +{ +} + +} + +#include "pinpairingdialog.moc" diff --git a/private/pinpairingdialog.h b/private/pinpairingdialog.h new file mode 100644 index 000000000..eb6157056 --- /dev/null +++ b/private/pinpairingdialog.h @@ -0,0 +1,54 @@ +/* + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef PINPAIRINGDIALOG_H +#define PINPAIRINGDIALOG_H + +#include "plasma_export.h" +#include + +namespace Plasma +{ + +class AuthorizationRule; +class ClientPinRequest; +class PinPairingDialogPrivate; + +class PLASMA_EXPORT PinPairingDialog : public QObject +{ + +Q_OBJECT + +public: + PinPairingDialog(AuthorizationRule &rule, QObject* parent = 0); + PinPairingDialog(ClientPinRequest &request, QObject* parent = 0); + ~PinPairingDialog(); + +private: + PinPairingDialogPrivate *const d; + + Q_PRIVATE_SLOT(d, void slotAccept()); + Q_PRIVATE_SLOT(d, void slotReject()); + + friend class PinPairingDialogPrivate; +}; + +} + +#endif // PINPAIRINGDIALOG_H diff --git a/private/plasmoidservice.cpp b/private/plasmoidservice.cpp new file mode 100644 index 000000000..c4ab1d20b --- /dev/null +++ b/private/plasmoidservice.cpp @@ -0,0 +1,150 @@ +/* + * Copyright © 2009 Rob Scheepmaker + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "plasmoidservice.h" + +#include "authorizationmanager_p.h" +#include "dataengineconsumer_p.h" +#include "dataengine_p.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +namespace Plasma +{ + +PlasmoidServiceJob::PlasmoidServiceJob(const QString &plasmoidLocation, + const QString &destination, + const QString &operation, + QMap& parameters, + PlasmoidService *service) + : Plasma::ServiceJob(destination, operation, parameters, + static_cast(service)), + m_service(service), + m_packagePath(plasmoidLocation) +{ +} + +void PlasmoidServiceJob::start() +{ + if (operationName() == "GetPackage") { + kDebug() << "sending " << m_service->m_packagePath; + QFileInfo fileInfo(m_service->m_packagePath); + + if (fileInfo.exists() && fileInfo.isFile() && fileInfo.isAbsolute()) { + kDebug() << "file exists, let's try and read it"; + QFile file(m_service->m_packagePath); + file.open(QIODevice::ReadOnly); + setResult(file.readAll()); + } else { + kDebug() << "file doesn't exists, we're sending the plugin name"; + setResult(m_packagePath); + } + } else if (operationName() == "GetMetaData") { + KTemporaryFile tempFile; + m_service->m_metadata.write(tempFile.fileName()); + QFile file(tempFile.fileName()); + setResult(file.readAll()); + } else if (operationName() == "DataEngine") { + DataEngine *engine = m_service->dataEngine(parameters()["EngineName"].toString()); + QString serviceName = "plasma-dataengine-" + parameters()["EngineName"].toString(); + engine->d->publish(NoAnnouncement, serviceName); + if (!AuthorizationManager::self()->d->matchingRule(serviceName, identity())) { + AuthorizationRule *rule = new AuthorizationRule(serviceName, identity().id()); + rule->setPolicy(AuthorizationRule::Allow); + AuthorizationManager::self()->d->rules.append(rule); + } + setResult(serviceName); + } +} + + +PlasmoidService::PlasmoidService(const QString &packageLocation) + : Plasma::Service(0) +{ + setName("plasmoidservice"); + + QString location; + location = packageLocation; + if (!location.endsWith('/')) { + location.append('/'); + } + + m_metadata.read(location + "metadata.desktop"); + if (!m_metadata.isValid()) { + kDebug() << "not a valid package"; + } + if (!m_tempFile.open()) { + kDebug() << "could not create tempfile"; + } + QString packagePath = m_tempFile.fileName(); + m_tempFile.close(); + + + // put everything into a zip archive + KZip creation(packagePath); + creation.setCompression(KZip::NoCompression); + if (!creation.open(QIODevice::WriteOnly)) { + kDebug() << "could not open archive"; + } + + creation.addLocalFile(location + "metadata.desktop", "metadata.desktop"); + location.append("contents/"); + creation.addLocalDirectory(location, "contents"); + creation.close(); + + m_packagePath = packagePath; +} + +PlasmoidService::PlasmoidService(Applet *applet) +{ + setName("plasmoidservice"); + if (!applet->package() || !applet->package()->isValid()) { + kDebug() << "not a valid package"; + m_packagePath = applet->pluginName(); + } +} + +PackageMetadata PlasmoidService::metadata() const +{ + return m_metadata; +} + +Plasma::ServiceJob* PlasmoidService::createJob(const QString& operation, + QMap& parameters) +{ + return new PlasmoidServiceJob(m_packagePath, destination(), operation, parameters, this); +} + +} + +#include "plasmoidservice.moc" + diff --git a/private/plasmoidservice.h b/private/plasmoidservice.h new file mode 100644 index 000000000..bbb7e73c1 --- /dev/null +++ b/private/plasmoidservice.h @@ -0,0 +1,82 @@ +/* + * Copyright © 2009 Rob Scheepmaker + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef PUBLICKEYSERVICE_H +#define PUBLICKEYSERVICE_H + +#include "dataengineconsumer_p.h" +#include +#include +#include +#include + +#include + +namespace Plasma +{ + +class Applet; +class DataEngine; +class GetSource; +class PlasmoidService; + +class PlasmoidServiceJob : public ServiceJob +{ + Q_OBJECT + + public: + PlasmoidServiceJob(const QString &plasmoidLocation, + const QString &destination, + const QString &operation, + QMap& parameters, + PlasmoidService *parent = 0); + + void start(); + + private: + PlasmoidService *m_service; + QString m_packagePath; + QString m_pluginName; +}; + +class PlasmoidService : public Service, DataEngineConsumer +{ + Q_OBJECT + + public: + PlasmoidService(const QString &plasmoidLocation); + PlasmoidService(Applet *applet); + PackageMetadata metadata() const; + + + protected: + Plasma::ServiceJob* createJob(const QString& operation, + QMap& parameters); + + private: + QString m_packagePath; + PackageMetadata m_metadata; + KTemporaryFile m_tempFile; + //Package m_package; + + friend class PlasmoidServiceJob; +}; + +} + +#endif diff --git a/private/publickeyfetcher.cpp b/private/publickeyfetcher.cpp new file mode 100644 index 000000000..07b01b8f7 --- /dev/null +++ b/private/publickeyfetcher.cpp @@ -0,0 +1,82 @@ +/* + * Copyright 2009 by Rob Scheepmaker + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "publickeyfetcher.h" +#include "authorizationmanager_p.h" +#include "joliemessagehelper_p.h" +#include "../authorizationmanager.h" +#include "../accessmanager.h" +#include "../servicejob.h" +#include "../serviceaccessjob.h" + +#include +#include +#include + +namespace Plasma +{ + +PublicKeyFetcher::PublicKeyFetcher(const QString &sender) + : QObject(AuthorizationManager::self()), + m_sender(sender) +{ + connect(AccessManager::self(), SIGNAL(serviceAccessFinished(Plasma::ServiceAccessJob*)), + this, SLOT(slotKeyServiceReady(Plasma::ServiceAccessJob*))); + AccessManager::self()->accessService(KUrl(sender)); +} + +PublicKeyFetcher::~PublicKeyFetcher() +{ +} + +QList & PublicKeyFetcher::pendingMessages() +{ + return m_messageList; +} + +void PublicKeyFetcher::slotKeyServiceReady(Plasma::ServiceAccessJob *job) +{ + if (job->service()) { + KConfigGroup op = job->service()->operationDescription("GetPublicKey"); + job->service()->startOperationCall(op); + connect(job->service(), SIGNAL(finished(Plasma::ServiceJob*)), + this, SLOT(slotKeyObtained(Plasma::ServiceJob*))); + } +} + +void PublicKeyFetcher::slotKeyObtained(Plasma::ServiceJob *job) +{ + QByteArray reply = job->result().toByteArray(); + QCA::PublicKey key = QCA::PublicKey::fromPEM(reply); + AuthorizationManager::self()->d->publicKeys[m_sender] = key; + + KConfig c("plasmapublickeys"); + c.group(m_sender).writeEntry("PublicKey", key.toPEM()); + + kDebug() << "Obtained public key from: " << m_sender << ", public key: " << reply; + + foreach (Jolie::Message message, m_messageList) { + kDebug() << "process pending message: " << printJolieMessage(message); + AuthorizationManager::self()->d->startAuthorization(message, ""); + } +} + +} // Plasma namespace + +#include "publickeyfetcher.moc" diff --git a/private/publickeyfetcher.h b/private/publickeyfetcher.h new file mode 100644 index 000000000..4504d26fa --- /dev/null +++ b/private/publickeyfetcher.h @@ -0,0 +1,56 @@ +/* + * Copyright 2009 by Rob Scheepmaker + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef PLASMA_PUBLICKEYFETCHER_H +#define PLASMA_PUBLICKEYFETCHER_H + +#include +#include +#include + +class QString; + +namespace Plasma +{ + +class AuthorizationManager; +class ServiceAccessJob; +class ServiceJob; + +class PublicKeyFetcher : public QObject +{ + Q_OBJECT + public: + PublicKeyFetcher(const QString &sender); + ~PublicKeyFetcher(); + + QList & pendingMessages(); + + private Q_SLOTS: + void slotKeyServiceReady(Plasma::ServiceAccessJob *job); + void slotKeyObtained(Plasma::ServiceJob *job); + + private: + QList m_messageList; + QString m_sender; +}; +} // Plasma namespace + +#endif + diff --git a/private/publickeyfetcher_p.h b/private/publickeyfetcher_p.h new file mode 100644 index 000000000..82e56082e --- /dev/null +++ b/private/publickeyfetcher_p.h @@ -0,0 +1,56 @@ +/* + * Copyright 2009 by Rob Scheepmaker + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef PLASMA_PUBLICKEYFETCHER_H +#define PLASMA_PUBLICKEYFETCHER_H + +#include +#include +#include + +class QString; + +namespace Plasma +{ + +class AuthorizationManager; +class ServiceAccessJob; +class ServiceJob; + +class PublicKeyFetcher : public QObject +{ + Q_OBJECT + public: + PublicKeyFetcher(const QString &sender, AuthorizationManager *am); + ~PublicKeyFetcher(); + + QList pendingMessages(); + + private Q_SLOTS: + void slotKeyServiceReady(ServiceAccessJob *job); + void slotKeyServiceObtained(ServiceAccessJob *job); + + private: + QList m_messageList; + QString m_sender; +}; +} // Plasma namespace + +#endif + diff --git a/private/publickeyservice.cpp b/private/publickeyservice.cpp new file mode 100644 index 000000000..129f04552 --- /dev/null +++ b/private/publickeyservice.cpp @@ -0,0 +1,39 @@ +/* + * Copyright © 2008 Rob Scheepmaker + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "publickeyservice.h" +#include "getpublickey.h" + +#include + +PublicKeyService::PublicKeyService(const QString &pemKey, QObject* parent) + : Plasma::Service(parent), + m_pemKey(pemKey) +{ + setName("publickeyservice"); +} + +Plasma::ServiceJob* PublicKeyService::createJob(const QString& operation, + QMap& parameters) +{ + kDebug(); + return new GetPublicKey(m_pemKey, operation, parameters, this); +} + +#include "publickeyservice.moc" + diff --git a/private/publickeyservice.h b/private/publickeyservice.h new file mode 100644 index 000000000..fac75f115 --- /dev/null +++ b/private/publickeyservice.h @@ -0,0 +1,40 @@ +/* + * Copyright © 2009 Rob Scheepmaker + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef PUBLICKEYSERVICE_H +#define PUBLICKEYSERVICE_H + +#include "../service.h" + +class PublicKeyService : public Plasma::Service +{ + Q_OBJECT + + public: + PublicKeyService(const QString &pemKey, QObject* parent); + + protected: + Plasma::ServiceJob* createJob(const QString& operation, + QMap& parameters); + + private: + QString m_pemKey; + +}; + +#endif diff --git a/private/publish.ui b/private/publish.ui new file mode 100644 index 000000000..520456881 --- /dev/null +++ b/private/publish.ui @@ -0,0 +1,51 @@ + + + publishWidget + + + + 0 + 0 + 394 + 131 + + + + Form + + + + + + Publishing a widget on the network allows you to access this widget from another computer as a remote control. + + + true + + + + + + + Publish this widget on the network. + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + diff --git a/private/qtjolie-branch/CMakeLists.txt b/private/qtjolie-branch/CMakeLists.txt index ae270c9b8..0f276dcbc 100644 --- a/private/qtjolie-branch/CMakeLists.txt +++ b/private/qtjolie-branch/CMakeLists.txt @@ -1,10 +1,3 @@ -find_package(KDE4 REQUIRED) -include(KDE4Defaults) -include(MacroLibrary) - -add_definitions(${QT_DEFINITIONS} ${KDE4_DEFINITIONS}) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_NO_CAST_FROM_ASCII -DQT_NO_CAST_TO_ASCII") - add_subdirectory(qtjolie) add_subdirectory(includes) -add_subdirectory(tests) +#add_subdirectory(tests) diff --git a/private/qtjolie-branch/qtjolie/CMakeLists.txt b/private/qtjolie-branch/qtjolie/CMakeLists.txt index a21e04efa..8f8bd6b7e 100644 --- a/private/qtjolie-branch/qtjolie/CMakeLists.txt +++ b/private/qtjolie-branch/qtjolie/CMakeLists.txt @@ -1,5 +1,3 @@ -project(QtJolie) - include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../ ${CMAKE_CURRENT_BINARY_DIR} @@ -20,14 +18,14 @@ set(qtjolie_LIB_SRCS serverthread.cpp ) -kde4_add_library(QtJolie SHARED ${qtjolie_LIB_SRCS}) +kde4_add_library(QtJoliePlasmaPrivate SHARED ${qtjolie_LIB_SRCS}) -target_link_libraries(QtJolie ${QT_QTCORE_LIBRARY} ${QT_QTNETWORK_LIBRARY}) +target_link_libraries(QtJoliePlasmaPrivate ${QT_QTCORE_LIBRARY} ${QT_QTNETWORK_LIBRARY}) -install(TARGETS QtJolie +install(TARGETS QtJoliePlasmaPrivate DESTINATION ${LIB_INSTALL_DIR}) -set_target_properties(QtJolie PROPERTIES VERSION 1.0.0 SOVERSION 1) +set_target_properties(QtJoliePlasmaPrivate PROPERTIES VERSION 1.0.0 SOVERSION 1) install(FILES abstractadaptor.h @@ -43,9 +41,9 @@ install(FILES DESTINATION ${INCLUDE_INSTALL_DIR}/qtjolie) if(NOT WIN32) # pkgconfig file - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/QtJolie.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/QtJolie.pc @ONLY) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/QtJolie.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/QtJolie.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/QtJoliePlasmaPrivate.pc @ONLY) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/QtJoliePlasmaPrivate.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) endif(NOT WIN32) -configure_file("QtJolie.prf.cmake" "${CMAKE_BINARY_DIR}/QtJolie.prf" @ONLY) -install(FILES "${CMAKE_BINARY_DIR}/QtJolie.prf" DESTINATION ${CMAKE_INSTALL_PREFIX}/mkspecs/features) +configure_file("QtJolie.prf.cmake" "${CMAKE_BINARY_DIR}/QtJoliePlasmaPrivate.prf" @ONLY) +install(FILES "${CMAKE_BINARY_DIR}/QtJoliePlasmaPrivate.prf" DESTINATION ${CMAKE_INSTALL_PREFIX}/mkspecs/features) diff --git a/private/qtjolie-branch/qtjolie/QtJolie.pc.cmake b/private/qtjolie-branch/qtjolie/QtJolie.pc.cmake index 1995ed3b0..5d40665cc 100644 --- a/private/qtjolie-branch/qtjolie/QtJolie.pc.cmake +++ b/private/qtjolie-branch/qtjolie/QtJolie.pc.cmake @@ -7,5 +7,5 @@ Name: QtJolie Description: A QtDbus like API for JOLIE Version: 1.0.0 Requires: QtCore -Libs: -L${libdir} -llibQtJolie +Libs: -L${libdir} -lQtJolie Cflags: -I${includedir} diff --git a/private/qtjolie-branch/qtjolie/QtJolie.prf.cmake b/private/qtjolie-branch/qtjolie/QtJolie.prf.cmake index 333c50a85..48c6066eb 100644 --- a/private/qtjolie-branch/qtjolie/QtJolie.prf.cmake +++ b/private/qtjolie-branch/qtjolie/QtJolie.prf.cmake @@ -5,9 +5,9 @@ CONFIG *= qt INCLUDEPATH += $$QTJOLIE_INCDIR LIBS += -L$$QTJOLIE_LIBDIR -LINKAGE = -llibQtJolie +LINKAGE = -lQtJolie CONFIG(debug, debug|release) { - windows:LINKAGE = -llibQtJolied - mac:LINKAGE = -llibQtJolie_debug + windows:LINKAGE = -lQtJolied + mac:LINKAGE = -lQtJolie_debug } LIBS += $$LINKAGE diff --git a/private/qtjolie-branch/qtjolie/abstractadaptor.cpp b/private/qtjolie-branch/qtjolie/abstractadaptor.cpp index fcfc597a8..e9839895c 100644 --- a/private/qtjolie-branch/qtjolie/abstractadaptor.cpp +++ b/private/qtjolie-branch/qtjolie/abstractadaptor.cpp @@ -20,6 +20,9 @@ #include "abstractadaptor.h" +#define QT_NO_CAST_FROM_ASCII +#define QT_NO_CAST_TO_ASCII + namespace Jolie { class AbstractAdaptorPrivate diff --git a/private/qtjolie-branch/qtjolie/abstractadaptor.h b/private/qtjolie-branch/qtjolie/abstractadaptor.h index fb7a3416c..be2aec976 100644 --- a/private/qtjolie-branch/qtjolie/abstractadaptor.h +++ b/private/qtjolie-branch/qtjolie/abstractadaptor.h @@ -40,7 +40,7 @@ public: private: - virtual Message relay(Server *server, const Message &message) = 0; + virtual void relay(Server *server, int descriptor, const Message &message) = 0; friend class ServerPrivate; diff --git a/private/qtjolie-branch/qtjolie/client.cpp b/private/qtjolie-branch/qtjolie/client.cpp index df03857a9..9f1a19d34 100644 --- a/private/qtjolie-branch/qtjolie/client.cpp +++ b/private/qtjolie-branch/qtjolie/client.cpp @@ -26,6 +26,9 @@ #include "pendingcall.h" #include "pendingreply.h" +#define QT_NO_CAST_FROM_ASCII +#define QT_NO_CAST_TO_ASCII + using namespace Jolie; Client::Client(const QString &hostName, quint16 port) diff --git a/private/qtjolie-branch/qtjolie/clientthread.cpp b/private/qtjolie-branch/qtjolie/clientthread.cpp index c165dcdbd..837827356 100644 --- a/private/qtjolie-branch/qtjolie/clientthread.cpp +++ b/private/qtjolie-branch/qtjolie/clientthread.cpp @@ -26,6 +26,9 @@ #include "message.h" #include "sodephelpers_p.h" +#define QT_NO_CAST_FROM_ASCII +#define QT_NO_CAST_TO_ASCII + using namespace Jolie; ClientThread::ClientThread(const QString &hostName, quint16 port, ClientPrivate *client) diff --git a/private/qtjolie-branch/qtjolie/fault.cpp b/private/qtjolie-branch/qtjolie/fault.cpp index 5a213d46b..7fcba74bf 100644 --- a/private/qtjolie-branch/qtjolie/fault.cpp +++ b/private/qtjolie-branch/qtjolie/fault.cpp @@ -24,6 +24,9 @@ #include "sodephelpers_p.h" +#define QT_NO_CAST_FROM_ASCII +#define QT_NO_CAST_TO_ASCII + namespace Jolie { diff --git a/private/qtjolie-branch/qtjolie/message.cpp b/private/qtjolie-branch/qtjolie/message.cpp index 68d56c2e3..10633c65b 100644 --- a/private/qtjolie-branch/qtjolie/message.cpp +++ b/private/qtjolie-branch/qtjolie/message.cpp @@ -24,6 +24,9 @@ #include "sodephelpers_p.h" +#define QT_NO_CAST_FROM_ASCII +#define QT_NO_CAST_TO_ASCII + namespace Jolie { diff --git a/private/qtjolie-branch/qtjolie/metaservice.cpp b/private/qtjolie-branch/qtjolie/metaservice.cpp index ed4042117..deb06d9cf 100644 --- a/private/qtjolie-branch/qtjolie/metaservice.cpp +++ b/private/qtjolie-branch/qtjolie/metaservice.cpp @@ -25,6 +25,9 @@ #include "client.h" #include "message.h" +#define QT_NO_CAST_FROM_ASCII +#define QT_NO_CAST_TO_ASCII + namespace Jolie { diff --git a/private/qtjolie-branch/qtjolie/pendingcall.cpp b/private/qtjolie-branch/qtjolie/pendingcall.cpp index dff30f9a7..6f40fb2f1 100644 --- a/private/qtjolie-branch/qtjolie/pendingcall.cpp +++ b/private/qtjolie-branch/qtjolie/pendingcall.cpp @@ -22,6 +22,9 @@ #include "pendingcall_p.h" #include "pendingcallwatcher.h" +#define QT_NO_CAST_FROM_ASCII +#define QT_NO_CAST_TO_ASCII + using namespace Jolie; PendingCall::PendingCall(const PendingCall &other) diff --git a/private/qtjolie-branch/qtjolie/pendingcallwatcher.cpp b/private/qtjolie-branch/qtjolie/pendingcallwatcher.cpp index 250eb5c31..8786bae4d 100644 --- a/private/qtjolie-branch/qtjolie/pendingcallwatcher.cpp +++ b/private/qtjolie-branch/qtjolie/pendingcallwatcher.cpp @@ -22,6 +22,9 @@ #include "pendingcall_p.h" +#define QT_NO_CAST_FROM_ASCII +#define QT_NO_CAST_TO_ASCII + using namespace Jolie; PendingCallWatcher::PendingCallWatcher(const PendingCall &other, QObject *parent) diff --git a/private/qtjolie-branch/qtjolie/pendingreply.cpp b/private/qtjolie-branch/qtjolie/pendingreply.cpp index d13e21755..1411d7f38 100644 --- a/private/qtjolie-branch/qtjolie/pendingreply.cpp +++ b/private/qtjolie-branch/qtjolie/pendingreply.cpp @@ -22,6 +22,9 @@ #include "pendingcall_p.h" +#define QT_NO_CAST_FROM_ASCII +#define QT_NO_CAST_TO_ASCII + using namespace Jolie; PendingReply::PendingReply() diff --git a/private/qtjolie-branch/qtjolie/qtjolie.diff b/private/qtjolie-branch/qtjolie/qtjolie.diff new file mode 100644 index 000000000..db249f117 --- /dev/null +++ b/private/qtjolie-branch/qtjolie/qtjolie.diff @@ -0,0 +1,111 @@ +Index: server.cpp +=================================================================== +--- server.cpp (revision 985276) ++++ server.cpp (working copy) +@@ -22,6 +22,7 @@ + #include "server_p.h" + + #include ++#include + + #include "abstractadaptor.h" + #include "serverthread_p.h" +@@ -56,11 +57,13 @@ + + bool Server::registerAdaptor(const QByteArray &path, AbstractAdaptor *adaptor) + { ++ //qDebug() << "registering an adaptor: " << QString(path); + if (path.isEmpty() || d->adaptors.contains(path)) { + return false; + } + + d->adaptors[path] = adaptor; ++ return true; + } + + bool Server::unregisterAdaptor(const QByteArray &path) +@@ -68,11 +71,16 @@ + return d->adaptors.take(path)!=0; + } + ++void Server::sendMessage(int descriptor, const Message &message) ++{ ++ d->serverThread->sendMessage(descriptor, message); ++} ++ + void ServerPrivate::messageReceived(int descriptor, const Message &message) + { + if (adaptors.contains(message.resourcePath())) { +- Message reply = adaptors[message.resourcePath()]->relay(q, message); +- serverThread->sendMessage(descriptor, reply); ++ adaptors[message.resourcePath()]->relay(q, descriptor, message); ++ //serverThread->sendMessage(descriptor, reply); + } else { + qWarning() << "Got a message for an unregistered object:" + << message.operationName() +Index: sodephelpers_p.h +=================================================================== +--- sodephelpers_p.h (revision 985276) ++++ sodephelpers_p.h (working copy) +@@ -193,7 +193,7 @@ + io.read(data, length); + data[length] = '\0'; + +- QByteArray result(data); ++ QByteArray result(data, length); + delete[] data; + + return result; +Index: abstractadaptor.h +=================================================================== +--- abstractadaptor.h (revision 985276) ++++ abstractadaptor.h (working copy) +@@ -40,7 +40,7 @@ + + + private: +- virtual Message relay(Server *server, const Message &message) = 0; ++ virtual void relay(Server *server, int descriptor, const Message &message) = 0; + + friend class ServerPrivate; + +Index: QtJolie.prf.cmake +=================================================================== +--- QtJolie.prf.cmake (revision 985276) ++++ QtJolie.prf.cmake (working copy) +@@ -5,9 +5,9 @@ + INCLUDEPATH += $$QTJOLIE_INCDIR + LIBS += -L$$QTJOLIE_LIBDIR + +-LINKAGE = -llibQtJolie ++LINKAGE = -lQtJolie + CONFIG(debug, debug|release) { +- windows:LINKAGE = -llibQtJolied +- mac:LINKAGE = -llibQtJolie_debug ++ windows:LINKAGE = -lQtJolied ++ mac:LINKAGE = -lQtJolie_debug + } + LIBS += $$LINKAGE +Index: QtJolie.pc.cmake +=================================================================== +--- QtJolie.pc.cmake (revision 985276) ++++ QtJolie.pc.cmake (working copy) +@@ -7,5 +7,5 @@ + Description: A QtDbus like API for JOLIE + Version: 1.0.0 + Requires: QtCore +-Libs: -L${libdir} -llibQtJolie ++Libs: -L${libdir} -lQtJolie + Cflags: -I${includedir} +Index: server.h +=================================================================== +--- server.h (revision 985276) ++++ server.h (working copy) +@@ -47,6 +47,7 @@ + + bool registerAdaptor(const QByteArray &path, AbstractAdaptor *adaptor); + bool unregisterAdaptor(const QByteArray &path); ++ void sendMessage(int descriptor, const Message &message); + + private: + friend class ServerPrivate; diff --git a/private/qtjolie-branch/qtjolie/server.cpp b/private/qtjolie-branch/qtjolie/server.cpp index 9750a8921..4d25482ba 100644 --- a/private/qtjolie-branch/qtjolie/server.cpp +++ b/private/qtjolie-branch/qtjolie/server.cpp @@ -22,6 +22,7 @@ #include "server_p.h" #include +#include #include "abstractadaptor.h" #include "serverthread_p.h" @@ -29,6 +30,9 @@ #include "pendingcall.h" #include "pendingreply.h" +#define QT_NO_CAST_FROM_ASCII +#define QT_NO_CAST_TO_ASCII + using namespace Jolie; Server::Server(quint16 port) @@ -56,11 +60,13 @@ QString Server::errorString() const bool Server::registerAdaptor(const QByteArray &path, AbstractAdaptor *adaptor) { + //qDebug() << "registering an adaptor: " << QString(path); if (path.isEmpty() || d->adaptors.contains(path)) { return false; } d->adaptors[path] = adaptor; + return true; } bool Server::unregisterAdaptor(const QByteArray &path) @@ -68,11 +74,16 @@ bool Server::unregisterAdaptor(const QByteArray &path) return d->adaptors.take(path)!=0; } +void Server::sendMessage(int descriptor, const Message &message) +{ + d->serverThread->sendMessage(descriptor, message); +} + void ServerPrivate::messageReceived(int descriptor, const Message &message) { if (adaptors.contains(message.resourcePath())) { - Message reply = adaptors[message.resourcePath()]->relay(q, message); - serverThread->sendMessage(descriptor, reply); + adaptors[message.resourcePath()]->relay(q, descriptor, message); + //serverThread->sendMessage(descriptor, reply); } else { qWarning() << "Got a message for an unregistered object:" << message.operationName() diff --git a/private/qtjolie-branch/qtjolie/server.h b/private/qtjolie-branch/qtjolie/server.h index 2855ecef3..3904c13b5 100644 --- a/private/qtjolie-branch/qtjolie/server.h +++ b/private/qtjolie-branch/qtjolie/server.h @@ -47,6 +47,7 @@ public: bool registerAdaptor(const QByteArray &path, AbstractAdaptor *adaptor); bool unregisterAdaptor(const QByteArray &path); + void sendMessage(int descriptor, const Message &message); private: friend class ServerPrivate; diff --git a/private/qtjolie-branch/qtjolie/serverthread.cpp b/private/qtjolie-branch/qtjolie/serverthread.cpp index a609e2f36..ab6dac4f7 100644 --- a/private/qtjolie-branch/qtjolie/serverthread.cpp +++ b/private/qtjolie-branch/qtjolie/serverthread.cpp @@ -27,6 +27,9 @@ #include "message.h" #include "sodephelpers_p.h" +#define QT_NO_CAST_FROM_ASCII +#define QT_NO_CAST_TO_ASCII + using namespace Jolie; Q_DECLARE_METATYPE(QAbstractSocket*) diff --git a/private/qtjolie-branch/qtjolie/sodephelpers_p.h b/private/qtjolie-branch/qtjolie/sodephelpers_p.h index 7d5696261..660815900 100644 --- a/private/qtjolie-branch/qtjolie/sodephelpers_p.h +++ b/private/qtjolie-branch/qtjolie/sodephelpers_p.h @@ -191,9 +191,9 @@ inline QByteArray sodepReadByteArray(QIODevice &io) char *data = new char[length+1]; io.read(data, length); - data[length] = '\0'; + //data[length] = '\0'; - QByteArray result(data); + QByteArray result(data, length); delete[] data; return result; diff --git a/private/qtjolie-branch/qtjolie/value.cpp b/private/qtjolie-branch/qtjolie/value.cpp index 15e6c492e..190978c43 100644 --- a/private/qtjolie-branch/qtjolie/value.cpp +++ b/private/qtjolie-branch/qtjolie/value.cpp @@ -24,6 +24,9 @@ #include "sodephelpers_p.h" +#define QT_NO_CAST_FROM_ASCII +#define QT_NO_CAST_TO_ASCII + namespace Jolie { diff --git a/private/qtjolie-branch/qtjolie/~.qtjolie.diff b/private/qtjolie-branch/qtjolie/~.qtjolie.diff new file mode 100644 index 000000000..db249f117 --- /dev/null +++ b/private/qtjolie-branch/qtjolie/~.qtjolie.diff @@ -0,0 +1,111 @@ +Index: server.cpp +=================================================================== +--- server.cpp (revision 985276) ++++ server.cpp (working copy) +@@ -22,6 +22,7 @@ + #include "server_p.h" + + #include ++#include + + #include "abstractadaptor.h" + #include "serverthread_p.h" +@@ -56,11 +57,13 @@ + + bool Server::registerAdaptor(const QByteArray &path, AbstractAdaptor *adaptor) + { ++ //qDebug() << "registering an adaptor: " << QString(path); + if (path.isEmpty() || d->adaptors.contains(path)) { + return false; + } + + d->adaptors[path] = adaptor; ++ return true; + } + + bool Server::unregisterAdaptor(const QByteArray &path) +@@ -68,11 +71,16 @@ + return d->adaptors.take(path)!=0; + } + ++void Server::sendMessage(int descriptor, const Message &message) ++{ ++ d->serverThread->sendMessage(descriptor, message); ++} ++ + void ServerPrivate::messageReceived(int descriptor, const Message &message) + { + if (adaptors.contains(message.resourcePath())) { +- Message reply = adaptors[message.resourcePath()]->relay(q, message); +- serverThread->sendMessage(descriptor, reply); ++ adaptors[message.resourcePath()]->relay(q, descriptor, message); ++ //serverThread->sendMessage(descriptor, reply); + } else { + qWarning() << "Got a message for an unregistered object:" + << message.operationName() +Index: sodephelpers_p.h +=================================================================== +--- sodephelpers_p.h (revision 985276) ++++ sodephelpers_p.h (working copy) +@@ -193,7 +193,7 @@ + io.read(data, length); + data[length] = '\0'; + +- QByteArray result(data); ++ QByteArray result(data, length); + delete[] data; + + return result; +Index: abstractadaptor.h +=================================================================== +--- abstractadaptor.h (revision 985276) ++++ abstractadaptor.h (working copy) +@@ -40,7 +40,7 @@ + + + private: +- virtual Message relay(Server *server, const Message &message) = 0; ++ virtual void relay(Server *server, int descriptor, const Message &message) = 0; + + friend class ServerPrivate; + +Index: QtJolie.prf.cmake +=================================================================== +--- QtJolie.prf.cmake (revision 985276) ++++ QtJolie.prf.cmake (working copy) +@@ -5,9 +5,9 @@ + INCLUDEPATH += $$QTJOLIE_INCDIR + LIBS += -L$$QTJOLIE_LIBDIR + +-LINKAGE = -llibQtJolie ++LINKAGE = -lQtJolie + CONFIG(debug, debug|release) { +- windows:LINKAGE = -llibQtJolied +- mac:LINKAGE = -llibQtJolie_debug ++ windows:LINKAGE = -lQtJolied ++ mac:LINKAGE = -lQtJolie_debug + } + LIBS += $$LINKAGE +Index: QtJolie.pc.cmake +=================================================================== +--- QtJolie.pc.cmake (revision 985276) ++++ QtJolie.pc.cmake (working copy) +@@ -7,5 +7,5 @@ + Description: A QtDbus like API for JOLIE + Version: 1.0.0 + Requires: QtCore +-Libs: -L${libdir} -llibQtJolie ++Libs: -L${libdir} -lQtJolie + Cflags: -I${includedir} +Index: server.h +=================================================================== +--- server.h (revision 985276) ++++ server.h (working copy) +@@ -47,6 +47,7 @@ + + bool registerAdaptor(const QByteArray &path, AbstractAdaptor *adaptor); + bool unregisterAdaptor(const QByteArray &path); ++ void sendMessage(int descriptor, const Message &message); + + private: + friend class ServerPrivate; diff --git a/private/remotedataengine.cpp b/private/remotedataengine.cpp new file mode 100644 index 000000000..d0428b256 --- /dev/null +++ b/private/remotedataengine.cpp @@ -0,0 +1,185 @@ +/* + * Copyright © 2009 Rob Scheepmaker + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "remotedataengine.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Plasma +{ + +RemoteDataEngine::RemoteDataEngine(KUrl location, QObject* parent, const QVariantList& args) + : Plasma::DataEngine(parent, args), + m_service(0), + m_callInProgress(true), + m_location(location), + m_uuid("") +{ + if (!location.isEmpty()) { + setLocation(location); + } else { + kDebug() << "LOCATION IS EMPTY"; + } +} + +RemoteDataEngine::~RemoteDataEngine() +{ +} + +void RemoteDataEngine::setLocation(KUrl location) +{ + m_location = location; + setMinimumPollingInterval(1000); + setPollingInterval(5000); + m_uuid = QUuid::createUuid(); + Service *service = Service::access(location); + connect(service, SIGNAL(serviceReady(Plasma::Service*)), + this, SLOT(serviceReady(Plasma::Service*))); +} + +Plasma::Service* RemoteDataEngine::serviceForSource(const QString& source) +{ + if (m_serviceForSource.contains(source)) { + return m_serviceForSource[source]; + } else { + RemoteService *service = new RemoteService(this); + m_serviceForSource[source] = service; + KConfigGroup op = m_service->operationDescription("ServiceForSource"); + op.writeEntry("SourceName", source); + m_service->startOperationCall(op); + return service; + } +} + +void RemoteDataEngine::init() +{ +} + +void RemoteDataEngine::serviceReady(Plasma::Service *service) +{ + m_service = service; + KConfigGroup op = m_service->operationDescription("GetSourceNames"); + m_service->startOperationCall(op); + connect(m_service, SIGNAL(finished(Plasma::ServiceJob*)), + this, SLOT(remoteCallFinished(Plasma::ServiceJob*))); + QTimer *timer = new QTimer(this); + timer->setInterval(5000); + connect(timer, SIGNAL(timeout()), this, SLOT(updateSources())); + timer->start(); + m_callInProgress = false; +} + +QStringList RemoteDataEngine::sources() const +{ + return m_sources; +} + +void RemoteDataEngine::remoteCallFinished(Plasma::ServiceJob *job) +{ + if (job->operationName() == "GetSourceNames") { + kDebug() << "get source names"; + QStringList oldsources = m_sources; + m_sources = job->result().toStringList(); + + //first check if there are sources that have to be removed: + foreach (const QString &source, oldsources) { + if (!m_sources.contains(source)) { + kDebug() << "source no longer exists... remove that data."; + removeAllData(source); + } + } + + //are there sources that have to be added? + foreach (const QString &source, m_sources) { + if (!oldsources.contains(source)) { + kDebug() << "new source = " << source; + setData(source, DataEngine::Data()); + } + } + } else if (job->operationName() == "GetSource") { + QString source = job->parameters().value("SourceName").toString(); + kDebug() << "setting data for " << source; + if (m_sources.contains(source)) { + if (job->result().type() == QVariant::Bool && job->result().toBool() == false) { + kDebug() << "there is no update"; + } else { + setData(source, + static_cast(job->result().toHash())); + } + } + } else { + QString source = job->parameters().value("SourceName").toString(); + kDebug() << "setting serviceForSource for " << source; + QString resource = job->result().toString(); + KUrl loc = m_location; + loc.setFileName(resource); + if (m_serviceForSource.contains(source)) { + m_serviceForSource[source]->setLocation(loc); + } else { + kDebug() << "no such service?"; + } + } +} + +bool RemoteDataEngine::updateSourceEvent(const QString &source) +{ + if (m_callInProgress) { + return false; + } + KConfigGroup op = m_service->operationDescription("GetSource"); + op.writeEntry("SourceName", source); + op.writeEntry("UUID", m_uuid); + m_service->startOperationCall(op); + return false; +} + +bool RemoteDataEngine::sourceRequestEvent(const QString &source) +{ + if (m_callInProgress) { + return false; + } + + KConfigGroup op = m_service->operationDescription("GetSource"); + op.writeEntry("SourceName", source); + op.writeEntry("UUID", m_uuid); + m_service->startOperationCall(op); + return false; +} + +void RemoteDataEngine::updateSources() +{ + if (m_callInProgress) { + return; + } + if (m_service) { + KConfigGroup op = m_service->operationDescription("GetSourceNames"); + m_service->startOperationCall(op); + } +} + +} + +#include "remotedataengine.moc" + diff --git a/private/remotedataengine.h b/private/remotedataengine.h new file mode 100644 index 000000000..821a7bfac --- /dev/null +++ b/private/remotedataengine.h @@ -0,0 +1,67 @@ +/* + * Copyright © 2008 Rob Scheepmaker + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef REMOTEDATAENGINE_H +#define REMOTEDATAENGINE_H + +#include +#include + +class JobView; + +namespace Plasma +{ + class Service; + class ServiceAccessJob; + +class RemoteDataEngine : public Plasma::DataEngine +{ + Q_OBJECT + +public: + RemoteDataEngine(KUrl location, QObject* parent = 0, const QVariantList &args = QVariantList()); + ~RemoteDataEngine(); + Plasma::Service* serviceForSource(const QString& source); + void setLocation(KUrl location); + + //Plasma::Service* serviceForSource(const QString& source); + +protected: + void init(); + QStringList sources() const; + bool updateSourceEvent(const QString &source); + bool sourceRequestEvent(const QString &source); + +private Q_SLOTS: + void serviceReady(Plasma::Service *service); + void remoteCallFinished(Plasma::ServiceJob *job); + void updateSources(); + +private: + Service *m_service; + QStringList m_sources; + bool m_callInProgress; + QMap m_serviceForSource; + KUrl m_location; + QString m_uuid; + +}; + +} // namespace Plasma + +#endif diff --git a/private/remoteservice.cpp b/private/remoteservice.cpp index 4cd31a947..9544aaafb 100644 --- a/private/remoteservice.cpp +++ b/private/remoteservice.cpp @@ -16,37 +16,262 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef REMOTESERVICE_H -#define REMOTESERVICE_H +#include "remoteservice_p.h" +#include "joliemessagehelper_p.h" + +#include +#include +#include +#include +#include + +#include "authorizationmanager_p.h" +#include "remoteservicejob_p.h" +#include "service_p.h" + +#include +#include +#include +#include #include +#include +#include +#include +#include +#include -#include "remoteservice_p.h" -#include "remoteservicejob_p.h" +#include +#include namespace Plasma { -RemoteService::RemoteService(QObject* parent, KUrl location) - : m_location(location), - m_client(Jolie::Client(location->host(), location->port())) +RemoteService::RemoteService(QObject* parent) + : Service(parent), + m_client(0), + m_ready(false), + m_busy(false) { - Jolie::Message getOpDesc(location->path(), "getOperationNames"); - //TODO: async - Jolie::Message response = m_client->call(AccessManager::self()->signMessage(getOpDesc)); - QBuffer buffer(response.data().toByteArray()); - buffer.open(QBuffer::ReadWrite); - setOperationsScheme(&buffer); } -RemoteService::ServiceJob* createJob(const QString& operation, +RemoteService::RemoteService(QObject* parent, KUrl location) + : Service(parent), + m_location(location), + m_client(0), + m_ready(false), + m_busy(false) +{ + if (AuthorizationManager::self()->d->myCredentials.isValid()) { + setLocation(location); + } else { + connect(AuthorizationManager::self(), SIGNAL(readyForRemoteAccess()), + this, SLOT(slotReadyForRemoteAccess())); + } +} + +RemoteService::~RemoteService() +{ + delete m_client; +} + +void RemoteService::slotReadyForRemoteAccess() +{ + kDebug() << "AuthorizationManager is now ready for remote access!"; + setLocation(m_location); +} + +void RemoteService::setLocation(const KUrl &location) +{ + kDebug() << "Setting RemoteService location to " << location.prettyUrl(); + + m_uuid = QUuid::createUuid().toString(); + Credentials identity = AuthorizationManager::self()->d->myCredentials; + if (!identity.canSign()) { + kDebug() << "we can't sign? how did we get here?"; + return; + } + + if (m_client && (m_location != location)) { + delete m_client; + m_client = new Jolie::Client(location.host(), location.port()); + } + + if (!m_client) { + m_client = new Jolie::Client(location.host(), location.port()); + } + + m_location = location; + + QByteArray identityByteArray; + QDataStream stream(&identityByteArray, QIODevice::WriteOnly); + stream << identity.toPublicCredentials(); + + Jolie::Message getOpDesc(location.path(KUrl::RemoveTrailingSlash).remove(0, 1).toUtf8(), + "startConnection"); + Jolie::Value data; + data.children(Message::Field::IDENTITY) << Jolie::Value(identityByteArray); + data.children(Message::Field::UUID) << Jolie::Value(m_uuid.toAscii()); + getOpDesc.setData(data); + + Jolie::PendingCall pendingReply = m_client->asyncCall(getOpDesc); + Jolie::PendingCallWatcher *watcher = new Jolie::PendingCallWatcher(pendingReply, this); + connect(watcher, SIGNAL(finished(Jolie::PendingCallWatcher*)), + this, SLOT(callCompleted(Jolie::PendingCallWatcher*))); +} + +QString RemoteService::location() const +{ + return m_location.prettyUrl(); +} + +void RemoteService::callCompleted(Jolie::PendingCallWatcher *watcher) +{ + Jolie::PendingReply reply = *watcher; + Jolie::Message response = reply.reply(); + + if (response.operationName() == "startConnection") { + kDebug() << "Started connection: fetching .operations"; + m_token = Message::field(Message::Field::TOKEN, response); + Jolie::Message getOpDesc(m_location.path(KUrl::RemoveTrailingSlash).remove(0, 1).toUtf8(), + "getOperations"); + //TODO: async + Jolie::PendingCall pendingReply = m_client->asyncCall(signMessage(getOpDesc)); + Jolie::PendingCallWatcher *watcher = new Jolie::PendingCallWatcher(pendingReply, this); + connect(watcher, SIGNAL(finished(Jolie::PendingCallWatcher*)), + this, SLOT(callCompleted(Jolie::PendingCallWatcher*))); + } else if (response.operationName() == "getOperations") { + if (response.fault().name() == Message::Error::REQUIREPIN) { + kDebug() << "pin required, request auth interface"; + ClientPinRequest *request = new ClientPinRequest(this); + connect(request, SIGNAL(changed(Plasma::ClientPinRequest*)), + this, SLOT(slotGotPin(Plasma::ClientPinRequest*))); + AuthorizationManager::self()->d->authorizationInterface->clientPinRequest(*request); + } else { + kDebug() << "RemoteService is now ready for use!"; + m_operationsScheme = Message::field(Message::Field::OPERATIONSDESCRIPTION, response); + m_token = Message::field(Message::Field::TOKEN, response); + m_ready = true; + setName(m_location.prettyUrl()); + } + } else if (response.operationName() == "getEnabledOperations") { + //TODO: optimize. + m_token = Message::field(Message::Field::TOKEN, response); + QByteArray enabledOperations = Message::field(Message::Field::ENABLEDOPERATIONS, response); + QDataStream in(&enabledOperations, QIODevice::ReadOnly); + QStringList enabledOperationsList; + in >> enabledOperationsList; + + foreach (const QString &operation, operationNames()) { + if (enabledOperationsList.contains(operation) && !isOperationEnabled(operation)) { + kDebug() << "yeah, we're enabling the operation with the name " << operation; + setOperationEnabled(operation, true); + } else if (!enabledOperationsList.contains(operation) && isOperationEnabled(operation)) { + kDebug() << "we're disabling the operation with the name " << operation; + setOperationEnabled(operation, false); + } + } + + //if there's stuff in the queue, let it continue. + m_busy = false; + slotFinished(); + } else { + kDebug() << "How did we end up here?"; + } +} + +void RemoteService::slotGotPin(Plasma::ClientPinRequest *request) +{ + Jolie::Message getOpDesc(m_location.path(KUrl::RemoveTrailingSlash).remove(0, 1).toUtf8(), + "getOperations"); + Jolie::Value value; + value.children(Message::Field::PARAMETERS) << Jolie::Value(QByteArray()); + if (!request->pin().isEmpty()) { + value.children(Message::Field::PIN) << Jolie::Value(request->pin().toAscii()); + } + getOpDesc.setData(value); + //TODO: async + Jolie::PendingCall pendingReply = m_client->asyncCall(signMessage(getOpDesc)); + Jolie::PendingCallWatcher *watcher = new Jolie::PendingCallWatcher(pendingReply, this); + connect(watcher, SIGNAL(finished(Jolie::PendingCallWatcher*)), + this, SLOT(callCompleted(Jolie::PendingCallWatcher*))); +} + +void RemoteService::registerOperationsScheme() +{ + QBuffer buffer(&m_operationsScheme); + buffer.open(QBuffer::ReadWrite); + setOperationsScheme(&buffer); + QTimer *timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(slotUpdateEnabledOperations())); + //FIXME: get some sensible interval depending on the connection speed. This is kind of stupid. + timer->start(2000); +} + +void RemoteService::slotUpdateEnabledOperations() +{ + //TODO: maybe push the get enabled operations also on the queue? + if (!m_busy) { + m_busy = true; + Jolie::Message getOpDesc(m_location.path(KUrl::RemoveTrailingSlash).remove(0, 1).toUtf8(), + "getEnabledOperations"); + + Jolie::PendingCall pendingReply = m_client->asyncCall(signMessage(getOpDesc)); + Jolie::PendingCallWatcher *watcher = new Jolie::PendingCallWatcher(pendingReply, this); + connect(watcher, SIGNAL(finished(Jolie::PendingCallWatcher*)), + this, SLOT(callCompleted(Jolie::PendingCallWatcher*))); + } else { + kDebug() << "We would like to update enabled operations, but are still busy so let's wait for now."; + } +} + +ServiceJob* RemoteService::createJob(const QString& operation, QMap& parameters) { - return new RemoteServiceJob(m_location, operation, parameters, parent()); + if (m_ready) { + ServiceJob *job = new RemoteServiceJob(m_location, destination(), + operation, parameters, m_token, this); + connect(job, SIGNAL(finished(KJob *)), this, SLOT(slotFinished())); + return job; + } else { + kWarning() << "We're not yet ready, so we're starting a NullServiceJob."; + kWarning() << "This means some plasmoid doesn't check for the serviceReady signal, which it should."; + return new NullServiceJob(destination(), operation, this); + } +} + +void RemoteService::slotFinished() +{ + if (m_queue.isEmpty()) { + return; + } + + kDebug() << "Job finished, there are still service jobs in queue, starting next in queue."; + ServiceJob *job = m_queue.dequeue(); + QTimer::singleShot(0, job, SLOT(slotStart())); +} + +Jolie::Message RemoteService::signMessage(const Jolie::Message &message) const +{ + Jolie::Message response(message); + + Credentials identity = AuthorizationManager::self()->d->myCredentials; + if (!identity.isValid()) { + kDebug() << "We don't have our identity yet, just drop this message"; + return response; + } + + Jolie::Value data = response.data(); + data.children(Message::Field::IDENTITYID) << Jolie::Value(identity.id().toAscii()); + data.children(Message::Field::TOKEN) << Jolie::Value(m_token); + data.children(Message::Field::UUID) << Jolie::Value(m_uuid.toAscii()); + response.setData(data); + data.children(Message::Field::SIGNATURE) << + Jolie::Value(identity.signMessage(Message::payload(response))); + response.setData(data); + return response; } } //namespace Plasma #include "remoteservice_p.moc" - -#endif // REMOTESERVICE_H diff --git a/private/remoteservice_p.h b/private/remoteservice_p.h index c4b784fe7..57f6336b7 100644 --- a/private/remoteservice_p.h +++ b/private/remoteservice_p.h @@ -16,27 +16,65 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef REMOTESERVICE_H -#define REMOTESERVICE_H +#ifndef PLASMA_REMOTESERVICE_H +#define PLASMA_REMOTESERVICE_H -#include "../service.h" +#include +#include + +#include + +namespace Jolie +{ + class Client; + class PendingCallWatcher; +} namespace Plasma { +class ClientPinRequest; +class RemoteServiceJob; + class RemoteService : public Plasma::Service { Q_OBJECT public: + RemoteService(QObject* parent); RemoteService(QObject* parent, KUrl location); + ~RemoteService(); + + void setLocation(const KUrl &location); + QString location() const; protected: ServiceJob* createJob(const QString& operation, QMap& parameters); + void registerOperationsScheme(); + + private Q_SLOTS: + void callCompleted(Jolie::PendingCallWatcher *watcher); + void slotFinished(); + void slotGotPin(Plasma::ClientPinRequest *request); + void slotUpdateEnabledOperations(); + void slotReadyForRemoteAccess(); private: - KUrl m_location; + Jolie::Message signMessage(const Jolie::Message &message) const; + + private: + KUrl m_location; + Jolie::Client *m_client; + QByteArray m_token; + QByteArray m_operationsScheme; + bool m_ready; + QQueue m_queue; + bool m_busy; + QString m_pin; + QString m_uuid; + + friend class RemoteServiceJob; }; diff --git a/private/remoteservicejob.cpp b/private/remoteservicejob.cpp index 35aa1f5a4..8010d1421 100644 --- a/private/remoteservicejob.cpp +++ b/private/remoteservicejob.cpp @@ -16,43 +16,111 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "remoteservicejob_p.h" + #include +#include #include +#include +#include +#include #include "../servicejob.h" +#include "../accessmanager.h" +#include "../authorizationmanager.h" +#include "authorizationmanager_p.h" +#include "remoteservice_p.h" +#include "joliemessagehelper_p.h" +#include namespace Plasma { RemoteServiceJob::RemoteServiceJob(KUrl location, + const QString& destination, const QString& operation, QMap& parameters, - QObject* parent = 0); - : ServiceJob(location, operation, parameters, parent), - m_location(location) + QByteArray initialToken, + RemoteService* parent) + : ServiceJob(destination, operation, parameters, parent), + m_token(initialToken), + m_location(location), + m_service(parent) { } void RemoteServiceJob::start() { - Jolie::Client client(location.host(), location.port()); - Jolie::Message message(location.path(), "startOperation"); - Jolie::Message response = client.call(AccessManager::self()->signMessage(message)); + QTimer::singleShot(30000, this, SLOT(timeout())); + + Jolie::Client *client = m_service->m_client; + + if (m_service->m_busy) { + //enqueue and wait + m_service->m_queue.enqueue(this); + kDebug() << "already busy... enqueue, queue contains " << m_service->m_queue.count(); + return; + } else { + m_service->m_busy = true; + } + + //serialize the parameters + QByteArray params; + QBuffer buffer(¶ms); + buffer.open(QIODevice::WriteOnly); + QDataStream out(&buffer); + out << parameters(); + + Jolie::Message message(m_location.path(KUrl::RemoveTrailingSlash).remove(0, 1).toUtf8(), + "startOperationCall"); + Jolie::Value data; + data.children(Message::Field::OPERATION) << (Jolie::Value(operationName().toAscii())); + data.children(Message::Field::PARAMETERS) << Jolie::Value(params); + data.children(Message::Field::DESTINATION) << Jolie::Value(destination().toAscii()); + message.setData(data); + + Jolie::PendingCall pendingReply = client->asyncCall(m_service->signMessage(message)); + Jolie::PendingCallWatcher *watcher = new Jolie::PendingCallWatcher(pendingReply, this); + connect(watcher, SIGNAL(finished(Jolie::PendingCallWatcher*)), + this, SLOT(callCompleted(Jolie::PendingCallWatcher*))); +} + +void RemoteServiceJob::callCompleted(Jolie::PendingCallWatcher *watcher) +{ + m_service->m_busy = false; + + Jolie::PendingReply reply = *watcher; + Jolie::Message response = reply.reply(); + //TODO:async if (response.fault().isValid()) { - setErrorText(response.fault().data().toByteArray()); + kDebug() << "fault: " << response.fault().name(); + setError(-1); + setErrorText(Message::errorMessage(response.fault().name())); + emitResult(); return; } - if (response.data().isDouble()) { - setResult(response.data().toDouble()); - } else if (response.data().isInt()) { - setResult(response.data().toInt()); - } else { - setResult(respoonse.data().toByteArray()); - } + + m_service->m_token = Message::field(Message::Field::TOKEN, response); + + QVariant variantResult; + QByteArray byteArrayResult = Message::field(Message::Field::RESULT, response); + QBuffer buffer(&byteArrayResult); + buffer.open(QIODevice::ReadOnly); + QDataStream in(&buffer); + in >> variantResult; + + setResult(variantResult); +} + +void RemoteServiceJob::timeout() +{ + m_service->m_busy = false; + kDebug() << "Service job timed out."; + setError(-1); + setErrorText(i18n("Timeout.")); + emitResult(); } } // namespace Plasma - -#endif //REMOTESERVICEJOB_H diff --git a/private/remoteservicejob_p.h b/private/remoteservicejob_p.h index 618096201..8c8d365ed 100644 --- a/private/remoteservicejob_p.h +++ b/private/remoteservicejob_p.h @@ -16,30 +16,46 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef REMOTESERVICEJOB_H -#define REMOTESERVICEJOB_H +#ifndef PLASMA_REMOTESERVICEJOB_H +#define PLASMA_REMOTESERVICEJOB_H +#include #include #include "../servicejob.h" +namespace Jolie +{ + class PendingCallWatcher; +} + namespace Plasma { +class RemoteService; + class RemoteServiceJob : public Plasma::ServiceJob { Q_OBJECT public: RemoteServiceJob(KUrl location, + const QString& destination, const QString& operation, QMap& parameters, - QObject* parent = 0); + QByteArray initialToken, + RemoteService *parent); void start(); + private Q_SLOTS: + void callCompleted(Jolie::PendingCallWatcher *watcher); + void timeout(); + private: + QByteArray m_token; KUrl m_location; + RemoteService *m_service; }; } // namespace Plasma diff --git a/private/service_p.h b/private/service_p.h index 8145cbe5e..70714af46 100644 --- a/private/service_p.h +++ b/private/service_p.h @@ -21,20 +21,27 @@ #define SERVICE_P_H #include "servicejob.h" +#include "service.h" #include +#include #include #include #include #include +#include +#include + #include "plasma/configloader.h" +#include "accessmanager_p.h" namespace Plasma { class ConfigLoader; +class ServiceProvider; class NullServiceJob : public ServiceJob { @@ -74,7 +81,9 @@ public: : q(service), config(0), dummyConfig(0), - tempFile(0) + tempFile(0), + publicService(0), + serviceProvider(0) { } @@ -85,41 +94,30 @@ public: delete tempFile; } - void jobFinished(KJob *job) - { - emit q->finished(static_cast(job)); - } + void jobFinished(KJob *job); - void associatedWidgetDestroyed(QObject *obj) - { - associatedWidgets.remove(static_cast(obj)); - } + void associatedWidgetDestroyed(QObject *obj); - void associatedGraphicsWidgetDestroyed(QObject *obj) - { - associatedGraphicsWidgets.remove(static_cast(obj)); - } + void associatedGraphicsWidgetDestroyed(QObject *obj); - KConfigGroup dummyGroup() - { - if (!dummyConfig) { - if (!tempFile) { - tempFile = new KTemporaryFile; - tempFile->open(); - } + void publish(AnnouncementMethods methods, const QString &name, + PackageMetadata metadata = PackageMetadata()); - dummyConfig = new KConfig(tempFile->fileName()); - } + void unpublish(); - return KConfigGroup(dummyConfig, "DummyGroup"); - } + bool isPublished() const; + + KConfigGroup dummyGroup(); Service *q; QString destination; QString name; + QString resourcename; ConfigLoader *config; KConfig *dummyConfig; KTemporaryFile *tempFile; + DNSSD::PublicService *publicService; + ServiceProvider *serviceProvider; QMultiHash associatedWidgets; QMultiHash associatedGraphicsWidgets; QSet disabledOperations; diff --git a/private/servicejob_p.h b/private/servicejob_p.h new file mode 100644 index 000000000..c5b067500 --- /dev/null +++ b/private/servicejob_p.h @@ -0,0 +1,47 @@ +/* + * Copyright © 2009 Rob Scheepmaker + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include +#include +#include + +namespace Plasma +{ + +class ServiceJobPrivate +{ +public: + ServiceJobPrivate(ServiceJob *owner, + const QString &dest, + const QString &op, + const QMap ¶ms); + + void slotStart(); + + ServiceJob *q; + QString destination; + QString operation; + QMap parameters; + QVariant result; + Credentials identity; +}; + +} \ No newline at end of file diff --git a/private/serviceprovider.cpp b/private/serviceprovider.cpp index ceeea5eba..7d0df5089 100644 --- a/private/serviceprovider.cpp +++ b/private/serviceprovider.cpp @@ -16,92 +16,412 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef REMOTESERVICE_H -#define REMOTESERVICE_H - #include "serviceprovider_p.h" +#include "authorizationrule_p.h" +#include "authorizationmanager_p.h" +#include "joliemessagehelper_p.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include + namespace Plasma { -ServiceProvider::ServiceProvider(Service *service) - : m_service(service) +ServiceProvider::ServiceProvider(const QString &name, Service *service) + : Jolie::AbstractAdaptor(service), + m_service(service) { - //we need some resource name and a redirect should be added under that name. the actual chosen - //resource name (a number might be appended by jolie to avoid conflicts), should probably be made - //available through a resourceName() function by the jolie adaptor, or maybe just a KUrl url() - //since that would be convenient when wanting to announce services on the network through - //zeroconf, and the resource name is easily obtained from there as well. - setResourceName(service->name()); - connect(AccessManager::self(), - SIGNAL(authorizationSuccesful(Plasma::Service *service, Jolie::Message)), - this, SLOT(messageAuthorized(Plasma::Service *service, Jolie::Message))); + connect(service, SIGNAL(finished(Plasma::ServiceJob *)), + this, SLOT(operationCompleted(Plasma::ServiceJob*))); + + m_providerName = name; + AuthorizationManager::self()->d->server->registerAdaptor(m_providerName.toUtf8(), this); + kDebug() << "registered service provider " << m_providerName; } -ServiceProvider::messageReceived(Jolie::Message message) +ServiceProvider::~ServiceProvider() { - //authorization occurs by checking the value of two children that are added to every - //message that get's sent by RemoteService (the client side of ServiceProvider): "host" - //(full hostname or ip) and "signature" (a digital signature made by encrypting a hash - //of the entire sodep message and verified by obtaining the public key from a PublicKeyService - //running at the computer sending this message. obviously this authorization needs to be - //async. - AccessManager::self()->authorize(this, message); + AuthorizationManager::self()->d->server->unregisterAdaptor(m_providerName.toUtf8()); } -ServiceProvider::sendOperationNames(Jolie::Message message) +void ServiceProvider::startOperationCall(Jolie::Message message) { - Jolie::Message response(resourceName(), message->operationName(), message->id()); - foreach (const QString &operationName, m_service->operationNames()) { - response.children("operationNames") << Jolie::Value(operationName); + kDebug() << "starting operation call"; + + KConfigGroup description = + m_service->operationDescription(QString(Message::field(Message::Field::OPERATION, message))); + + //deserialize the parameters + QByteArray parametersByteArray; + parametersByteArray = Message::field(Message::Field::PARAMETERS, message); + kDebug() << "parameters byte array: " << parametersByteArray.toBase64(); + QBuffer buffer(¶metersByteArray); + buffer.open(QIODevice::ReadOnly); + QDataStream in(&buffer); + QMap parameters; + in >> parameters; + + if (!description.isValid()) { + kDebug() << "invalid description."; } - sendMessage(response); + + kDebug() << "====PARAMETERS===="; + + //write the parameters into the operation description + foreach (const QString &key, parameters.keys()) { + kDebug() << "key = " << key << ", value = " << parameters.value(key); + description.writeEntry(key, parameters.value(key)); + } + + m_service->setDestination(Message::field(Message::Field::DESTINATION, message)); + ServiceJob *job = m_service->startOperationCall(description); + QString identityID = Message::field(Message::Field::IDENTITYID, message); + job->d->identity = AuthorizationManager::self()->d->getCredentials(identityID); + kDebug() << "adding into messagemap:" << ((QObject*)job); + m_messageMap[job] = message; } -ServiceProvider::sendOperationDescription(Jolie::Message message) +void ServiceProvider::sendOperations(Jolie::Message message) { - QByteArray operationDescription = //serialize the operationDescription KConfigGroup. Hmm, reading the KConfigGroup apidox this seems rather ugly. It looks like it can only be done by using a KSharedConfig to write to a temporary file, and read that. Let's hope I'm wrong :p - Jolie::Message response(resourceName(), message->operationName(), message->id()); - response.setData(Jolie::Value(operationDescription)); - sendMessage(response); + kDebug() << "send operations."; + //kDebug() << printJolieMessage(message); + Jolie::Message response(message.resourcePath(), message.operationName(), message.id()); + + //FIXME: this is duplicated from Plasma::Service + QString path = KStandardDirs::locate("data", "plasma/services/" + m_service->name() + +".operations"); + + if (path.isEmpty()) { + kDebug() << "Cannot find operations description:" << m_service->name() << ".operations"; + response.setFault(Jolie::Fault("NoOperationsDescription")); + } else { + kDebug() << "file = " << path; + QFile file(path); + file.open(QIODevice::ReadOnly); + Jolie::Value value; + value.children(Message::Field::OPERATIONSDESCRIPTION) << Jolie::Value(file.readAll()); + file.close(); + response.setData(value); + } + + QByteArray id = Message::field(Message::Field::IDENTITYID, message); + QByteArray uuid = Message::field(Message::Field::UUID, message); + response = appendToken(response, id, uuid); + kDebug() << "caller = " << id.toBase64(); + + //hack around the not yet async service adaptor api in qtjolie + if (m_descriptorMap.contains(id + uuid)) { + kDebug() << "descriptor found, sending message"; + AuthorizationManager::self()->d->server->sendMessage( + m_descriptorMap.value(id + uuid), response); + } else { + kDebug() << "no valid entry in descriptormap."; + } } -ServiceProvider::startOperationCall(Jolie::Message message) +void ServiceProvider::sendEnabledOperations(Jolie::Message message) { - KConfigGroup description = //deserialize the KConfigGroup - m_service->startOperationCall(description); - //map finished signal through signalmapper to include the message, and connect to - //operationCompleted slot. + kDebug() << "send enabled operations."; + Jolie::Message response(message.resourcePath(), message.operationName(), message.id()); + + QStringList enabledOperationsList; + foreach (const QString &operation, m_service->operationNames()) { + if (m_service->isOperationEnabled(operation)) { + enabledOperationsList << operation; + } + } + + kDebug() << "enabled operations: " << enabledOperationsList; + + QByteArray enabledOperationsArray; + QDataStream out(&enabledOperationsArray, QIODevice::WriteOnly); + out << enabledOperationsList; + + Jolie::Value value; + value.children(Message::Field::ENABLEDOPERATIONS) << Jolie::Value(enabledOperationsArray); + response.setData(value); + + QByteArray id = Message::field(Message::Field::IDENTITYID, message); + QByteArray uuid = Message::field(Message::Field::UUID, message); + response = appendToken(response, id, uuid); + kDebug() << "caller = " << id.toBase64(); + + //hack around the not yet async service adaptor api in qtjolie + if (m_descriptorMap.contains(id + uuid)) { + kDebug() << "descriptor found, sending message"; + AuthorizationManager::self()->d->server->sendMessage( + m_descriptorMap.value(id + uuid), response); + } else { + kDebug() << "no valid entry in descriptormap."; + } } -ServiceProvider::messageAuthorized(Plasma::Service *service, Jolie::Message message) +QString ServiceProvider::resourceName() const { - if (service != this) { + return m_providerName; +} + +void ServiceProvider::relay(Jolie::Server *server, int descriptor, + const Jolie::Message &message) +{ + Q_UNUSED(server) + + if (message.operationName() == "startConnection") { + kDebug() << "reset token"; + //add the identity + Credentials identity; + QByteArray identityByteArray = Message::field(Message::Field::IDENTITY, message); + QDataStream stream(&identityByteArray, QIODevice::ReadOnly); + stream >> identity; + AuthorizationManager::self()->d->addCredentials(identity); + + Jolie::Message response(message.resourcePath(), message.operationName(), message.id()); + QByteArray uuid = Message::field(Message::Field::UUID, message); + response = appendToken(response, identity.id().toAscii(), uuid); + AuthorizationManager::self()->d->server->sendMessage(descriptor, response); + + return; + } + + if (Message::field(Message::Field::TOKEN, message).isEmpty()) { + Jolie::Message response(message.resourcePath(), message.operationName(), message.id()); + response.setFault(Jolie::Fault(Message::Error::INVALIDTOKEN)); + AuthorizationManager::self()->d->server->sendMessage(descriptor, response); + return; + } + + //m_descriptor = descriptor; + QByteArray id = Message::field(Message::Field::IDENTITYID, message); + QByteArray uuid = Message::field(Message::Field::UUID, message); + m_descriptorMap[id + uuid] = descriptor; + authorize(message, m_tokens[id + uuid]); +} + +void ServiceProvider::operationCompleted(Plasma::ServiceJob *job) +{ + kDebug() << "operation completed."; + if (!m_messageMap.contains(job)) { + kDebug() << "service not in map!"; return; } - //would be lovely if this kind of stuff could be autogenerated code from xml like in dbus adaptors - if (message.operationName() == "getOperationNames") { - sendOperationNames(message); - } else if (message.operationName() == "getOperationDescription") { - sendOperationDescription(message); + kDebug() << "found message in message map!"; + + Jolie::Message message = m_messageMap.take(job); + Jolie::Message response(message.resourcePath(), message.operationName(), message.id()); + + QVariant variantResult = job->result(); + kDebug() << "got a result: " << variantResult; + QByteArray byteArrayResult; + QBuffer buffer(&byteArrayResult); + buffer.open(QIODevice::WriteOnly); + QDataStream out(&buffer); + out << variantResult; + + Jolie::Value data; + data.children(Message::Field::RESULT) << Jolie::Value(byteArrayResult); + response.setData(data); + if (job->error()) { + response.setFault(Jolie::Fault(job->errorString().toAscii())); + } + + QByteArray id = Message::field(Message::Field::IDENTITYID, message); + QByteArray uuid = Message::field(Message::Field::UUID, message); + response = appendToken(response, id, uuid); + + //hack around the not yet async service adaptor api in qtjolie + if (m_descriptorMap.contains(id + uuid)) { + kDebug() << "descriptor found, sending message"; + AuthorizationManager::self()->d->server->sendMessage( + m_descriptorMap.value(id + uuid), response); + } else { + kDebug() << "no valid entry in descriptormap."; + } +} + +void ServiceProvider::ruleChanged(Plasma::AuthorizationRule *rule) +{ + int i = 0; + foreach (Jolie::Message message, m_messagesPendingAuthorization) { + QByteArray id = Message::field(Message::Field::IDENTITYID, message); + //Credentials identity = AuthorizationManager::self()->d->getCredentials(id); + + bool matches = rule->d->matches(message.resourcePath(), id); + if (matches && rule->policy() == AuthorizationRule::PinRequired && + Message::field(Message::Field::PIN, message) != rule->pin()) { + kDebug() << "we need a pin"; + authorizationFailed(message, Message::Error::REQUIREPIN); + m_messagesPendingAuthorization.removeAt(i); + return; + } else if (matches && rule->policy() == AuthorizationRule::PinRequired) { + kDebug() << "AUTHORIZATION: Service is freely accessable for verified caller."; + rule->setPolicy(AuthorizationRule::Allow); + authorizationSuccess(message); + //TODO: it might be nicer to do a removeAll once Jolie::Message implements == + m_messagesPendingAuthorization.removeAt(i); + return; + } else if (matches && rule->policy() == AuthorizationRule::Allow) { + kDebug() << "AUTHORIZATION: Service is freely accessable for verified caller."; + authorizationSuccess(message); + //TODO: it might be nicer to do a removeAll once Jolie::Message implements == + m_messagesPendingAuthorization.removeAt(i); + return; + } else if (matches && rule->policy() == AuthorizationRule::Deny) { + kDebug() << "AUTHORIZATION: Service is never accessable for verified caller."; + authorizationFailed(message, Message::Error::ACCESSDENIED); + m_messagesPendingAuthorization.removeAt(i); + return; + } else { + i++; + } + } +} + +Jolie::Message ServiceProvider::appendToken(Jolie::Message message, + const QByteArray &caller, + const QByteArray &uuid) +{ + m_tokens[caller + uuid] = QCA::Random::randomArray(256).toByteArray(); + //kDebug() << "setting token: " << m_tokens[caller + uuid].toBase64() + //<< " for caller: " << caller.toBase64() + //<< " with uuid caller: " << uuid.toBase64(); + + Jolie::Value data = message.data(); + data.children(Message::Field::TOKEN) << Jolie::Value(m_tokens[caller + uuid]); + message.setData(data); + return message; +} + + +void ServiceProvider::authorize(const Jolie::Message &message, const QByteArray &validToken) +{ + kDebug() << "VALIDATING MESSAGE:"; + //kDebug() << Message::print(message); + + //Authorization step 1: is the service accessable to all callers? In that case we can skip the + //verification of the signature + kDebug() << "STEP1"; + AuthorizationRule *rule = + AuthorizationManager::self()->d->matchingRule(message.resourcePath(), Credentials()); + + if (rule && rule->policy() == AuthorizationRule::Allow) { + kDebug() << "AUTHORIZATION: Service is freely accessable."; + authorizationSuccess(message); + return; + } else if (rule && rule->policy() == AuthorizationRule::Deny) { + kDebug() << "AUTHORIZATION: Service is never accessable."; + authorizationFailed(message, Message::Error::ACCESSDENIED); + return; + } + + //Authorization step 2: see if the token matches. If it doesn't we can't safely identify the + //caller and are finished. + kDebug() << "STEP2"; + if (Message::field(Message::Field::TOKEN, message) != validToken && !validToken.isEmpty()) { + kDebug() << "AUTHORIZATION: Message token doesn't match."; + kDebug() << "expected: " << validToken.toBase64(); + authorizationFailed(message, Message::Error::INVALIDTOKEN); + return; + } + + QByteArray payload = Message::payload(message); + QByteArray signature = Message::field(Message::Field::SIGNATURE, message); + Credentials identity = AuthorizationManager::self()->d->getCredentials( + Message::field(Message::Field::IDENTITYID, message)); + + if (!identity.isValid()) { + kDebug() << "no identity"; + authorizationFailed(message, Message::Error::INVALIDTOKEN); + return; + } + + kDebug() << "STEP3"; + //Authorization step 3: see if we have the key and can validate the signature. If we can't, + //either the public key has changed, or somebody is doing something nasty, and we're finished. + if ((!identity.isValidSignature(signature, payload))) { + kDebug() << "AUTHORIZATION: signature invalid."; + authorizationFailed(message, Message::Error::ACCESSDENIED); + return; + } + + kDebug() << "STEP4"; + //Authorization step 4: if we have a valid signature, see if we've got a matching rule + rule = AuthorizationManager::self()->d->matchingRule(message.resourcePath(), identity); + if (rule && rule->policy() == AuthorizationRule::PinRequired) { + kDebug() << "we expect a pin!"; + QByteArray pin = Message::field(Message::Field::PIN, message); + if (rule->pin() == QString(pin)) { + authorizationSuccess(message); + rule->setPolicy(AuthorizationRule::Allow); + } else { + authorizationFailed(message, Message::Error::ACCESSDENIED); + AuthorizationManager::self()->d->rules.removeAll(rule); + delete rule; + } + } else if (rule && rule->policy() == AuthorizationRule::Allow) { + kDebug() << "AUTHORIZATION: Service is freely accessable for validated sender."; + authorizationSuccess(message); + return; + } else if (rule && rule->policy() == AuthorizationRule::Deny) { + kDebug() << "AUTHORIZATION: Service is not accessable for validated sender."; + authorizationFailed(message, Message::Error::ACCESSDENIED); + return; + } else { + //- let the shell set the rule matching this request: + kDebug() << "STEP6"; + kDebug() << "leave it up to the authorization interface"; + m_messagesPendingAuthorization << message; + AuthorizationRule *newRule = + new AuthorizationRule(QString(message.resourcePath()), identity.id()); + connect(newRule, SIGNAL(changed(Plasma::AuthorizationRule*)), this, + SLOT(ruleChanged(Plasma::AuthorizationRule*))); + AuthorizationManager::self()->d->rules.append(newRule); + AuthorizationManager::self()->d->authorizationInterface->authorizationRequest(*newRule); + } +} + +void ServiceProvider::authorizationSuccess(const Jolie::Message &message) +{ + kDebug() << "message with operationName " << message.operationName() << " allowed!"; + + //would be lovely if this kind of stuff could be autogenerated code from xml like in dbus + //adaptors + if (message.operationName() == "getOperations") { + sendOperations(message); + } else if (message.operationName() == "getEnabledOperations") { + sendEnabledOperations(message); } else if (message.operationName() == "startOperationCall") { startOperationCall(message); } } -ServiceProvider::operationCompleted(Plasma::ServiceJob *job, Jolie::Message message) +void ServiceProvider::authorizationFailed(const Jolie::Message &message, const QByteArray &error) { - Jolie::Message response(resourceName(), message->operationName(), message->id()); - response.setData(Jolie::Value(job->reply())); //convert first to one of the 3 supported sodep message types. double or int as values, serialize the variant otherwise - if (Jolie::Value(job->error())) { - reponse.children("error") << Jolie::Value(job->error()); - } - sendMessage(response); + kDebug() << "message with operationName " << message.operationName() << " NOT allowed!"; + Jolie::Message response(message.resourcePath(), message.operationName(), message.id()); + response.setFault(Jolie::Fault(error)); + + QByteArray id = Message::field(Message::Field::IDENTITYID, message); + QByteArray uuid = Message::field(Message::Field::UUID, message); + AuthorizationManager::self()->d->server->sendMessage( + m_descriptorMap.value(id + uuid), response); + return; } } //namespace Plasma #include "serviceprovider_p.moc" - -#endif //SERVICEPROVIDER_H diff --git a/private/serviceprovider_p.h b/private/serviceprovider_p.h index a388ee09e..4961ea4f0 100644 --- a/private/serviceprovider_p.h +++ b/private/serviceprovider_p.h @@ -19,27 +19,56 @@ #ifndef SERVICEPROVIDER_H #define SERVICEPROVIDER_H +#include + +#include +#include + +class QSignalMapper; + namespace Plasma { +class AuthorizationRule; class Service; +class ServiceJob; -class ServiceProvider : public Jolie::Interface +class ServiceProvider : public Jolie::AbstractAdaptor { Q_OBJECT public: - ServiceProvider(Service *service); + ServiceProvider(const QString &name, Service *service); + ~ServiceProvider(); + + void startOperationCall(Jolie::Message message); + void sendOperations(Jolie::Message message); + void sendEnabledOperations(Jolie::Message message); + QString resourceName() const; protected: - messageReceived(Jolie::Message message); + void relay(Jolie::Server *server, int descriptor, const Jolie::Message &message); + + private Q_SLOTS: + void operationCompleted(Plasma::ServiceJob *job); + void ruleChanged(Plasma::AuthorizationRule *rule); private: - void sendOperationNames(); - void sendOperationDescription(const QString &operationName); - void startOperationCall(const QString &destination, const QByteArray &description) + Jolie::Message appendToken(Jolie::Message message, const QByteArray &caller, + const QByteArray &uuid); + void authorize(const Jolie::Message &message, const QByteArray &validToken); + void authorizationSuccess(const Jolie::Message &message); + void authorizationFailed(const Jolie::Message &message, const QByteArray &error); + + Service *m_service; + int m_descriptor; + QString m_providerName; + + QMap m_messageMap; + QMap m_tokens; + QMap m_descriptorMap; + QList m_messagesPendingAuthorization; - Service *m_service; }; } //namespace Plasma diff --git a/private/trustedonlyauthorization.cpp b/private/trustedonlyauthorization.cpp new file mode 100644 index 000000000..47c2f1e33 --- /dev/null +++ b/private/trustedonlyauthorization.cpp @@ -0,0 +1,55 @@ +/* + * Copyright 2009 by Rob Scheepmaker + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "trustedonlyauthorization.h" + +#include "authorizationrule.h" +#include "pinpairingdialog.h" + +#include +#include + + +namespace Plasma +{ + +TrustedOnlyAuthorization::TrustedOnlyAuthorization() +{ +} + +TrustedOnlyAuthorization::~TrustedOnlyAuthorization() +{ + //TODO: cleanup +} + +void TrustedOnlyAuthorization::clientPinRequest(ClientPinRequest &request) +{ + new PinPairingDialog(request); +} + +void TrustedOnlyAuthorization::authorizationRequest(AuthorizationRule &rule) +{ + if (rule.credentials().trustLevel() > TrustedCredentials) { + rule.setPolicy(AuthorizationRule::Allow); + rule.setTargets(AuthorizationRule::AllServices); + } +} + +} // Plasma namespace + diff --git a/private/trustedonlyauthorization.h b/private/trustedonlyauthorization.h new file mode 100644 index 000000000..bb400966f --- /dev/null +++ b/private/trustedonlyauthorization.h @@ -0,0 +1,42 @@ +/* + * Copyright 2009 by Rob Scheepmaker + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef PLASMA_TRUSTEDONLYAUTHORIZATION_H +#define PLASMA_TRUSTEDONLYAUTHORIZATION_H + +#include "plasma_export.h" +#include "authorizationinterface.h" + +#include + +namespace Plasma +{ + +class PLASMA_EXPORT TrustedOnlyAuthorization : public AuthorizationInterface +{ + public: + TrustedOnlyAuthorization(); + ~TrustedOnlyAuthorization(); + virtual void authorizationRequest(AuthorizationRule &rule); + virtual void clientPinRequest(ClientPinRequest &request); +}; +} // Plasma namespace + +#endif + diff --git a/publickeyservice.operations b/publickeyservice.operations new file mode 100644 index 000000000..78f662b08 --- /dev/null +++ b/publickeyservice.operations @@ -0,0 +1,6 @@ + + + + + diff --git a/service.cpp b/service.cpp index f23e26ed5..1199de73d 100644 --- a/service.cpp +++ b/service.cpp @@ -18,7 +18,9 @@ */ #include "service.h" +#include "private/remoteservice_p.h" #include "private/service_p.h" +#include "private/serviceprovider_p.h" #include #include @@ -29,10 +31,14 @@ #include #include #include +#include +#include #include "configloader.h" #include "version.h" #include "private/configloader_p.h" +//#include "widgets/widget.h.template" +//#include "packagemetadata.h" namespace Plasma { @@ -52,6 +58,7 @@ Service::Service(QObject *parent, const QVariantList &args) Service::~Service() { + d->unpublish(); delete d; } @@ -92,6 +99,89 @@ Service *Service::load(const QString &name, QObject *parent) return service; } +Service *Service::access(const KUrl &url, QObject *parent) +{ + return new RemoteService(parent, url); +} + +void ServicePrivate::jobFinished(KJob *job) + { + emit q->finished(static_cast(job)); + } + + void ServicePrivate::associatedWidgetDestroyed(QObject *obj) + { + associatedWidgets.remove(static_cast(obj)); + } + + void ServicePrivate::associatedGraphicsWidgetDestroyed(QObject *obj) + { + associatedGraphicsWidgets.remove(static_cast(obj)); + } + + void ServicePrivate::publish(AnnouncementMethods methods, const QString &name, PackageMetadata metadata) + { + if (!serviceProvider) { + serviceProvider = new ServiceProvider(name, q); + + if (methods.testFlag(ZeroconfAnnouncement) && + (DNSSD::ServiceBrowser::isAvailable() == DNSSD::ServiceBrowser::Working)) { + //TODO: dynamically pick a free port number. + publicService = new DNSSD::PublicService(name, "_plasma._tcp", 4000); + + QMap textData; + textData["name"] = name.toUtf8(); + textData["plasmoidname"] = metadata.name().toUtf8(); + textData["description"] = metadata.description().toUtf8(); + publicService->setTextData(textData); + kDebug() << "about to publish"; + + publicService->publishAsync(); + } else if (methods.testFlag(ZeroconfAnnouncement) && + (DNSSD::ServiceBrowser::isAvailable() != DNSSD::ServiceBrowser::Working)) { + kDebug() << "sorry, but your zeroconf daemon doesn't seem to be running."; + } + } else { + kDebug() << "already published!"; + } + } + + void ServicePrivate::unpublish() + { + if (serviceProvider) { + delete serviceProvider; + serviceProvider = 0; + } + + if (publicService) { + delete publicService; + publicService = 0; + } + } + + bool ServicePrivate::isPublished() const + { + if (serviceProvider) { + return true; + } else { + return false; + } + } + + KConfigGroup ServicePrivate::dummyGroup() + { + if (!dummyConfig) { + if (!tempFile) { + tempFile = new KTemporaryFile; + tempFile->open(); + } + + dummyConfig = new KConfig(tempFile->fileName()); + } + + return KConfigGroup(dummyConfig, "DummyGroup"); + } + void Service::setDestination(const QString &destination) { d->destination = destination; @@ -216,6 +306,8 @@ void Service::setName(const QString &name) d->dummyConfig = 0; registerOperationsScheme(); + + emit serviceReady(this); } void Service::setOperationEnabled(const QString &operation, bool enable) diff --git a/service.h b/service.h index e7cc853bc..7bb91bf65 100644 --- a/service.h +++ b/service.h @@ -27,6 +27,8 @@ #include #include +#include +#include "packagemetadata.h" class QGraphicsWidget; class QIODevice; @@ -75,6 +77,7 @@ class ServicePrivate; class PLASMA_EXPORT Service : public QObject { Q_OBJECT + Q_DECLARE_PRIVATE(Service) public: /** * Destructor @@ -91,6 +94,12 @@ public: */ static Service *load(const QString &name, QObject *parent = 0); + /** + * Used to access a service from an url. Always check for the signal serviceReady() that fires + * when this service is actually ready for use. + */ + static Service *access(const KUrl &url, QObject *parent = 0); + /** * Sets the destination for this Service to operate on * @@ -196,6 +205,11 @@ Q_SIGNALS: */ void operationsChanged(); + /** + * Emitted when this service is ready for use + */ + void serviceReady(Plasma::Service *service); + protected: /** * Default constructor @@ -256,7 +270,11 @@ private: ServicePrivate * const d; - friend class ServicePrivate; + friend class Applet; + friend class DataEnginePrivate; + friend class GetSource; + friend class PackagePrivate; + friend class ServiceProvider; }; } // namespace Plasma diff --git a/serviceaccessjob.cpp b/serviceaccessjob.cpp index 5499a3c68..1169db66c 100644 --- a/serviceaccessjob.cpp +++ b/serviceaccessjob.cpp @@ -18,6 +18,7 @@ */ #include "serviceaccessjob.h" +#include "private/remoteservice_p.h" namespace Plasma { @@ -25,8 +26,9 @@ namespace Plasma class ServiceAccessJobPrivate { public: - ServiceAccessJobPrivate(ServiceJob *owner, KUrl location) + ServiceAccessJobPrivate(ServiceAccessJob *owner, KUrl location) : q(owner), + service(0), location(location) { } @@ -36,7 +38,13 @@ public: q->start(); } + void slotServiceReady() + { + q->emitResult(); + } + ServiceAccessJob *q; + Service *service; KUrl location; }; @@ -53,15 +61,16 @@ ServiceAccessJob::~ServiceAccessJob() Service *ServiceAccessJob::service() const { - return d->destination; + return d->service; } void ServiceAccessJob::start() { - //TODO: implement + d->service = new RemoteService(parent(), d->location); + connect(d->service, SIGNAL(ready()), this, SLOT(slotServiceReady())); } } // namespace Plasma -#include "servicejob.moc" +#include "serviceaccessjob.moc" diff --git a/serviceaccessjob.h b/serviceaccessjob.h index 4f2ea9894..0225f77f6 100644 --- a/serviceaccessjob.h +++ b/serviceaccessjob.h @@ -1,5 +1,5 @@ /* - * Copyright 2009 Rob Scheepmaker + * Copyright 2009 Rob Scheepmaker -#include +#include "service.h" #include @@ -44,7 +44,7 @@ class PLASMA_EXPORT ServiceAccessJob : public KJob Q_OBJECT public: - ~ServiceJob(); + ~ServiceAccessJob(); Service *service() const; @@ -55,12 +55,19 @@ protected: * @arg location the location of the service * @arg parent the parent object for this service */ - ServiceJob(KUrl location, QObject *parent = 0); + ServiceAccessJob(KUrl location, QObject *parent = 0); + + void start(); private: Q_PRIVATE_SLOT(d, void slotStart()) + Q_PRIVATE_SLOT(d, void slotServiceReady()) ServiceAccessJobPrivate * const d; + + friend class AccessManager; + friend class AccessManagerPrivate; + friend class ServiceAccessJobPrivate; }; } // namespace Plasma diff --git a/servicejob.cpp b/servicejob.cpp index f85a1be66..debb5b7a0 100644 --- a/servicejob.cpp +++ b/servicejob.cpp @@ -18,35 +18,24 @@ */ #include "servicejob.h" +#include namespace Plasma { -class ServiceJobPrivate -{ -public: - ServiceJobPrivate(ServiceJob *owner, - const QString &dest, - const QString &op, - const QMap ¶ms) +ServiceJobPrivate::ServiceJobPrivate(ServiceJob *owner, const QString &dest, + const QString &op, const QMap ¶ms) : q(owner), destination(dest), operation(op), parameters(params) - { - } +{ +} - void slotStart() - { - q->start(); - } - - ServiceJob *q; - QString destination; - QString operation; - QMap parameters; - QVariant result; -}; +void ServiceJobPrivate::slotStart() +{ + q->start(); +} ServiceJob::ServiceJob(const QString &destination, const QString &operation, const QMap ¶meters, QObject *parent) @@ -75,6 +64,11 @@ QMap ServiceJob::parameters() const return d->parameters; } +Credentials ServiceJob::identity() const +{ + return d->identity; +} + QVariant ServiceJob::result() const { return d->result; diff --git a/servicejob.h b/servicejob.h index e17c83bb8..268b0cfd2 100644 --- a/servicejob.h +++ b/servicejob.h @@ -26,6 +26,7 @@ #include #include +#include "credentials.h" namespace Plasma { @@ -86,6 +87,11 @@ public: */ QMap parameters() const; + /** + * @return the identity of the caller of this operation + */ + Credentials identity() const; + /** * Returns the result of the operation * @@ -115,6 +121,8 @@ private: Q_PRIVATE_SLOT(d, void slotStart()) ServiceJobPrivate * const d; + + friend class ServiceProvider; }; } // namespace Plasma diff --git a/widgets/webview.cpp b/widgets/webview.cpp index 9f8f6ea1f..1cb972ff7 100644 --- a/widgets/webview.cpp +++ b/widgets/webview.cpp @@ -32,6 +32,7 @@ #include #include +#include #include #include "plasma/widgets/webview.h"