diff --git a/CMakeLists.txt b/CMakeLists.txt index eecdbd71a..f2c2b9f32 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR}) add_subdirectory(kded) add_subdirectory(libkdeconnect) add_subdirectory(kcm) -#add_subdirectory(kioslave) +add_subdirectory(kio) add_subdirectory(plasmoid) add_subdirectory(tests) diff --git a/kded/plugins/clipboard/clipboardplugin.cpp b/kded/plugins/clipboard/clipboardplugin.cpp index 40000ebdb..7e99bd0f7 100644 --- a/kded/plugins/clipboard/clipboardplugin.cpp +++ b/kded/plugins/clipboard/clipboardplugin.cpp @@ -21,7 +21,6 @@ #include "clipboardplugin.h" #include -#include #include K_PLUGIN_FACTORY( KdeConnectPluginFactory, registerPlugin< ClipboardPlugin >(); ) diff --git a/kded/plugins/sftp/CMakeLists.txt b/kded/plugins/sftp/CMakeLists.txt index eaf942e06..4c1ac46da 100644 --- a/kded/plugins/sftp/CMakeLists.txt +++ b/kded/plugins/sftp/CMakeLists.txt @@ -27,6 +27,7 @@ target_link_libraries(kdeconnect_sftp ${KDE4_KDECORE_LIBS} ${KDE4_KDEUI_LIBS} ${KDE4_KIO_LIBS} + ${KDE4_KFILE_LIBS} ${QT_QTNETWORK_LIBRARY} ${QJSON_LIBRARIES} ${QCA2_LIBRARIES} diff --git a/kded/plugins/sftp/sftpplugin.cpp b/kded/plugins/sftp/sftpplugin.cpp index 3cb979240..5691e1bd2 100644 --- a/kded/plugins/sftp/sftpplugin.cpp +++ b/kded/plugins/sftp/sftpplugin.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include "sftp_config.h" #include "../../kdebugnamespace.h" @@ -43,10 +44,7 @@ K_EXPORT_PLUGIN( KdeConnectPluginFactory("kdeconnect_sftp", "kdeconnect_sftp") ) static const char* passwd_c = "sftppassword"; static const char* mountpoint_c = "sftpmountpoint"; static const char* timestamp_c = "timestamp"; - -static const QSet fields_c = QSet() << - "ip" << "port" << "user" << "port" << "password" << "path"; - +static const QSet fields_c = QSet() << "ip" << "port" << "user" << "port" << "password" << "path"; inline bool isTimeout(QObject* o, const KConfigGroup& cfg) { @@ -54,11 +52,6 @@ inline bool isTimeout(QObject* o, const KConfigGroup& cfg) return cfg.readEntry("idle", true) && duration > (cfg.readEntry("idletimeout", 60) * 60); } -inline QString mountpoint(QObject* o) -{ - return o->property(mountpoint_c).toString(); -} - struct SftpPlugin::Pimpl { Pimpl() : waitForMount(false) @@ -67,6 +60,7 @@ struct SftpPlugin::Pimpl }; QPointer mountProc; + KFilePlacesModel* m_placesModel; QTimer mountTimer; int idleTimer; bool waitForMount; @@ -81,16 +75,41 @@ SftpPlugin::SftpPlugin(QObject *parent, const QVariantList &args) m_d->idleTimer = startTimer(20 * 1000); connect(&m_d->mountTimer, SIGNAL(timeout()), this, SLOT(mountTimeout())); + + //Add KIO entry to Dolphin's Places + m_d->m_placesModel = new KFilePlacesModel(); + addToDolphin(); + +} + +void SftpPlugin::addToDolphin() +{ + removeFromDolphin(); + KUrl kioUrl("kdeconnect://"+device()->id()+"/"); + m_d->m_placesModel->addPlace(device()->name(), kioUrl, "smartphone"); + kDebug(kdeconnect_kded()) << "add to dolphin"; +} + +void SftpPlugin::removeFromDolphin() +{ + KUrl kioUrl("kdeconnect://"+device()->id()+"/"); + QModelIndex index = m_d->m_placesModel->closestItem(kioUrl); + while (index.row() != -1) { + m_d->m_placesModel->removePlace(index); + index = m_d->m_placesModel->closestItem(kioUrl); + } } void SftpPlugin::connected() { + } SftpPlugin::~SftpPlugin() { QDBusConnection::sessionBus().unregisterObject(dbusPath(), QDBusConnection::UnregisterTree); umount(); + removeFromDolphin(); } void SftpPlugin::mount() @@ -113,7 +132,7 @@ void SftpPlugin::umount() { if (m_d->mountProc) { - cleanMountPoint(m_d->mountProc); + cleanMountPoint(); if (m_d->mountProc) { m_d->mountProc->terminate(); @@ -127,7 +146,7 @@ void SftpPlugin::startBrowsing() { if (m_d->mountProc) { - new KRun(KUrl::fromLocalFile(mountpoint(m_d->mountProc)), 0); + new KRun(KUrl::fromLocalFile(mountPoint()), 0); } else { @@ -159,8 +178,7 @@ bool SftpPlugin::receivePackage(const NetworkPackage& np) connect(m_d->mountProc, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(onFinished(int,QProcess::ExitStatus))); connect(m_d->mountProc, SIGNAL(finished(int,QProcess::ExitStatus)), m_d->mountProc, SLOT(deleteLater())); - const QString mpoint = KConfig("kdeconnect/plugins/sftp").group("main").readEntry("mountpoint" - , KStandardDirs::locateLocal("appdata", "", true, componentData())) + "/" + device()->name() + "/"; + const QString mpoint = mountPoint(); QDir().mkpath(mpoint); const QString program = "sshfs"; @@ -177,14 +195,20 @@ bool SftpPlugin::receivePackage(const NetworkPackage& np) m_d->mountProc->setProgram(program, arguments); m_d->mountProc->setProperty(passwd_c, np.get("password")); - m_d->mountProc->setProperty(mountpoint_c, mpoint); - cleanMountPoint(m_d->mountProc); + cleanMountPoint(); m_d->mountProc->start(); return true; } +QString SftpPlugin::mountPoint() +{ + const QString defaultMountDir = KStandardDirs::locateLocal("appdata", "", true, componentData()); + const QString mountDir = KConfig("kdeconnect/plugins/sftp").group("main").readEntry("mountpoint", defaultMountDir); + return mountDir + "/" + device()->id() + "/"; +} + void SftpPlugin::timerEvent(QTimerEvent* event) { if (event->timerId() == m_d->idleTimer) @@ -206,14 +230,14 @@ void SftpPlugin::onStarted() m_d->mountProc->closeWriteChannel(); knotify(KNotification::Notification - , i18n("Filesystem mounted at %1").arg(mountpoint(sender())) + , i18n("Filesystem mounted at %1").arg(mountPoint()) , KIconLoader::global()->loadIcon("drive-removable-media", KIconLoader::Desktop) ); if (m_d->waitForMount) { m_d->waitForMount = false; - new KRun(KUrl::fromLocalFile(mountpoint(sender())), 0); + new KRun(KUrl::fromLocalFile(mountPoint()), 0); } } @@ -226,7 +250,7 @@ void SftpPlugin::onError(QProcess::ProcessError error) , i18n("Failed to start sshfs") , KIconLoader::global()->loadIcon("dialog-error", KIconLoader::Desktop) ); - cleanMountPoint(sender()); + cleanMountPoint(); } } @@ -259,7 +283,7 @@ void SftpPlugin::onFinished(int exitCode, QProcess::ExitStatus exitStatus) ); } - cleanMountPoint(sender()); + cleanMountPoint(); m_d->mountProc = 0; } @@ -270,16 +294,9 @@ void SftpPlugin::knotify(int type, const QString& text, const QPixmap& icon) con , KNotification::CloseOnTimeout); } -void SftpPlugin::cleanMountPoint(QObject* mounter) +void SftpPlugin::cleanMountPoint() { - if (!mounter || mountpoint(mounter).isEmpty()) - { - return; - } - - KProcess::execute(QStringList() - << "fusermount" << "-u" - << mountpoint(mounter), 10000); + KProcess::execute(QStringList() << "fusermount" << "-u" << mountPoint(), 10000); } void SftpPlugin::mountTimeout() diff --git a/kded/plugins/sftp/sftpplugin.h b/kded/plugins/sftp/sftpplugin.h index f5d3831f4..068b738bd 100644 --- a/kded/plugins/sftp/sftpplugin.h +++ b/kded/plugins/sftp/sftpplugin.h @@ -53,6 +53,8 @@ public Q_SLOTS: Q_SCRIPTABLE void startBrowsing(); + Q_SCRIPTABLE QString mountPoint(); + protected: void timerEvent(QTimerEvent *event); @@ -63,9 +65,11 @@ private Q_SLOTS: void mountTimeout(); private: - QString dbusPath() const { return "/modules/kdeconnect/devices/" + device()->id() + "/sftp"; } + QString dbusPath() const { return "/modules/kdeconnect/devices/" + device()->id() + "/sftp"; } void knotify(int type, const QString& text, const QPixmap& icon) const; - void cleanMountPoint(QObject* mounter); + void cleanMountPoint(); + void addToDolphin(); + void removeFromDolphin(); private: struct Pimpl; diff --git a/kio/CMakeLists.txt b/kio/CMakeLists.txt new file mode 100644 index 000000000..0d58ced5b --- /dev/null +++ b/kio/CMakeLists.txt @@ -0,0 +1,20 @@ +set(kio_kdeconnect_PART_SRCS + kiokdeconnect.cpp + kdebugnamespace.cpp) + +kde4_add_plugin(kio_kdeconnect ${kio_kdeconnect_PART_SRCS}) + +add_dependencies(kio_kdeconnect libkdeconnect) + +target_link_libraries(kio_kdeconnect + ${KDE4_KDECORE_LIBS} + ${KDE4_KIO_LIBRARY} + ${KDE4_KDEUI_LIBRARY} + ${QT_QTCORE_LIBRARY} + ${QT_QTGUI_LIBRARY} + kdeconnect +) + +########### install files ############### +install(TARGETS kio_kdeconnect DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES kdeconnect.protocol DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/kio/kdebugnamespace.cpp b/kio/kdebugnamespace.cpp new file mode 100644 index 000000000..a8c13ae98 --- /dev/null +++ b/kio/kdebugnamespace.cpp @@ -0,0 +1,26 @@ +/** + * Copyright 2013 Albert Vaca + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * 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 "kdebugnamespace.h" + +int kdeconnect_kio() { + static int s_area = KDebug::registerArea("kdeconnect_kio", true); + return s_area; +} diff --git a/kio/kdebugnamespace.h b/kio/kdebugnamespace.h new file mode 100644 index 000000000..9e536c0dd --- /dev/null +++ b/kio/kdebugnamespace.h @@ -0,0 +1,29 @@ +/** + * Copyright 2013 Albert Vaca + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * 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 KDEBUG_KDECONNECT_KCM_H +#define KDEBUG_KDECONNECT_KCM_H + +#include + +int kdeconnect_kio(); + +#endif + diff --git a/kio/kdeconnect.protocol b/kio/kdeconnect.protocol new file mode 100644 index 000000000..f03c3c2a4 --- /dev/null +++ b/kio/kdeconnect.protocol @@ -0,0 +1,16 @@ +[Protocol] +exec=kio_kdeconnect +protocol=kdeconnect +input=none +output=filesystem +copyToFile=false +copyFromFile=false +listing=Name,Type,Access +reading=true +writing=false +makedir=false +deleting=false +moving=false +Icon=smartphone +maxInstances=2 + diff --git a/kio/kiokdeconnect.cpp b/kio/kiokdeconnect.cpp new file mode 100644 index 000000000..ace10ba4b --- /dev/null +++ b/kio/kiokdeconnect.cpp @@ -0,0 +1,190 @@ +/** + * Copyright 2013 Albert Vaca + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * 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 "kiokdeconnect.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "kdebugnamespace.h" + +extern "C" int KDE_EXPORT kdemain(int argc, char **argv) +{ + KAboutData about("kiokdeconnect", "kdeconnect", ki18n("kiokdeconnect"), "1.0"); + KCmdLineArgs::init(&about); + + KApplication app; + + if (argc != 4) { + fprintf(stderr, "Usage: kio_kdeconnect protocol pool app\n"); + exit(-1); + } + + KioKdeconnect slave(argv[2], argv[3]); + slave.dispatchLoop(); + return 0; +} + +KioKdeconnect::KioKdeconnect(const QByteArray &pool, const QByteArray &app) + : SlaveBase("kdeconnect", pool, app), + m_dbusInterface(new DaemonDbusInterface(this)) +{ + +} + +void KioKdeconnect::listAllDevices() +{ + infoMessage(i18n("Listing devices...")); + + QStringList devices = m_dbusInterface->devices(true, true); //TODO: Change to all devices and show different icons for connected and disconnected? + + totalSize(devices.length()); + + int i = 0; + Q_FOREACH(const QString& deviceId, devices) { + + DeviceDbusInterface interface(deviceId); + + if (!interface.hasPlugin("kdeconnect_sftp")) continue; + + const QString target = QString("kdeconnect://").append(deviceId).append("/"); + const QString name = interface.name(); + const QString icon = "smartphone"; + + KIO::UDSEntry entry; + entry.insert(KIO::UDSEntry::UDS_NAME, name); + entry.insert(KIO::UDSEntry::UDS_ICON_NAME, icon); + entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR); + entry.insert(KIO::UDSEntry::UDS_ACCESS, S_IRUSR | S_IRGRP | S_IROTH); + entry.insert(KIO::UDSEntry::UDS_MIME_TYPE, ""); + entry.insert(KIO::UDSEntry::UDS_URL, target); + listEntry(entry, false); + + processedSize(i++); + + } + + listEntry(KIO::UDSEntry(), true); + infoMessage(""); + finished(); +} + +void KioKdeconnect::listDevice() +{ + infoMessage(i18n("Accessing device...")); + + 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(); + + KIO::UDSEntry entry; + entry.insert(KIO::UDSEntry::UDS_NAME, "files"); + entry.insert(KIO::UDSEntry::UDS_DISPLAY_NAME, "Browse images"); + entry.insert(KIO::UDSEntry::UDS_ICON_NAME, "folder"); + entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR); + entry.insert(KIO::UDSEntry::UDS_ACCESS, S_IRUSR | S_IRGRP | S_IROTH); + entry.insert(KIO::UDSEntry::UDS_MIME_TYPE, ""); + entry.insert(KIO::UDSEntry::UDS_URL, url + "/DCIM/Camera"); + listEntry(entry, false); + + entry.insert(KIO::UDSEntry::UDS_NAME, "files"); + entry.insert(KIO::UDSEntry::UDS_DISPLAY_NAME, "Browse all files"); + entry.insert(KIO::UDSEntry::UDS_ICON_NAME, "folder"); + entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR); + entry.insert(KIO::UDSEntry::UDS_ACCESS, S_IRUSR | S_IRGRP | S_IROTH); + entry.insert(KIO::UDSEntry::UDS_MIME_TYPE, ""); + entry.insert(KIO::UDSEntry::UDS_URL, url); + listEntry(entry, false); + + listEntry(KIO::UDSEntry(), true); + infoMessage(""); + finished(); + +} + + + +void KioKdeconnect::listDir(const KUrl &url) +{ + kDebug(kdeconnect_kio()) << "Listing..." << url; + + /// Url is not used here becuase all we could care about the url is the host, and that's already + /// handled in @p setHost + Q_UNUSED(url); + + if (!m_dbusInterface->isValid()) { + infoMessage(i18n("Could not contact background service.")); + listEntry(KIO::UDSEntry(), true); + finished(); + return; + } + + if (m_currentDevice.isEmpty()) { + listAllDevices(); + } else { + listDevice(); + } +} + +void KioKdeconnect::stat(const KUrl &url) +{ + kDebug(kdeconnect_kio()) << "Stat: " << url; + + KIO::UDSEntry entry; + entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR); + statEntry(entry); + + finished(); +} + +void KioKdeconnect::get(const KUrl &url) +{ + kDebug(kdeconnect_kio()) << "Get: " << url; + mimeType(""); + finished(); +} + +void KioKdeconnect::setHost(const QString &hostName, quint16 port, const QString &user, const QString &pass) +{ + + //This is called before everything else to set the file we want to show + + kDebug(kdeconnect_kio()) << "Setting host: " << hostName; + + // In this kio only the hostname is used + Q_UNUSED(port) + Q_UNUSED(user) + Q_UNUSED(pass) + + m_currentDevice = hostName; + +} + diff --git a/kio/kiokdeconnect.h b/kio/kiokdeconnect.h new file mode 100644 index 000000000..486bfc8a5 --- /dev/null +++ b/kio/kiokdeconnect.h @@ -0,0 +1,61 @@ +/** + * Copyright 2013 Albert Vaca + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * 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 KIOKDECONNECT_H +#define KIOKDECONNECT_H + +#include + +#include + +#include "../libkdeconnect/dbusinterfaces.h" + +class KioKdeconnect : public QObject, public KIO::SlaveBase +{ + Q_OBJECT + +public: + KioKdeconnect(const QByteArray &pool, const QByteArray &app); + + void get(const KUrl &url); + void listDir(const KUrl &url); + void stat(const KUrl &url); + + void setHost(const QString &constHostname, quint16 port, const QString &user, const QString &pass); + + void listAllDevices(); //List all devices exported by m_dbusInterface + void listDevice(); //List m_currentDevice + + +private: + + /** + * Contains the ID of the current device or is empty when no device is set. + */ + QString m_currentDevice; + + /** + * KDED DBus interface, used to communicate to the daemon since we need some status (like connected) + */ + DaemonDbusInterface *m_dbusInterface; + +}; + +#endif \ No newline at end of file