Fixed file transfer, added file size to protocol (optional)
Increased protocol version to 5 Updated README
This commit is contained in:
parent
cbe275106c
commit
e86897cfe3
11 changed files with 99 additions and 40 deletions
22
README
22
README
|
@ -15,11 +15,11 @@ Class diagram
|
||||||
|
|
||||||
Daemon instantiates Backends
|
Daemon instantiates Backends
|
||||||
|
|
||||||
Backends manage to create DeviceLinks with the devices they can reach, and Q_EMIT them to Daemon.
|
Backends manage to create DeviceLinks with the devices they can reach, and Q_EMIT them to the Daemon.
|
||||||
|
|
||||||
When Daemon receives a DeviceLink from a backend it:
|
When the Daemon receives a DeviceLink from a backend:
|
||||||
- If he already knows the Device, adds the DeviceLink to the Device
|
- If it already knows the Device, adds the new DeviceLink to the existing Device, as a new way to reach it.
|
||||||
- If not, it creates a new Device.
|
- If not, it creates a new untrusted (yet to be paired) Device.
|
||||||
|
|
||||||
Devices contain a list of DeviceLinks, plus a list of Plugins (instantiated automatically)
|
Devices contain a list of DeviceLinks, plus a list of Plugins (instantiated automatically)
|
||||||
|
|
||||||
|
@ -45,10 +45,22 @@ The basic structure of a NetworkPackage is the following:
|
||||||
"body": {
|
"body": {
|
||||||
|
|
||||||
},
|
},
|
||||||
"version": 1
|
"version": 5
|
||||||
}
|
}
|
||||||
|
|
||||||
Each type of package defines what it should contain inside its "body", so only
|
Each type of package defines what it should contain inside its "body", so only
|
||||||
the emisor Plugin and receiver Plugin of this type of package need agree about
|
the emisor Plugin and receiver Plugin of this type of package need agree about
|
||||||
its content.
|
its content.
|
||||||
|
|
||||||
|
If the package has a payload attached, it will also contain two more fields:
|
||||||
|
"payloadSize": The size of the file, or -1 if it is a stream without known end
|
||||||
|
"payloadTransferInfo": Another JSON Object containing the information that the
|
||||||
|
backend wants to send to the peer backend, to actually
|
||||||
|
transfer the payload.
|
||||||
|
|
||||||
|
Encrypted network packages have the following format:
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
|
||||||
|
|
||||||
|
//TODO: Document the possible contents written for each plugin in the body part
|
||||||
|
|
|
@ -32,6 +32,7 @@ void DownloadJob::start()
|
||||||
qDebug() << "start";
|
qDebug() << "start";
|
||||||
mSocket->connectToHost(mAddress, mPort, QIODevice::ReadOnly);
|
mSocket->connectToHost(mAddress, mPort, QIODevice::ReadOnly);
|
||||||
connect(mSocket, SIGNAL(disconnected()), this, SLOT(disconnected()));
|
connect(mSocket, SIGNAL(disconnected()), this, SLOT(disconnected()));
|
||||||
|
//TODO: Implement payload encryption somehow (create an intermediate iodevice to encrypt the payload here?)
|
||||||
}
|
}
|
||||||
|
|
||||||
void DownloadJob::disconnected()
|
void DownloadJob::disconnected()
|
||||||
|
|
|
@ -101,7 +101,7 @@ void LanDeviceLink::dataReceived()
|
||||||
qDebug() << "HasPayloadTransferInfo";
|
qDebug() << "HasPayloadTransferInfo";
|
||||||
DownloadJob* job = new DownloadJob(mSocket->peerAddress(), decrypted.payloadTransferInfo());
|
DownloadJob* job = new DownloadJob(mSocket->peerAddress(), decrypted.payloadTransferInfo());
|
||||||
job->start();
|
job->start();
|
||||||
decrypted.setPayload(job->getPayload());
|
decrypted.setPayload(job->getPayload(), decrypted.payloadSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_EMIT receivedPackage(decrypted);
|
Q_EMIT receivedPackage(decrypted);
|
||||||
|
|
|
@ -62,6 +62,8 @@ void UploadJob::newConnection()
|
||||||
|
|
||||||
void UploadJob::readyRead()
|
void UploadJob::readyRead()
|
||||||
{
|
{
|
||||||
|
//TODO: Implement payload encryption
|
||||||
|
|
||||||
qint64 bytes = qMax(mInput->bytesAvailable(), (qint64)4096);
|
qint64 bytes = qMax(mInput->bytesAvailable(), (qint64)4096);
|
||||||
mSocket->write(mInput->read(bytes));
|
mSocket->write(mInput->read(bytes));
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ bool LoopbackDeviceLink::sendPackageEncrypted(QCA::PublicKey& key, NetworkPackag
|
||||||
//LoopbackDeviceLink does not need deviceTransferInfo
|
//LoopbackDeviceLink does not need deviceTransferInfo
|
||||||
if (input.hasPayload()) {
|
if (input.hasPayload()) {
|
||||||
QIODevice* device = input.payload();
|
QIODevice* device = input.payload();
|
||||||
output.setPayload(device);
|
output.setPayload(device, input.payloadSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_EMIT receivedPackage(output);
|
Q_EMIT receivedPackage(output);
|
||||||
|
@ -63,7 +63,7 @@ bool LoopbackDeviceLink::sendPackage(NetworkPackage& input)
|
||||||
//LoopbackDeviceLink does not need deviceTransferInfo
|
//LoopbackDeviceLink does not need deviceTransferInfo
|
||||||
if (input.hasPayload()) {
|
if (input.hasPayload()) {
|
||||||
QIODevice* device = input.payload();
|
QIODevice* device = input.payload();
|
||||||
output.setPayload(device);
|
output.setPayload(device, input.payloadSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_EMIT receivedPackage(output);
|
Q_EMIT receivedPackage(output);
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
#include <qjson/qobjecthelper.h>
|
#include <qjson/qobjecthelper.h>
|
||||||
|
|
||||||
const QCA::EncryptionAlgorithm NetworkPackage::EncryptionAlgorithm = QCA::EME_PKCS1v15;
|
const QCA::EncryptionAlgorithm NetworkPackage::EncryptionAlgorithm = QCA::EME_PKCS1v15;
|
||||||
const int NetworkPackage::ProtocolVersion = 4;
|
const int NetworkPackage::ProtocolVersion = 5;
|
||||||
|
|
||||||
NetworkPackage::NetworkPackage(const QString& type)
|
NetworkPackage::NetworkPackage(const QString& type)
|
||||||
{
|
{
|
||||||
|
@ -42,6 +42,7 @@ NetworkPackage::NetworkPackage(const QString& type)
|
||||||
mType = type;
|
mType = type;
|
||||||
mBody = QVariantMap();
|
mBody = QVariantMap();
|
||||||
mPayload = 0;
|
mPayload = 0;
|
||||||
|
mPayloadSize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkPackage::createIdentityPackage(NetworkPackage* np)
|
void NetworkPackage::createIdentityPackage(NetworkPackage* np)
|
||||||
|
@ -51,6 +52,7 @@ void NetworkPackage::createIdentityPackage(NetworkPackage* np)
|
||||||
np->mId = QString::number(QDateTime::currentMSecsSinceEpoch());
|
np->mId = QString::number(QDateTime::currentMSecsSinceEpoch());
|
||||||
np->mType = PACKAGE_TYPE_IDENTITY;
|
np->mType = PACKAGE_TYPE_IDENTITY;
|
||||||
np->mPayload = 0;
|
np->mPayload = 0;
|
||||||
|
np->mPayloadSize = 0;
|
||||||
np->set("deviceId", id);
|
np->set("deviceId", id);
|
||||||
np->set("deviceName", QHostInfo::localHostName());
|
np->set("deviceName", QHostInfo::localHostName());
|
||||||
np->set("protocolVersion", NetworkPackage::ProtocolVersion);
|
np->set("protocolVersion", NetworkPackage::ProtocolVersion);
|
||||||
|
@ -69,6 +71,7 @@ QByteArray NetworkPackage::serialize() const
|
||||||
|
|
||||||
if (hasPayload()) {
|
if (hasPayload()) {
|
||||||
//qDebug() << "Serializing payloadTransferInfo";
|
//qDebug() << "Serializing payloadTransferInfo";
|
||||||
|
variant["payloadSize"] = 0;
|
||||||
variant["payloadTransferInfo"] = mPayloadTransferInfo;
|
variant["payloadTransferInfo"] = mPayloadTransferInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,10 +113,8 @@ bool NetworkPackage::unserialize(const QByteArray& a, NetworkPackage* np)
|
||||||
qDebug() << "Unserialize: " << a;
|
qDebug() << "Unserialize: " << a;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (variant.contains("payloadTransferInfo")) {
|
np->mPayloadSize = variant["payloadSize"].toInt(); //Will return 0 if was not present, which is ok
|
||||||
//qDebug() << "Unserializing payloadTransferInfo";
|
np->mPayloadTransferInfo = variant["payloadTransferInfo"].toMap(); //Will return an empty qvariantmap if was not present, which is ok
|
||||||
np->mPayloadTransferInfo = variant["payloadTransferInfo"].toMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -122,7 +123,6 @@ bool NetworkPackage::unserialize(const QByteArray& a, NetworkPackage* np)
|
||||||
void NetworkPackage::encrypt(QCA::PublicKey& key)
|
void NetworkPackage::encrypt(QCA::PublicKey& key)
|
||||||
{
|
{
|
||||||
|
|
||||||
//TODO: Implement payload encryption somehow (create an intermediate iodevice to encrypt the payload here?)
|
|
||||||
QByteArray serialized = serialize();
|
QByteArray serialized = serialize();
|
||||||
|
|
||||||
int chunkSize = key.maximumEncryptSize(NetworkPackage::EncryptionAlgorithm);
|
int chunkSize = key.maximumEncryptSize(NetworkPackage::EncryptionAlgorithm);
|
||||||
|
@ -160,12 +160,15 @@ bool NetworkPackage::decrypt(QCA::PrivateKey& key, NetworkPackage* out) const
|
||||||
decryptedJson.append(decryptedChunk.toByteArray());
|
decryptedJson.append(decryptedChunk.toByteArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Implement payload encryption somehow (create an intermediate iodevice to decrypt the payload here?)
|
bool success = unserialize(decryptedJson, out);
|
||||||
|
|
||||||
|
if (!success) return false;
|
||||||
|
|
||||||
if (hasPayload()) {
|
if (hasPayload()) {
|
||||||
out->setPayload(mPayload);
|
out->mPayload = mPayload;
|
||||||
}
|
}
|
||||||
|
|
||||||
return unserialize(decryptedJson, out);
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,8 +71,9 @@ public:
|
||||||
|
|
||||||
//TODO: Change to a shared pointer
|
//TODO: Change to a shared pointer
|
||||||
QIODevice* payload() const { return mPayload; }
|
QIODevice* payload() const { return mPayload; }
|
||||||
void setPayload(QIODevice* device) { mPayload = device; }
|
void setPayload(QIODevice* device, int payloadSize) { mPayload = device; mPayloadSize = payloadSize; Q_ASSERT(mPayloadSize >= -1); }
|
||||||
bool hasPayload() const { return (mPayload != 0); }
|
bool hasPayload() const { return (mPayloadSize != 0); }
|
||||||
|
int payloadSize() const { return mPayloadSize; } //-1 means it is an endless stream
|
||||||
|
|
||||||
//To be called by a particular DeviceLink
|
//To be called by a particular DeviceLink
|
||||||
QVariantMap payloadTransferInfo() const { return mPayloadTransferInfo; }
|
QVariantMap payloadTransferInfo() const { return mPayloadTransferInfo; }
|
||||||
|
@ -84,12 +85,14 @@ private:
|
||||||
void setId(const QString& id) { mId = id; }
|
void setId(const QString& id) { mId = id; }
|
||||||
void setType(const QString& t) { mType = t; }
|
void setType(const QString& t) { mType = t; }
|
||||||
void setBody(const QVariantMap& b) { mBody = b; }
|
void setBody(const QVariantMap& b) { mBody = b; }
|
||||||
|
void setPayloadSize(int s) { mPayloadSize = s; }
|
||||||
|
|
||||||
QString mId;
|
QString mId;
|
||||||
QString mType;
|
QString mType;
|
||||||
QVariantMap mBody;
|
QVariantMap mBody;
|
||||||
|
|
||||||
QIODevice* mPayload;
|
QIODevice* mPayload;
|
||||||
|
int mPayloadSize;
|
||||||
QVariantMap mPayloadTransferInfo;
|
QVariantMap mPayloadTransferInfo;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,13 +20,17 @@
|
||||||
|
|
||||||
#include "filetransferjob.h"
|
#include "filetransferjob.h"
|
||||||
|
|
||||||
|
#include <KLocalizedString>
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <qalgorithms.h>
|
#include <qalgorithms.h>
|
||||||
|
|
||||||
FileTransferJob::FileTransferJob(QIODevice* origin, const KUrl& destination): KJob()
|
FileTransferJob::FileTransferJob(QIODevice* origin, int size, const KUrl& destination): KJob()
|
||||||
{
|
{
|
||||||
mDestination = destination;
|
mDestination = destination;
|
||||||
mOrigin = origin;
|
mOrigin = origin;
|
||||||
|
mSize = size;
|
||||||
|
mWritten = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileTransferJob::start()
|
void FileTransferJob::start()
|
||||||
|
@ -47,50 +51,79 @@ void FileTransferJob::open(KIO::Job* job)
|
||||||
{
|
{
|
||||||
Q_UNUSED(job);
|
Q_UNUSED(job);
|
||||||
|
|
||||||
|
qDebug() << "open";
|
||||||
|
|
||||||
|
if (!mOrigin) {
|
||||||
|
qDebug() << "FileTransferJob: Origin is null";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//Open source file
|
//Open source file
|
||||||
|
|
||||||
mOrigin->open(QIODevice::ReadOnly);
|
mOrigin->open(QIODevice::ReadOnly);
|
||||||
|
|
||||||
Q_ASSERT(mOrigin->isOpen());
|
Q_ASSERT(mOrigin->isOpen());
|
||||||
|
|
||||||
connect(mOrigin, SIGNAL(readyRead()),this, SLOT(readyRead()));
|
connect(mOrigin, SIGNAL(readyRead()),this, SLOT(readyRead()));
|
||||||
connect(mOrigin, SIGNAL(aboutToClose()),this, SLOT(sourceFinished()));
|
connect(mOrigin, SIGNAL(disconnected()),this, SLOT(sourceFinished()));
|
||||||
if (mOrigin->bytesAvailable() > 0) readyRead();
|
if (mOrigin->bytesAvailable() > 0) readyRead();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileTransferJob::readyRead()
|
void FileTransferJob::readyRead()
|
||||||
{
|
{
|
||||||
|
qDebug() << "readyRead";
|
||||||
|
|
||||||
//Copy a chunk of data
|
//Copy a chunk of data
|
||||||
|
|
||||||
int bytes = qMin(qint64(4096), mOrigin->bytesAvailable());
|
int bytes = qMin(qint64(4096), mOrigin->bytesAvailable());
|
||||||
QByteArray data = mOrigin->read(bytes);
|
QByteArray data = mOrigin->read(bytes);
|
||||||
mTempDestination->write(data);
|
mTempDestination->write(data);
|
||||||
|
mWritten += bytes;
|
||||||
|
|
||||||
if(!mOrigin->atEnd())
|
if (mSize > -1) {
|
||||||
|
setPercent((mWritten*100)/mSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << mSize << mWritten << bytes;
|
||||||
|
|
||||||
|
if (mSize > -1 && mWritten >= mSize) { //At the end or expected size reached
|
||||||
|
qDebug() << "No more data to read";
|
||||||
|
disconnect(mOrigin, SIGNAL(readyRead()),this, SLOT(readyRead()));
|
||||||
|
mOrigin->close();
|
||||||
|
} else if (mOrigin->bytesAvailable() > 0) {
|
||||||
QMetaObject::invokeMethod(this, "readyRead", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(this, "readyRead", Qt::QueuedConnection);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileTransferJob::sourceFinished()
|
void FileTransferJob::sourceFinished()
|
||||||
{
|
{
|
||||||
qDebug() << "sourceFinished";
|
qDebug() << "sourceFinished";
|
||||||
|
|
||||||
readyRead(); //Read the last chunk of data, if any
|
//Make sure we do not enter this function again
|
||||||
|
disconnect(mOrigin, SIGNAL(aboutToClose()),this, SLOT(sourceFinished()));
|
||||||
|
|
||||||
qDebug() << "Finished" << mTempDestination->url();
|
//TODO: MD5 check the file
|
||||||
|
if (mSize > -1 && mWritten != mSize) {
|
||||||
|
qDebug() << "Received incomplete file";
|
||||||
|
setError(1);
|
||||||
|
setErrorText(i18n("Received incomplete file"));
|
||||||
|
emitResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "Finished" << mTempDestination->url() << mDestination;
|
||||||
KIO::FileCopyJob* job = KIO::file_move(mTempDestination->url(), mDestination);
|
KIO::FileCopyJob* job = KIO::file_move(mTempDestination->url(), mDestination);
|
||||||
connect(job, SIGNAL(result(KJob*)), this, SLOT(moveResult(KJob*)));
|
connect(job, SIGNAL(result(KJob*)), this, SLOT(moveResult(KJob*)));
|
||||||
job->start();
|
job->start();
|
||||||
|
|
||||||
delete mOrigin; //TODO: Use shared pointers
|
//delete mOrigin; //TODO: Use shared pointers
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileTransferJob::moveResult(KJob* job)
|
void FileTransferJob::moveResult(KJob* job)
|
||||||
{
|
{
|
||||||
//TODO: Error handling, cleanup
|
//TODO: Error handling, cleanup
|
||||||
qDebug() << "Move result";
|
qDebug() << "Move finished";
|
||||||
qDebug() << job->errorString();
|
if (job->error()) {
|
||||||
qDebug() << job->errorText();
|
qDebug() << job->errorText();
|
||||||
|
}
|
||||||
emitResult();
|
emitResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ class FileTransferJob : public KJob
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FileTransferJob(QIODevice* origin, const KUrl& destination);
|
FileTransferJob(QIODevice* origin, int size, const KUrl& destination);
|
||||||
virtual void start();
|
virtual void start();
|
||||||
KUrl destination() { return mDestination; }
|
KUrl destination() { return mDestination; }
|
||||||
|
|
||||||
|
@ -48,7 +48,9 @@ public Q_SLOTS:
|
||||||
private:
|
private:
|
||||||
KIO::FileJob* mTempDestination;
|
KIO::FileJob* mTempDestination;
|
||||||
KUrl mDestination;
|
KUrl mDestination;
|
||||||
|
int mSize;
|
||||||
QIODevice* mOrigin;
|
QIODevice* mOrigin;
|
||||||
|
int mWritten;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -40,41 +40,42 @@ FileTransferPlugin::FileTransferPlugin(QObject* parent, const QVariantList& args
|
||||||
//TODO: Use downloads user path
|
//TODO: Use downloads user path
|
||||||
//TODO: Be able to change this from config
|
//TODO: Be able to change this from config
|
||||||
mDestinationDir = QDesktopServices::storageLocation(QDesktopServices::DesktopLocation);
|
mDestinationDir = QDesktopServices::storageLocation(QDesktopServices::DesktopLocation);
|
||||||
|
if (!mDestinationDir.endsWith('/')) mDestinationDir.append('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FileTransferPlugin::receivePackage(const NetworkPackage& np)
|
bool FileTransferPlugin::receivePackage(const NetworkPackage& np)
|
||||||
{
|
{
|
||||||
|
|
||||||
//TODO: Move this code to a test and do a diff between files
|
//TODO: Move this code to a test and do a diff between files
|
||||||
//if (np.type() == PACKAGE_TYPE_PING) {
|
if (np.type() == PACKAGE_TYPE_PING) {
|
||||||
|
|
||||||
qDebug() << "sending file" << (QDesktopServices::storageLocation(QDesktopServices::HomeLocation) + "/.bashrc");
|
qDebug() << "sending file" << (QDesktopServices::storageLocation(QDesktopServices::HomeLocation) + "/.bashrc");
|
||||||
|
|
||||||
NetworkPackage out(PACKAGE_TYPE_FILETRANSFER);
|
NetworkPackage out(PACKAGE_TYPE_FILETRANSFER);
|
||||||
out.set("filename", mDestinationDir + "/itworks.txt");
|
out.set("filename", mDestinationDir + "itworks.txt");
|
||||||
//TODO: Use shared pointers
|
//TODO: Use shared pointers
|
||||||
AutoClosingQFile* file = new AutoClosingQFile(QDesktopServices::storageLocation(QDesktopServices::HomeLocation) + "/.bashrc"); //Test file to transfer
|
AutoClosingQFile* file = new AutoClosingQFile(QDesktopServices::storageLocation(QDesktopServices::HomeLocation) + "/.bashrc"); //Test file to transfer
|
||||||
|
|
||||||
out.setPayload(file);
|
out.setPayload(file, file->size());
|
||||||
|
|
||||||
device()->sendPackage(out);
|
device()->sendPackage(out);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
//}
|
}
|
||||||
|
|
||||||
if (np.type() != PACKAGE_TYPE_FILETRANSFER) return false;
|
if (np.type() != PACKAGE_TYPE_FILETRANSFER) return false;
|
||||||
|
qDebug() << "File transfer";
|
||||||
qDebug() << "file transfer";
|
|
||||||
|
|
||||||
if (np.hasPayload()) {
|
if (np.hasPayload()) {
|
||||||
qDebug() << "receiving file";
|
qDebug() << "receiving file";
|
||||||
QString filename = np.get<QString>("filename");
|
QString filename = np.get<QString>("filename", mDestinationDir + QString::number(QDateTime::currentMSecsSinceEpoch()));
|
||||||
QIODevice* incoming = np.payload();
|
QIODevice* incoming = np.payload();
|
||||||
FileTransferJob* job = new FileTransferJob(incoming,filename);
|
FileTransferJob* job = new FileTransferJob(incoming, np.payloadSize(), filename);
|
||||||
connect(job,SIGNAL(result(KJob*)), this, SLOT(finished(KJob*)));
|
connect(job,SIGNAL(result(KJob*)), this, SLOT(finished(KJob*)));
|
||||||
job->start();
|
job->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,8 @@ void NotificationsDbusInterface::processPackage(const NetworkPackage& np)
|
||||||
} else {
|
} else {
|
||||||
Notification* noti = new Notification(np, this);
|
Notification* noti = new Notification(np, this);
|
||||||
|
|
||||||
|
//TODO: Store the app icon if any under tmp with the app name as filename (so we only store one per app) and export the path to that file to dbus inside Notification
|
||||||
|
|
||||||
//Do not show updates to existent notification nor answers to a initialization request
|
//Do not show updates to existent notification nor answers to a initialization request
|
||||||
if (!mInternalIdToPublicId.contains(noti->internalId()) && !np.get<bool>("requestAnswer", false)) {
|
if (!mInternalIdToPublicId.contains(noti->internalId()) && !np.get<bool>("requestAnswer", false)) {
|
||||||
KNotification* notification = new KNotification("notification");
|
KNotification* notification = new KNotification("notification");
|
||||||
|
|
Loading…
Reference in a new issue