diff --git a/kded/plugins/sftp/sftpplugin.cpp b/kded/plugins/sftp/sftpplugin.cpp index 62bc09ee8..036b3e39d 100644 --- a/kded/plugins/sftp/sftpplugin.cpp +++ b/kded/plugins/sftp/sftpplugin.cpp @@ -20,10 +20,11 @@ #include "sftpplugin.h" -#include #include #include +#include + #include #include #include @@ -52,18 +53,40 @@ inline bool isTimeout(QObject* o, const KConfigGroup& cfg) return cfg.readEntry("idle", true) && duration > (cfg.readEntry("idletimeout", 60) * 60); } +MountLoop::MountLoop() + : QEventLoop() +{ +} + +bool MountLoop::exec(QEventLoop::ProcessEventsFlags flags) +{ + return QEventLoop::exec(flags) == 0; +} + +void MountLoop::failed() +{ + Q_EMIT(result(false)); + exit(1); +} + +void MountLoop::successed() +{ + Q_EMIT(result(true)); + exit(0); +} + +void MountLoop::exitWith(bool status) +{ + Q_EMIT(result(status)); + exit(status ? 0 : 1); +} + struct SftpPlugin::Pimpl { - Pimpl() : waitForMount(false) - { - mountTimer.setSingleShot(true); - }; - QPointer mountProc; KFilePlacesModel* m_placesModel; - QTimer mountTimer; int idleTimer; - bool waitForMount; + MountLoop loop; }; SftpPlugin::SftpPlugin(QObject *parent, const QVariantList &args) @@ -74,7 +97,8 @@ SftpPlugin::SftpPlugin(QObject *parent, const QVariantList &args) m_d->idleTimer = startTimer(20 * 1000); - connect(&m_d->mountTimer, SIGNAL(timeout()), this, SLOT(mountTimeout())); + connect(this, SIGNAL(mount_succesed()), &m_d->loop, SLOT(successed())); + connect(this, SIGNAL(mount_failed()), &m_d->loop, SLOT(failed())); //Add KIO entry to Dolphin's Places m_d->m_placesModel = new KFilePlacesModel(); @@ -119,20 +143,45 @@ void SftpPlugin::connected() void SftpPlugin::mount() { kDebug(kdeconnect_kded()) << "start mounting device:" << device()->name(); - if (m_d->mountTimer.isActive() || m_d->mountProc) + if (m_d->loop.isRunning() || m_d->mountProc) { return; } - else - { - m_d->mountTimer.start(10000); - } NetworkPackage np(PACKAGE_TYPE_SFTP); np.set("startBrowsing", true); device()->sendPackage(np); } +bool SftpPlugin::mountAndWait() +{ + kDebug(kdeconnect_kded()) << "start mounting device and block:" << device()->name(); + + if (m_d->mountProc && !m_d->loop.isRunning()) + { + return true; + } + + if (m_d->loop.isRunning()) + { + MountLoop loop; + connect(&m_d->loop, SIGNAL(result(bool)), &loop, SLOT(exitWith(bool))); + return loop.exec(); + } + + kDebug(kdeconnect_kded()) << "call mounting" << device()->name(); + + mount(); + + QTimer mt; + connect(&mt, SIGNAL(timeout()), &m_d->loop, SLOT(failed())); + connect(&mt, SIGNAL(timeout()), this, SLOT(mountTimeout())); + kDebug(kdeconnect_kded()) << "stargting timer"; + mt.start(15000); + return m_d->loop.exec(); +} + + void SftpPlugin::umount() { if (m_d->mountProc) @@ -149,15 +198,10 @@ void SftpPlugin::umount() void SftpPlugin::startBrowsing() { - if (m_d->mountProc) + if (mountAndWait()) { new KRun(KUrl::fromLocalFile(mountPoint()), 0); } - else - { - m_d->waitForMount = true; - mount(); - } } bool SftpPlugin::receivePackage(const NetworkPackage& np) @@ -173,8 +217,6 @@ bool SftpPlugin::receivePackage(const NetworkPackage& np) return true; } - m_d->mountTimer.stop(); - m_d->mountProc = new KProcess(this); m_d->mountProc->setOutputChannelMode(KProcess::SeparateChannels); @@ -237,14 +279,11 @@ void SftpPlugin::onStarted() , KIconLoader::global()->loadIcon("drive-removable-media", KIconLoader::Desktop) ); + //Used to notify MountLoop about success. + Q_EMIT mount_succesed(); + connect(m_d->mountProc, SIGNAL(readyReadStandardError()), this, SLOT(readProcessStderr())); connect(m_d->mountProc, SIGNAL(readyReadStandardOutput()), this, SLOT(readProcessStdout())); - - if (m_d->waitForMount) - { - m_d->waitForMount = false; - new KRun(KUrl::fromLocalFile(mountPoint()), 0); - } } void SftpPlugin::onError(QProcess::ProcessError error) @@ -294,6 +333,10 @@ void SftpPlugin::onFinished(int exitCode, QProcess::ExitStatus exitStatus) cleanMountPoint(); m_d->mountProc = 0; + + //Used to notify MountLoop about error. + //There is no loop running if mount was succesful! + Q_EMIT mount_failed(); } void SftpPlugin::knotify(int type, const QString& text, const QPixmap& icon) const @@ -310,6 +353,7 @@ void SftpPlugin::cleanMountPoint() void SftpPlugin::mountTimeout() { + kDebug(kdeconnect_kded()) << "loop.... TIMEOUT"; knotify(KNotification::Error , i18n("Failed to mount filesystem: device not responding") , KIconLoader::global()->loadIcon("dialog-error", KIconLoader::Desktop) @@ -328,6 +372,23 @@ void SftpPlugin::readProcessStdout() m_d->mountProc->readAllStandardOutput(); } +bool SftpPlugin::waitForMount() +{ + if (m_d->loop.isRunning()) + { + MountLoop loop; + connect(&m_d->loop, SIGNAL(result(bool)), &loop, SLOT(exitWith(bool))); + + kDebug(kdeconnect_kded()) << "start secondary loop..."; + bool ret = loop.exec(); + kDebug(kdeconnect_kded()) << "finish secondary loop...:" << ret; + return ret; + } + + return m_d->mountProc; +} + + // void SftpPlugin::startAgent() // { // m_d->agentProc = new KProcess(this); diff --git a/kded/plugins/sftp/sftpplugin.h b/kded/plugins/sftp/sftpplugin.h index 9947275b7..ddf4e8958 100644 --- a/kded/plugins/sftp/sftpplugin.h +++ b/kded/plugins/sftp/sftpplugin.h @@ -22,6 +22,7 @@ #define SFTPPLUGIN_H #include +#include #include "../kdeconnectplugin.h" @@ -29,6 +30,24 @@ class KNotification; +//TODO move to private +class MountLoop : public QEventLoop +{ + Q_OBJECT +public: + MountLoop(); + + bool exec(QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents); + +Q_SIGNALS: + void result(bool status); + +public Q_SLOTS: + void failed(); + void successed(); + void exitWith(bool status); +}; + class SftpPlugin : public KdeConnectPlugin { @@ -36,6 +55,7 @@ class SftpPlugin Q_CLASSINFO("D-Bus Interface", "org.kde.kdeconnect.device.sftp") public: + explicit SftpPlugin(QObject *parent, const QVariantList &args); virtual ~SftpPlugin(); @@ -43,6 +63,12 @@ public: { return KComponentData("kdeconnect", "kdeconnect"); } + +Q_SIGNALS: + + void mount_succesed(); //TODO make private - for internal use + void mount_failed(); //TODO make private -for internal use + public Q_SLOTS: virtual bool receivePackage(const NetworkPackage& np); @@ -50,11 +76,13 @@ public Q_SLOTS: Q_SCRIPTABLE void mount(); Q_SCRIPTABLE void umount(); + Q_SCRIPTABLE bool mountAndWait(); Q_SCRIPTABLE void startBrowsing(); Q_SCRIPTABLE QString mountPoint(); + protected: void timerEvent(QTimerEvent *event); @@ -67,6 +95,8 @@ private Q_SLOTS: void readProcessStderr(); void readProcessStdout(); + bool waitForMount(); + private: QString dbusPath() const { return "/modules/kdeconnect/devices/" + device()->id() + "/sftp"; } void knotify(int type, const QString& text, const QPixmap& icon) const; @@ -79,4 +109,5 @@ private: QScopedPointer m_d; }; + #endif diff --git a/kio/kiokdeconnect.cpp b/kio/kiokdeconnect.cpp index ace10ba4b..39f3f06c2 100644 --- a/kio/kiokdeconnect.cpp +++ b/kio/kiokdeconnect.cpp @@ -51,6 +51,36 @@ extern "C" int KDE_EXPORT kdemain(int argc, char **argv) return 0; } +//Some useful error mapping +KIO::Error toKioError(const QDBusError::ErrorType type) +{ + switch (type) + { + case QDBusError::NoError: + return KIO::Error(KJob::NoError); + case QDBusError::NoMemory: + return KIO::ERR_OUT_OF_MEMORY; + case QDBusError::Timeout: + return KIO::ERR_SERVER_TIMEOUT; + case QDBusError::TimedOut: + return KIO::ERR_SERVER_TIMEOUT; + default: + return KIO::ERR_INTERNAL; + }; +}; + +template +bool handleDBusError(QDBusReply& reply, KIO::SlaveBase* slave) +{ + if (!reply.isValid()) + { + kDebug(kdeconnect_kio()) << "Error in DBus request:" << reply.error(); + slave->error(toKioError(reply.error().type()),reply.error().message()); + return true; + } + return false; +} + KioKdeconnect::KioKdeconnect(const QByteArray &pool, const QByteArray &app) : SlaveBase("kdeconnect", pool, app), m_dbusInterface(new DaemonDbusInterface(this)) @@ -102,9 +132,29 @@ void KioKdeconnect::listDevice() kDebug(kdeconnect_kio()) << "ListDevice" << m_currentDevice; SftpDbusInterface interface(m_currentDevice); - interface.mount(); //Since this does not happen immediately, we mount it here - QString url = interface.mountPoint(); - + + QDBusReply mountreply = interface.mountAndWait(); + + if (handleDBusError(mountreply, this)) + { + return; + } + + if (!mountreply.value()) + { + error(KIO::ERR_COULD_NOT_MOUNT, i18n("Could not mount device filesystem")); + return; + } + + QDBusReply urlreply = interface.mountPoint(); + + if (handleDBusError(urlreply, this)) + { + return; + } + + QString url = urlreply.value(); + KIO::UDSEntry entry; entry.insert(KIO::UDSEntry::UDS_NAME, "files"); entry.insert(KIO::UDSEntry::UDS_DISPLAY_NAME, "Browse images");