Merge branch '0.9'

This commit is contained in:
Aleix Pol 2015-10-19 17:48:13 +02:00
commit 0bca50af93
20 changed files with 225 additions and 114 deletions

View file

@ -20,30 +20,50 @@
#include "downloadjob.h"
#include <core/core_debug.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include "lanlinkprovider.h"
DownloadJob::DownloadJob(const QHostAddress &address, const QVariantMap &transferInfo): KJob()
{
mAddress = address;
mPort = transferInfo["port"].toInt();
mSocket = QSharedPointer<QTcpSocket>(new QTcpSocket);
mSocket = QSharedPointer<QTcpSocket>(new QTcpSocket());
}
DownloadJob::~DownloadJob()
{
}
void DownloadJob::start()
{
//kDebug(kdeconnect_kded()) << "DownloadJob Start";
//TODO: Timeout?
connect(mSocket.data(), &QAbstractSocket::disconnected, this, &DownloadJob::done);
connect(mSocket.data(), SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(done()));
//connect(mSocket.data(), &QAbstractSocket::connected, [=](){ qDebug() << "Connected"; });
mSocket->connectToHost(mAddress, mPort, QIODevice::ReadOnly);
connect(mSocket.data(), SIGNAL(disconnected()),
this, SLOT(disconnected()));
//mSocket->open(QIODevice::ReadOnly);
//TODO: Implement payload encryption somehow (create an intermediate iodevice to encrypt the payload here?)
}
void DownloadJob::disconnected()
void DownloadJob::done()
{
//kDebug(kdeconnect_kded()) << "DownloadJob End";
if (mSocket->error()) {
qWarning(KDECONNECT_CORE) << mSocket->errorString();
}
emitResult();
deleteLater();
}
QSharedPointer<QIODevice> DownloadJob::getPayload()
{
//kDebug(kdeconnect_kded()) << "getPayload";
return mSocket.staticCast<QIODevice>();
}

View file

@ -35,7 +35,8 @@ class DownloadJob
Q_OBJECT
public:
DownloadJob(const QHostAddress &address, const QVariantMap &transferInfo);
virtual void start() override;
~DownloadJob();
void start() Q_DECL_OVERRIDE;
QSharedPointer<QIODevice> getPayload();
private:
@ -43,9 +44,8 @@ private:
qint16 mPort;
QSharedPointer<QTcpSocket> mSocket;
private Q_SLOTS:
void disconnected();
void done();
};

View file

@ -26,7 +26,6 @@
#include <QUdpSocket>
#include "../linkprovider.h"
#include "netaddress.h"
class LanLinkProvider
: public LinkProvider

View file

@ -1,37 +0,0 @@
/**
* Copyright 2013 Albert Vaca <albertvaka@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef NETADDRESS_H
#define NETADDRESS_H
#include <QHostAddress>
struct NetAddress {
NetAddress() { }
NetAddress(const QHostAddress &_ip, quint16 _port) : ip(_ip), port(_port) { }
QHostAddress ip;
quint16 port;
};
inline bool operator< (const NetAddress& a, const NetAddress& b){
return (a.ip.toString()+a.port) < (b.ip.toString()+b.port);
}
#endif // NETADDRESS_H

View file

@ -33,8 +33,8 @@ void SocketLineReader::dataReceived()
{
while (mSocket->canReadLine()) {
const QByteArray line = mSocket->readLine();
if (line.length() > 1) {
mPackages.enqueue(line);//we don't want single \n
if (line.length() > 1) { //we don't want a single \n
mPackages.enqueue(line);
}
}

View file

@ -23,6 +23,8 @@
#include <QLoggingCategory>
Q_DECLARE_LOGGING_CATEGORY(KDECONNECT_CORE)
#include "kdeconnectcore_export.h"
KDECONNECTCORE_EXPORT Q_DECLARE_LOGGING_CATEGORY(KDECONNECT_CORE)
#endif //CORE_DEBUG_H

View file

@ -33,7 +33,7 @@ FileTransferJob::FileTransferJob(const QSharedPointer<QIODevice>& origin, qint64
: KJob()
, mOrigin(origin)
, mReply(Q_NULLPTR)
, mDeviceName("KDE Connect") //TODO: Actually fetch the device name
, mFrom("KDE Connect")
, mDestination(destination)
, mSpeedBytes(0)
, mWritten(0)
@ -48,6 +48,7 @@ FileTransferJob::FileTransferJob(const QSharedPointer<QIODevice>& origin, qint64
if (size >= 0) {
setTotalAmount(Bytes, size);
}
setCapabilities(Killable);
qCDebug(KDECONNECT_CORE) << "FileTransferJob Downloading payload to" << destination;
}
@ -60,9 +61,8 @@ void FileTransferJob::start()
void FileTransferJob::doStart()
{
description(this, i18n("Receiving file over KDE-Connect"),
QPair<QString, QString>(i18nc("File transfer origin", "From"),
mDeviceName)
description(this, i18n("Receiving file over KDE Connect"),
QPair<QString, QString>(i18nc("File transfer origin", "From"), mFrom)
);
if (mDestination.isLocalFile() && QFile::exists(mDestination.toLocalFile())) {
@ -78,9 +78,8 @@ void FileTransferJob::startTransfer()
{
setProcessedAmount(Bytes, 0);
mTime = QTime::currentTime();
description(this, i18n("Receiving file over KDE-Connect"),
QPair<QString, QString>(i18nc("File transfer origin", "From"),
mDeviceName),
description(this, i18n("Receiving file over KDE Connect"),
QPair<QString, QString>(i18nc("File transfer origin", "From"), mFrom),
QPair<QString, QString>(i18nc("File transfer destination", "To"), mDestination.toLocalFile()));
QNetworkRequest req(mDestination);

View file

@ -55,7 +55,7 @@ public:
FileTransferJob(const QSharedPointer<QIODevice>& origin, qint64 size, const QUrl &destination);
virtual void start() Q_DECL_OVERRIDE;
QUrl destination() const { return mDestination; }
void setDeviceName(const QString &deviceName) { mDeviceName = deviceName; }
void setOriginName(QString from) { mFrom = from; }
private Q_SLOTS:
void doStart();
@ -69,7 +69,7 @@ private:
QSharedPointer<QIODevice> mOrigin;
QNetworkReply* mReply;
QString mDeviceName;
QString mFrom;
QUrl mDestination;
QTime mTime;
qulonglong mSpeedBytes;

View file

@ -70,7 +70,9 @@
<string/>
</property>
<property name="icon">
<iconset theme="edit-rename"/>
<iconset theme="edit-rename">
<normaloff/>
</iconset>
</property>
</widget>
</item>
@ -91,7 +93,9 @@
<string/>
</property>
<property name="icon">
<iconset theme="dialog-ok"/>
<iconset theme="dialog-ok">
<normaloff/>
</iconset>
</property>
</widget>
</item>
@ -295,7 +299,38 @@
</sizepolicy>
</property>
<property name="text">
<string>If you have an Android phone, make sure to install the &lt;a href=&quot;https://play.google.com/store/apps/details?id=org.kde.kdeconnect_tp&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;KDE Connect Android app&lt;/span&gt;&lt;/a&gt; (also available &lt;a href=&quot;https://f-droid.org/repository/browse/?fdid=org.kde.kdeconnect_tp&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;from F-Droid&lt;/span&gt;&lt;/a&gt;).</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If you own Android device, make sure to install the &lt;a href=&quot;https://play.google.com/store/apps/details?id=org.kde.kdeconnect_tp&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;KDE Connect Android app&lt;/span&gt;&lt;/a&gt; (also available &lt;a href=&quot;https://f-droid.org/repository/browse/?fdid=org.kde.kdeconnect_tp&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;from F-Droid&lt;/span&gt;&lt;/a&gt;) and it should appear in the list.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="margin">
<number>40</number>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="noDeviceTroubleshoot">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If you are having problems, visit the &lt;a href=&quot;https://community.kde.org/KDEConnect&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;KDE Connect Community wiki&lt;/span&gt;&lt;/a&gt; for help.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>

View file

@ -24,6 +24,5 @@ set_target_properties(kdeconnectpluginkcm PROPERTIES
target_include_directories(kdeconnectpluginkcm PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
generate_export_header(kdeconnectpluginkcm EXPORT_FILE_NAME kdeconnectpluginkcm_export.h BASE_NAME kdeconnectpluginkcm)
# Remove NAMELINK_SKIP if/when headers are being installed and the library
# becomes public.
# Remove NAMELINK_SKIP if/when headers are being installed and the library becomes public.
install(TARGETS kdeconnectpluginkcm EXPORT kdeconnectLibraryTargets ${INSTALL_TARGETS_DEFAULT_ARGS} LIBRARY NAMELINK_SKIP)

View file

@ -32,7 +32,7 @@ Q_DECLARE_LOGGING_CATEGORY(KDECONNECT_KIO)
class KioKdeconnect : public QObject, public KIO::SlaveBase
{
Q_OBJECT
Q_OBJECT
public:
KioKdeconnect(const QByteArray &pool, const QByteArray &app);

View file

@ -25,7 +25,7 @@
Notification::Notification(const NetworkPackage& np, const QString& iconPath, QObject* parent)
: QObject(parent)
{
mId = np.get<QString>("id");
mInternalId = np.get<QString>("id");
mAppName = np.get<QString>("appName");
mTicker = np.get<QString>("ticker");
mDismissable = np.get<bool>("isClearable");
@ -40,7 +40,7 @@ Notification::~Notification()
void Notification::dismiss()
{
if (mDismissable) {
Q_EMIT dismissRequested(this);
Q_EMIT dismissRequested(mInternalId);
}
}

View file

@ -41,7 +41,7 @@ public:
Notification(const NetworkPackage& np, const QString& iconPath, QObject* parent);
virtual ~Notification();
QString internalId() const { return mId; }
QString internalId() const { return mInternalId; }
QString appName() const { return mAppName; }
QString ticker() const { return mTicker; }
QString iconPath() const { return mIconPath; }
@ -51,10 +51,10 @@ public Q_SLOTS:
Q_SCRIPTABLE void dismiss();
Q_SIGNALS:
void dismissRequested(Notification* self);
void dismissRequested(const QString& mInternalId);
private:
QString mId;
QString mInternalId;
QString mAppName;
QString mTicker;
QString mIconPath;

View file

@ -98,8 +98,8 @@ void NotificationsDbusInterface::addNotification(Notification* noti)
removeNotification(internalId);
}
connect(noti, SIGNAL(dismissRequested(Notification*)),
this, SLOT(dismissRequested(Notification*)));
connect(noti, &Notification::dismissRequested,
this, &NotificationsDbusInterface::dismissRequested);
const QString& publicId = newId();
mNotifications[publicId] = noti;
@ -133,10 +133,8 @@ void NotificationsDbusInterface::removeNotification(const QString& internalId)
Q_EMIT notificationRemoved(publicId);
}
void NotificationsDbusInterface::dismissRequested(Notification* notification)
void NotificationsDbusInterface::dismissRequested(const QString& internalId)
{
const QString& internalId = notification->internalId();
NetworkPackage np(PACKAGE_TYPE_NOTIFICATION);
np.set<QString>("cancel", internalId);
mPlugin->sendPackage(np);

View file

@ -44,10 +44,10 @@ public:
void processPackage(const NetworkPackage& np);
void clearNotifications();
void dismissRequested(const QString& notification);
public Q_SLOTS:
Q_SCRIPTABLE QStringList activeNotifications();
void dismissRequested(Notification* notification);
Q_SIGNALS:
Q_SCRIPTABLE void notificationPosted(const QString& publicId);

View file

@ -48,13 +48,13 @@ Mounter::Mounter(SftpPlugin* sftp)
m_connectTimer.setSingleShot(true);
QTimer::singleShot(0, this, SLOT(start()));
qCDebug(KDECONNECT_PLUGIN_SFTP) << "Created";
qCDebug(KDECONNECT_PLUGIN_SFTP) << "Created mounter";
}
Mounter::~Mounter()
{
qCDebug(KDECONNECT_PLUGIN_SFTP) << "Destroy mounter";
unmount();
qCDebug(KDECONNECT_PLUGIN_SFTP) << "Destroyed";
}
bool Mounter::wait()
@ -95,12 +95,14 @@ void Mounter::onPakcageReceived(const NetworkPackage& np)
* Q_EMIT mounted();
*/
m_proc.reset(new KProcess(this));
unmount();
m_proc = new KProcess(this);
m_proc->setOutputChannelMode(KProcess::MergedChannels);
connect(m_proc.data(), SIGNAL(started()), SLOT(onStarted()));
connect(m_proc.data(), SIGNAL(error(QProcess::ProcessError)), SLOT(onError(QProcess::ProcessError)));
connect(m_proc.data(), SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(onFinished(int,QProcess::ExitStatus)));
connect(m_proc, SIGNAL(started()), SLOT(onStarted()));
connect(m_proc, SIGNAL(error(QProcess::ProcessError)), SLOT(onError(QProcess::ProcessError)));
connect(m_proc, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(onFinished(int,QProcess::ExitStatus)));
QDir().mkpath(m_mountPoint);
@ -125,12 +127,6 @@ void Mounter::onPakcageReceived(const NetworkPackage& np)
m_proc->setProgram(program, arguments);
//To debug
//m_proc->setStandardOutputFile("/tmp/kdeconnect-sftp.out");
//m_proc->setStandardErrorFile("/tmp/kdeconnect-sftp.err");
cleanMountPoint();
qCDebug(KDECONNECT_PLUGIN_SFTP) << "Starting process: " << m_proc->program().join(" ");
m_proc->start();
}
@ -141,10 +137,12 @@ void Mounter::onStarted()
m_started = true;
Q_EMIT mounted();
connect(m_proc.data(), &KProcess::readyReadStandardError, [this]() {
//m_proc->setStandardOutputFile("/tmp/kdeconnect-sftp.out");
//m_proc->setStandardErrorFile("/tmp/kdeconnect-sftp.err");
connect(m_proc, &KProcess::readyReadStandardError, [this]() {
qCDebug(KDECONNECT_PLUGIN_SFTP) << "stderr: " << m_proc->readAll();
});
connect(m_proc.data(), &KProcess::readyReadStandardOutput, [this]() {
connect(m_proc, &KProcess::readyReadStandardOutput, [this]() {
qCDebug(KDECONNECT_PLUGIN_SFTP) << "stdout:" << m_proc->readAll();
});
}
@ -172,9 +170,7 @@ void Mounter::onFinished(int exitCode, QProcess::ExitStatus exitStatus)
Q_EMIT failed(i18n("Error when accessing to filesystem"));
}
cleanMountPoint();
m_proc.reset();
m_started = false;
unmount();
}
void Mounter::onMountTimeout()
@ -192,25 +188,18 @@ void Mounter::start()
m_connectTimer.start();
}
void Mounter::cleanMountPoint()
{
qCDebug(KDECONNECT_PLUGIN_SFTP()) << "cleanMountPoint";
KProcess::execute(QStringList() << "fusermount" << "-u" << m_mountPoint, 10000);
}
void Mounter::unmount()
{
qCDebug(KDECONNECT_PLUGIN_SFTP) << "Unmount" << m_proc;
if (m_proc)
{
cleanMountPoint();
if (m_proc)
{
m_proc->terminate();
QTimer::singleShot(5000, m_proc.data(), SLOT(kill()));
m_proc->waitForFinished();
}
auto toDestroy = m_proc;
m_proc = nullptr; //So we don't reenter this code path when onFinished gets called
toDestroy->kill();
delete toDestroy;
//Free mount point (won't always succeed if the path is in use)
KProcess::execute(QStringList() << "fusermount" << "-u" << m_mountPoint, 10000);
}
m_started = false;
}

View file

@ -52,12 +52,11 @@ private Q_SLOTS:
void start();
private:
void cleanMountPoint();
void unmount();
private:
SftpPlugin* m_sftp;
QScopedPointer<KProcess> m_proc;
KProcess* m_proc;
QTimer m_connectTimer;
QString m_mountPoint;
bool m_started;

View file

@ -96,7 +96,7 @@ bool SharePlugin::receivePackage(const NetworkPackage& np)
}
FileTransferJob* job = np.createPayloadTransferJob(destination);
job->setDeviceName(device()->name());
job->setOriginName(device()->name() + ": " + filename);
connect(job, SIGNAL(result(KJob*)), this, SLOT(finished(KJob*)));
KIO::getJobTracker()->registerJob(job);
job->start();

View file

@ -18,3 +18,4 @@ ecm_add_test(pluginloadtest.cpp LINK_LIBRARIES ${kdeconnect_libraries})
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})
ecm_add_test(downloadjobtest.cpp ../core/backends/lan/downloadjob.cpp TEST_NAME downloadjobtest LINK_LIBRARIES ${kdeconnect_libraries})

107
tests/downloadjobtest.cpp Normal file
View file

@ -0,0 +1,107 @@
/*************************************************************************************
* Copyright (C) 2014 by Albert Vaca Cintora <albertvaka@gmail.com> *
* *
* 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 "../core/backends/lan/downloadjob.h"
#include <QTest>
#include <QTcpServer>
#include <QTcpSocket>
#include <QProcess>
#include <QEventLoop>
#include <QTimer>
#include <QHostAddress>
#include <KJob>
#include <unistd.h>
#include <iostream>
class DownloadJobTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void failToConnectShouldDestroyTheJob();
void closingTheConnectionShouldDestroyTheJob();
private:
void initServer();
void initDownloadJob();
void awaitToBeDestroyedOrTimeOut();
void stopServer();
QTimer mTimer;
QEventLoop mLoop;
DownloadJob* test;
QTcpServer *mServer;
};
void DownloadJobTest::initServer()
{
mServer = new QTcpServer(this);
QVERIFY2(mServer->listen(QHostAddress::LocalHost, 8694), "Failed to create local tcp server");
}
void DownloadJobTest::stopServer()
{
mServer->close();
}
void DownloadJobTest::initDownloadJob()
{
QVariantMap transferInfo;
transferInfo["port"]= 8694;
test = new DownloadJob(QHostAddress::LocalHost, transferInfo);
test->start();
}
void DownloadJobTest::awaitToBeDestroyedOrTimeOut()
{
//Either the job is destroyed
connect(test, &QObject::destroyed, &mLoop, &QEventLoop::quit);
//Or we time out
mTimer.setInterval(2000);
mTimer.setSingleShot(true);
connect(&mTimer, &QTimer::timeout, [this]() {
mLoop.quit();
QFAIL("Test timed out");
});
mTimer.start();
//We wait
mLoop.exec();
mTimer.stop();
}
void DownloadJobTest::failToConnectShouldDestroyTheJob()
{
initDownloadJob();
awaitToBeDestroyedOrTimeOut();
}
void DownloadJobTest::closingTheConnectionShouldDestroyTheJob()
{
initServer();
initDownloadJob();
stopServer();
awaitToBeDestroyedOrTimeOut();
}
QTEST_GUILESS_MAIN(DownloadJobTest)
#include "downloadjobtest.moc"