diff --git a/core/backends/loopback/loopbackdevicelink.cpp b/core/backends/loopback/loopbackdevicelink.cpp index 718c5b8fd..ac174d4b1 100644 --- a/core/backends/loopback/loopbackdevicelink.cpp +++ b/core/backends/loopback/loopbackdevicelink.cpp @@ -46,6 +46,8 @@ bool LoopbackDeviceLink::sendPackageEncrypted(QCA::PublicKey& key, NetworkPackag //LoopbackDeviceLink does not need deviceTransferInfo if (input.hasPayload()) { + bool b = input.payload()->open(QIODevice::ReadOnly); + Q_ASSERT(b); output.setPayload(input.payload(), input.payloadSize()); } @@ -61,6 +63,8 @@ bool LoopbackDeviceLink::sendPackage(NetworkPackage& input) //LoopbackDeviceLink does not need deviceTransferInfo if (input.hasPayload()) { + bool b = input.payload()->open(QIODevice::ReadOnly); + Q_ASSERT(b); output.setPayload(input.payload(), input.payloadSize()); } diff --git a/core/daemon.cpp b/core/daemon.cpp index cb6999e12..1aa5ad69d 100644 --- a/core/daemon.cpp +++ b/core/daemon.cpp @@ -52,7 +52,7 @@ Daemon* Daemon::instance() return *s_instance; } -Daemon::Daemon(QObject *parent) +Daemon::Daemon(QObject *parent, bool testMode) : QObject(parent) , d(new DaemonPrivate) { @@ -61,8 +61,10 @@ Daemon::Daemon(QObject *parent) qCDebug(KDECONNECT_CORE) << "KdeConnect daemon starting"; //Load backends - d->mLinkProviders.insert(new LanLinkProvider()); - //d->mLinkProviders.insert(new LoopbackLinkProvider()); + if (testMode) + d->mLinkProviders.insert(new LoopbackLinkProvider()); + else + d->mLinkProviders.insert(new LanLinkProvider()); //Read remebered paired devices const QStringList& list = KdeConnectConfig::instance()->trustedDevices(); @@ -106,12 +108,12 @@ void Daemon::forceOnNetworkChange() } } -QStringList Daemon::devices(bool onlyReachable, bool onlyVisible) const +QStringList Daemon::devices(bool onlyReachable, bool onlyPaired) const { QStringList ret; Q_FOREACH(Device* device, d->mDevices) { if (onlyReachable && !device->isReachable()) continue; - if (onlyVisible && !device->isPaired()) continue; + if (onlyPaired && !device->isPaired()) continue; ret.append(device->id()); } return ret; @@ -182,6 +184,11 @@ QNetworkAccessManager* Daemon::networkAccessManager() return manager; } +QList Daemon::devicesList() const +{ + return d->mDevices.values(); +} + Daemon::~Daemon() { diff --git a/core/daemon.h b/core/daemon.h index d26316374..6da87e97d 100644 --- a/core/daemon.h +++ b/core/daemon.h @@ -39,7 +39,7 @@ class KDECONNECTCORE_EXPORT Daemon Q_CLASSINFO("D-Bus Interface", "org.kde.kdeconnect.daemon") public: - explicit Daemon(QObject *parent); + explicit Daemon(QObject *parent, bool testMode = false); ~Daemon(); public Q_SLOTS: @@ -55,16 +55,18 @@ public Q_SLOTS: Q_SCRIPTABLE void forceOnNetworkChange(); - Q_SCRIPTABLE QString announcedName(); - Q_SCRIPTABLE void setAnnouncedName(QString name); + QString announcedName(); + void setAnnouncedName(QString name); //Returns a list of ids. The respective devices can be manipulated using the dbus path: "/modules/kdeconnect/Devices/"+id - Q_SCRIPTABLE QStringList devices(bool onlyReachable = false, bool onlyVisible = false) const; + Q_SCRIPTABLE QStringList devices(bool onlyReachable = false, bool onlyPaired = false) const; virtual void requestPairing(Device *d) = 0; virtual void reportError(const QString &title, const QString &description) = 0; virtual QNetworkAccessManager* networkAccessManager(); + QList devicesList() const; + Q_SIGNALS: Q_SCRIPTABLE void deviceAdded(const QString& id); Q_SCRIPTABLE void deviceRemoved(const QString& id); //Note that paired devices will never be removed diff --git a/core/device.cpp b/core/device.cpp index d53b3c520..7305be608 100644 --- a/core/device.cpp +++ b/core/device.cpp @@ -522,3 +522,8 @@ void Device::setName(const QString &name) Q_EMIT nameChanged(name); } } + +KdeConnectPlugin* Device::plugin(const QString& pluginName) const +{ + return m_plugins[pluginName]; +} diff --git a/core/device.h b/core/device.h index 03f528cf5..bba396d78 100644 --- a/core/device.h +++ b/core/device.h @@ -102,6 +102,8 @@ public: Q_SCRIPTABLE QString pluginsConfigFile() const; + KdeConnectPlugin* plugin(const QString& plugin) const; + public Q_SLOTS: ///sends a @p np package to the device virtual bool sendPackage(NetworkPackage& np); diff --git a/core/filetransferjob.cpp b/core/filetransferjob.cpp index f503f6a30..f10f527d5 100644 --- a/core/filetransferjob.cpp +++ b/core/filetransferjob.cpp @@ -39,6 +39,7 @@ FileTransferJob::FileTransferJob(const QSharedPointer& origin, qint64 , mWritten(0) { Q_ASSERT(mOrigin); + Q_ASSERT(mOrigin->isReadable()); if (mDestination.scheme().isEmpty()) { qWarning() << "Destination QUrl" << mDestination << "lacks a scheme. Setting its scheme to 'file'."; mDestination.setScheme("file"); diff --git a/core/filetransferjob.h b/core/filetransferjob.h index 859a30321..1c5c3b88b 100644 --- a/core/filetransferjob.h +++ b/core/filetransferjob.h @@ -33,13 +33,15 @@ #include #include +#include "kdeconnectcore_export.h" + /** * @short It will stream a device into a url destination * * Given a QIODevice, the file transfer job will use the system's QNetworkAccessManager * for putting the stream into the requested location. */ -class FileTransferJob +class KDECONNECTCORE_EXPORT FileTransferJob : public KJob { Q_OBJECT diff --git a/plugins/share/shareplugin.cpp b/plugins/share/shareplugin.cpp index b4331b32a..4a925378f 100644 --- a/plugins/share/shareplugin.cpp +++ b/plugins/share/shareplugin.cpp @@ -129,7 +129,11 @@ bool SharePlugin::receivePackage(const NetworkPackage& np) void SharePlugin::finished(KJob* job) { - qCDebug(KDECONNECT_PLUGIN_SHARE) << "File transfer finished. Success:" << (!job->error()); + FileTransferJob* ftjob = qobject_cast(job); + if (ftjob) + fileReceived(ftjob->destination()); + + qCDebug(KDECONNECT_PLUGIN_SHARE) << "File transfer finished. Success:" << (!job->error()) << (ftjob ? ftjob->destination() : QUrl()); } void SharePlugin::openDestinationFolder() diff --git a/plugins/share/shareplugin.h b/plugins/share/shareplugin.h index de00693d1..615b86fd7 100644 --- a/plugins/share/shareplugin.h +++ b/plugins/share/shareplugin.h @@ -47,6 +47,9 @@ private Q_SLOTS: void finished(KJob*); void openDestinationFolder(); +Q_SIGNALS: + void fileReceived(const QUrl& url); + private: void shareUrl(const QUrl& url); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b00a574dc..42d1f4c9a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -13,5 +13,6 @@ set(kdeconnect_libraries qca-qt5 ) +ecm_add_test(sendfiletest.cpp LINK_LIBRARIES ${kdeconnect_libraries}) ecm_add_test(networkpackagetests.cpp LINK_LIBRARIES ${kdeconnect_libraries}) ecm_add_test(testsocketlinereader.cpp ../core/backends/lan/socketlinereader.cpp TEST_NAME testsocketlinereader LINK_LIBRARIES ${kdeconnect_libraries}) diff --git a/tests/sendfiletest.cpp b/tests/sendfiletest.cpp new file mode 100644 index 000000000..8e96c0b1e --- /dev/null +++ b/tests/sendfiletest.cpp @@ -0,0 +1,108 @@ +/** + * Copyright 2015 Aleix Pol Gonzalez + * + * 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 +#include +#include +#include +#include +#include + +#include + +#include "core/daemon.h" +#include "core/device.h" +#include "core/kdeconnectplugin.h" +#include "kdeconnect-version.h" + +class TestDaemon : public Daemon +{ +Q_OBJECT +public: + TestDaemon(QObject* parent = Q_NULLPTR) + : Daemon(parent, true) + , m_nam(Q_NULLPTR) + { + } + + void requestPairing(Device* d) Q_DECL_OVERRIDE + { + d->acceptPairing(); + } + + void reportError(const QString & title, const QString & description) Q_DECL_OVERRIDE + { + qWarning() << "error:" << title << description; + } + + QNetworkAccessManager* networkAccessManager() Q_DECL_OVERRIDE + { + if (!m_nam) { + m_nam = new KIO::AccessManager(this); + } + return m_nam; + } + +private: + QNetworkAccessManager* m_nam; +}; + +class TestSendFile : public QObject +{ + Q_OBJECT + public: + TestSendFile() : mDaemon(new TestDaemon) {} + + private Q_SLOTS: + void testSend() { + Device* d = mDaemon->devicesList().first(); + QCOMPARE(d->isReachable(), true); + QCOMPARE(d->isPaired(), true); + + QByteArray content("12312312312313213123213123"); + + QTemporaryFile temp; + temp.open(); + temp.write(content); + temp.close(); + + KdeConnectPlugin* plugin = d->plugin("kdeconnect_share"); + QVERIFY(plugin); + plugin->metaObject()->invokeMethod(plugin, "shareUrl", Q_ARG(QString, QUrl::fromLocalFile(temp.fileName()).toString())); + + QSignalSpy spy(plugin, SIGNAL(fileReceived(QUrl))); + QVERIFY(spy.wait(2000)); + + QVariantList args = spy.takeFirst(); + QUrl sentFile = args.first().toUrl(); + + QFile file(sentFile.toLocalFile()); + QCOMPARE(file.size(), content.size()); + QVERIFY(file.open(QIODevice::ReadOnly)); + QCOMPARE(file.readAll(), content); + } + + private: + TestDaemon* mDaemon; +}; + +QTEST_MAIN(TestSendFile); + +#include "sendfiletest.moc"