From 3a7735b19200552b219bc02f6f998e5f3702a8df Mon Sep 17 00:00:00 2001 From: blue Date: Sun, 18 Apr 2021 15:49:20 +0300 Subject: [PATCH] First steps on the new idea of file up/downloading --- CMakeLists.txt | 2 + core/account.cpp | 12 +- core/account.h | 2 +- core/handlers/messagehandler.cpp | 78 ++++++-- core/handlers/messagehandler.h | 7 +- core/networkaccess.cpp | 334 +++++++++++++++---------------- core/networkaccess.h | 30 +-- core/squawk.cpp | 25 +-- core/squawk.h | 31 ++- core/urlstorage.cpp | 191 +++++++++++------- core/urlstorage.h | 27 ++- main.cpp | 15 +- shared.h | 1 + shared/messageinfo.cpp | 45 +++++ shared/messageinfo.h | 43 ++++ ui/models/element.cpp | 15 +- ui/models/element.h | 6 +- ui/models/messagefeed.cpp | 26 ++- ui/models/messagefeed.h | 8 +- ui/models/roster.cpp | 136 ++++++------- ui/models/roster.h | 23 ++- ui/squawk.cpp | 103 ++-------- ui/squawk.h | 15 +- 23 files changed, 650 insertions(+), 525 deletions(-) create mode 100644 shared/messageinfo.cpp create mode 100644 shared/messageinfo.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 7418a7a..0db5693 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,7 @@ set(squawk_SRC shared/message.cpp shared/vcard.cpp shared/icons.cpp + shared/messageinfo.cpp ) set(squawk_HEAD @@ -45,6 +46,7 @@ set(squawk_HEAD shared/utils.h shared/vcard.h shared/icons.h + shared/messageinfo.h ) configure_file(resources/images/logo.svg squawk.svg COPYONLY) diff --git a/core/account.cpp b/core/account.cpp index 8452688..da7f25c 100644 --- a/core/account.cpp +++ b/core/account.cpp @@ -84,8 +84,9 @@ Account::Account(const QString& p_login, const QString& p_server, const QString& QObject::connect(dm, &QXmppDiscoveryManager::itemsReceived, this, &Account::onDiscoveryItemsReceived); QObject::connect(dm, &QXmppDiscoveryManager::infoReceived, this, &Account::onDiscoveryInfoReceived); - QObject::connect(network, &NetworkAccess::uploadFileComplete, mh, &MessageHandler::onFileUploaded); - QObject::connect(network, &NetworkAccess::uploadFileError, mh, &MessageHandler::onFileUploadError); + QObject::connect(network, &NetworkAccess::uploadFileComplete, mh, &MessageHandler::onUploadFileComplete); + QObject::connect(network, &NetworkAccess::downloadFileComplete, mh, &MessageHandler::onDownloadFileComplete); + QObject::connect(network, &NetworkAccess::loadFileError, mh, &MessageHandler::onLoadFileError); client.addExtension(rcpm); QObject::connect(rcpm, &QXmppMessageReceiptManager::messageDelivered, mh, &MessageHandler::onReceiptReceived); @@ -155,8 +156,9 @@ Account::~Account() reconnectTimer->stop(); } - QObject::disconnect(network, &NetworkAccess::uploadFileComplete, mh, &MessageHandler::onFileUploaded); - QObject::disconnect(network, &NetworkAccess::uploadFileError, mh, &MessageHandler::onFileUploadError); + QObject::disconnect(network, &NetworkAccess::uploadFileComplete, mh, &MessageHandler::onUploadFileComplete); + QObject::disconnect(network, &NetworkAccess::downloadFileComplete, mh, &MessageHandler::onDownloadFileComplete); + QObject::disconnect(network, &NetworkAccess::loadFileError, mh, &MessageHandler::onLoadFileError); delete mh; delete rh; @@ -549,9 +551,11 @@ void Core::Account::onClientError(QXmppClient::Error err) case QXmppStanza::Error::NotAuthorized: errorText = "Authentication error"; break; +#if (QXMPP_VERSION) < QT_VERSION_CHECK(1, 3, 0) case QXmppStanza::Error::PaymentRequired: errorText = "Payment is required"; break; +#endif case QXmppStanza::Error::RecipientUnavailable: errorText = "Recipient is unavailable"; break; diff --git a/core/account.h b/core/account.h index 1a46e24..8b0839b 100644 --- a/core/account.h +++ b/core/account.h @@ -133,7 +133,7 @@ signals: void removeRoomParticipant(const QString& jid, const QString& nickName); void receivedVCard(const QString& jid, const Shared::VCard& card); void uploadFile(const QFileInfo& file, const QUrl& set, const QUrl& get, QMap headers); - void uploadFileError(const QString& messageId, const QString& error); + void uploadFileError(const QString& jid, const QString& messageId, const QString& error); private: QString name; diff --git a/core/handlers/messagehandler.cpp b/core/handlers/messagehandler.cpp index a236f1e..51282eb 100644 --- a/core/handlers/messagehandler.cpp +++ b/core/handlers/messagehandler.cpp @@ -168,14 +168,16 @@ void Core::MessageHandler::initializeMessage(Shared::Message& target, const QXmp id = source.id(); #endif target.setId(id); - if (target.getId().size() == 0) { + QString messageId = target.getId(); + if (messageId.size() == 0) { target.generateRandomId(); //TODO out of desperation, I need at least a random ID + messageId = target.getId(); } target.setFrom(source.from()); target.setTo(source.to()); target.setBody(source.body()); target.setForwarded(forwarded); - target.setOutOfBandUrl(source.outOfBandUrl()); + if (guessing) { if (target.getFromJid() == acc->getLogin() + "@" + acc->getServer()) { outgoing = true; @@ -189,6 +191,12 @@ void Core::MessageHandler::initializeMessage(Shared::Message& target, const QXmp } else { target.setCurrentTime(); } + + QString oob = source.outOfBandUrl(); + if (oob.size() > 0) { + target.setAttachPath(acc->network->addMessageAndCheckForPath(oob, acc->getName(), target.getPenPalJid(), messageId)); + } + target.setOutOfBandUrl(oob); } void Core::MessageHandler::logMessage(const QXmppMessage& msg, const QString& reason) @@ -292,7 +300,7 @@ void Core::MessageHandler::prepareUpload(const Shared::Message& data) if (url.size() != 0) { sendMessageWithLocalUploadedFile(data, url); } else { - if (acc->network->isUploading(path, data.getId())) { + if (acc->network->checkAndAddToUploading(acc->getName(), data.getPenPalJid(), data.getId(), path)) { pendingMessages.emplace(data.getId(), data); } else { if (acc->um->serviceFound()) { @@ -303,17 +311,17 @@ void Core::MessageHandler::prepareUpload(const Shared::Message& data) acc->um->requestUploadSlot(file); } } else { - onFileUploadError(data.getId(), "Uploading file no longer exists or your system user has no permission to read it"); + handleUploadError(data.getPenPalJid(), data.getId(), "Uploading file no longer exists or your system user has no permission to read it"); qDebug() << "Requested upload slot in account" << acc->name << "for file" << path << "but the file doesn't exist or is not readable"; } } else { - onFileUploadError(data.getId(), "Your server doesn't support file upload service, or it's prohibited for your account"); + handleUploadError(data.getPenPalJid(), data.getId(), "Your server doesn't support file upload service, or it's prohibited for your account"); qDebug() << "Requested upload slot in account" << acc->name << "for file" << path << "but upload manager didn't discover any upload services"; } } } } else { - onFileUploadError(data.getId(), "Account is offline or reconnecting"); + handleUploadError(data.getPenPalJid(), data.getId(), "Account is offline or reconnecting"); qDebug() << "An attempt to send message with not connected account " << acc->name << ", skipping"; } } @@ -326,10 +334,10 @@ void Core::MessageHandler::onUploadSlotReceived(const QXmppHttpUploadSlotIq& slo } else { const std::pair& pair = uploadingSlotsQueue.front(); const QString& mId = pair.second.getId(); - acc->network->uploadFile(mId, pair.first, slot.putUrl(), slot.getUrl(), slot.putHeaders()); + acc->network->uploadFile({acc->name, pair.second.getPenPalJid(), mId}, pair.first, slot.putUrl(), slot.getUrl(), slot.putHeaders()); pendingMessages.emplace(mId, pair.second); - uploadingSlotsQueue.pop_front(); + uploadingSlotsQueue.pop_front(); if (uploadingSlotsQueue.size() > 0) { acc->um->requestUploadSlot(uploadingSlotsQueue.front().first); } @@ -338,35 +346,69 @@ void Core::MessageHandler::onUploadSlotReceived(const QXmppHttpUploadSlotIq& slo void Core::MessageHandler::onUploadSlotRequestFailed(const QXmppHttpUploadRequestIq& request) { + QString err(request.error().text()); if (uploadingSlotsQueue.size() == 0) { qDebug() << "HTTP Upload manager of account" << acc->name << "reports about an error requesting upload slot, but none was requested"; - qDebug() << request.error().text(); + qDebug() << err; } else { const std::pair& pair = uploadingSlotsQueue.front(); - qDebug() << "Error requesting upload slot for file" << pair.first << "in account" << acc->name << ":" << request.error().text(); - emit acc->uploadFileError(pair.second.getId(), "Error requesting slot to upload file: " + request.error().text()); + qDebug() << "Error requesting upload slot for file" << pair.first << "in account" << acc->name << ":" << err; + emit acc->uploadFileError(pair.second.getPenPalJid(), pair.second.getId(), "Error requesting slot to upload file: " + err); + uploadingSlotsQueue.pop_front(); if (uploadingSlotsQueue.size() > 0) { acc->um->requestUploadSlot(uploadingSlotsQueue.front().first); } - uploadingSlotsQueue.pop_front(); } } -void Core::MessageHandler::onFileUploaded(const QString& messageId, const QString& url) +void Core::MessageHandler::onDownloadFileComplete(const std::list& msgs, const QString& path) { - std::map::const_iterator itr = pendingMessages.find(messageId); - if (itr != pendingMessages.end()) { - sendMessageWithLocalUploadedFile(itr->second, url); - pendingMessages.erase(itr); + QMap cData = { + {"attachPath", path} + }; + for (const Shared::MessageInfo& info : msgs) { + if (info.account == acc->getName()) { + Contact* cnt = acc->rh->getContact(info.jid); + if (cnt != 0) { + if (cnt->changeMessage(info.messageId, cData)) { + emit acc->changeMessage(info.jid, info.messageId, cData); + } + } + } } } -void Core::MessageHandler::onFileUploadError(const QString& messageId, const QString& errMsg) +void Core::MessageHandler::onLoadFileError(const std::list& msgs, const QString& text, bool up) +{ + if (up) { + for (const Shared::MessageInfo& info : msgs) { + if (info.account == acc->getName()) { + handleUploadError(info.jid, info.messageId, text); + } + } + } +} + +void Core::MessageHandler::handleUploadError(const QString& jid, const QString& messageId, const QString& errorText) { std::map::const_iterator itr = pendingMessages.find(messageId); if (itr != pendingMessages.end()) { pendingMessages.erase(itr); + //TODO move the storage of pending messages to the database and change them there + } +} + +void Core::MessageHandler::onUploadFileComplete(const std::list& msgs, const QString& path) +{ + for (const Shared::MessageInfo& info : msgs) { + if (info.account == acc->getName()) { + std::map::const_iterator itr = pendingMessages.find(info.messageId); + if (itr != pendingMessages.end()) { + sendMessageWithLocalUploadedFile(itr->second, path); + pendingMessages.erase(itr); + } + } } } diff --git a/core/handlers/messagehandler.h b/core/handlers/messagehandler.h index 0b53cc2..8893921 100644 --- a/core/handlers/messagehandler.h +++ b/core/handlers/messagehandler.h @@ -28,6 +28,7 @@ #include #include +#include namespace Core { @@ -54,8 +55,9 @@ public slots: void onReceiptReceived(const QString& jid, const QString& id); void onUploadSlotReceived(const QXmppHttpUploadSlotIq& slot); void onUploadSlotRequestFailed(const QXmppHttpUploadRequestIq& request); - void onFileUploaded(const QString& messageId, const QString& url); - void onFileUploadError(const QString& messageId, const QString& errMsg); + void onDownloadFileComplete(const std::list& msgs, const QString& path); + void onUploadFileComplete(const std::list& msgs, const QString& path); + void onLoadFileError(const std::list& msgs, const QString& path, bool up); private: bool handleChatMessage(const QXmppMessage& msg, bool outgoing = false, bool forwarded = false, bool guessing = false); @@ -64,6 +66,7 @@ private: void sendMessageWithLocalUploadedFile(Shared::Message msg, const QString& url); void performSending(Shared::Message data); void prepareUpload(const Shared::Message& data); + void handleUploadError(const QString& jid, const QString& messageId, const QString& errorText); private: Account* acc; diff --git a/core/networkaccess.cpp b/core/networkaccess.cpp index 2d66a70..60d7cb9 100644 --- a/core/networkaccess.cpp +++ b/core/networkaccess.cpp @@ -16,13 +16,17 @@ * along with this program. If not, see . */ + +#include +#include + #include "networkaccess.h" Core::NetworkAccess::NetworkAccess(QObject* parent): QObject(parent), running(false), manager(0), - files("files"), + storage("fileURLStorage"), downloads(), uploads() { @@ -33,60 +37,31 @@ Core::NetworkAccess::~NetworkAccess() stop(); } -void Core::NetworkAccess::fileLocalPathRequest(const QString& messageId, const QString& url) +void Core::NetworkAccess::downladFile(const QString& url) { std::map::iterator itr = downloads.find(url); if (itr != downloads.end()) { - Transfer* dwn = itr->second; - std::set::const_iterator mItr = dwn->messages.find(messageId); - if (mItr == dwn->messages.end()) { - dwn->messages.insert(messageId); - } - emit downloadFileProgress(messageId, dwn->progress); + qDebug() << "NetworkAccess received a request to download a file" << url << ", but the file is currently downloading, skipping"; } else { try { - QString path = files.getRecord(url); - QFileInfo info(path); - if (info.exists() && info.isFile()) { - emit fileLocalPathResponse(messageId, path); + std::pair> p = storage.getPath(url); + if (p.first.size() > 0) { + QFileInfo info(p.first); + if (info.exists() && info.isFile()) { + emit downloadFileComplete(p.second, p.first); + } else { + startDownload(p.second, url); + } } else { - files.removeRecord(url); - emit fileLocalPathResponse(messageId, ""); + startDownload(p.second, url); } } catch (const Archive::NotFound& e) { - emit fileLocalPathResponse(messageId, ""); + qDebug() << "NetworkAccess received a request to download a file" << url << ", but there is now record of which message uses that file, downloading anyway"; + storage.addFile(url); + startDownload(std::list(), url); } catch (const Archive::Unknown& e) { qDebug() << "Error requesting file path:" << e.what(); - emit fileLocalPathResponse(messageId, ""); - } - } -} - -void Core::NetworkAccess::downladFileRequest(const QString& messageId, const QString& url) -{ - std::map::iterator itr = downloads.find(url); - if (itr != downloads.end()) { - Transfer* dwn = itr->second; - std::set::const_iterator mItr = dwn->messages.find(messageId); - if (mItr == dwn->messages.end()) { - dwn->messages.insert(messageId); - } - emit downloadFileProgress(messageId, dwn->progress); - } else { - try { - QString path = files.getRecord(url); - QFileInfo info(path); - if (info.exists() && info.isFile()) { - emit fileLocalPathResponse(messageId, path); - } else { - files.removeRecord(url); - startDownload(messageId, url); - } - } catch (const Archive::NotFound& e) { - startDownload(messageId, url); - } catch (const Archive::Unknown& e) { - qDebug() << "Error requesting file path:" << e.what(); - emit downloadFileError(messageId, QString("Database error: ") + e.what()); + emit loadFileError(std::list(), QString("Database error: ") + e.what(), false); } } } @@ -95,7 +70,7 @@ void Core::NetworkAccess::start() { if (!running) { manager = new QNetworkAccessManager(); - files.open(); + storage.open(); running = true; } } @@ -103,7 +78,7 @@ void Core::NetworkAccess::start() void Core::NetworkAccess::stop() { if (running) { - files.close(); + storage.close(); manager->deleteLater(); manager = 0; running = false; @@ -128,9 +103,7 @@ void Core::NetworkAccess::onDownloadProgress(qint64 bytesReceived, qint64 bytesT qreal total = bytesTotal; qreal progress = received/total; dwn->progress = progress; - for (std::set::const_iterator mItr = dwn->messages.begin(), end = dwn->messages.end(); mItr != end; ++mItr) { - emit downloadFileProgress(*mItr, progress); - } + emit loadFileProgress(dwn->messages, progress, false); } } @@ -146,9 +119,7 @@ void Core::NetworkAccess::onDownloadError(QNetworkReply::NetworkError code) if (errorText.size() > 0) { itr->second->success = false; Transfer* dwn = itr->second; - for (std::set::const_iterator mItr = dwn->messages.begin(), end = dwn->messages.end(); mItr != end; ++mItr) { - emit downloadFileError(*mItr, errorText); - } + emit loadFileError(dwn->messages, errorText, false); } } } @@ -276,61 +247,54 @@ QString Core::NetworkAccess::getErrorText(QNetworkReply::NetworkError code) void Core::NetworkAccess::onDownloadFinished() { - QString path(""); QNetworkReply* rpl = static_cast(sender()); QString url = rpl->url().toString(); std::map::const_iterator itr = downloads.find(url); if (itr == downloads.end()) { - qDebug() << "an error downloading" << url << ": the request is done but seems like noone is waiting for it, skipping"; + qDebug() << "an error downloading" << url << ": the request is done but there is no record of it being downloaded, ignoring"; } else { Transfer* dwn = itr->second; if (dwn->success) { qDebug() << "download success for" << url; QStringList hops = url.split("/"); QString fileName = hops.back(); - QStringList parts = fileName.split("."); - path = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation) + "/"; - QString suffix(""); - QStringList::const_iterator sItr = parts.begin(); - QString realName = *sItr; - ++sItr; - for (QStringList::const_iterator sEnd = parts.end(); sItr != sEnd; ++sItr) { - suffix += "." + (*sItr); + QString jid; + if (dwn->messages.size() > 0) { + jid = dwn->messages.front().jid; } - QString postfix(""); - QFileInfo proposedName(path + realName + postfix + suffix); - int counter = 0; - while (proposedName.exists()) { - postfix = QString("(") + std::to_string(++counter).c_str() + ")"; - proposedName = QFileInfo(path + realName + postfix + suffix); + QString path = prepareDirectory(jid); + if (path.size() > 0) { + path = checkFileName(fileName, path); + + QFile file(path); + if (file.open(QIODevice::WriteOnly)) { + file.write(dwn->reply->readAll()); + file.close(); + storage.setPath(url, path); + qDebug() << "file" << path << "was successfully downloaded"; + } else { + qDebug() << "couldn't save file" << path; + path = QString(); + } } - path = proposedName.absoluteFilePath(); - QFile file(path); - if (file.open(QIODevice::WriteOnly)) { - file.write(dwn->reply->readAll()); - file.close(); - files.addRecord(url, path); - qDebug() << "file" << path << "was successfully downloaded"; + if (path.size() > 0) { + emit downloadFileComplete(dwn->messages, path); } else { - qDebug() << "couldn't save file" << path; - path = ""; + //TODO do I need to handle the failure here or it's already being handled in error? + //emit loadFileError(dwn->messages, path, false); } } - for (std::set::const_iterator mItr = dwn->messages.begin(), end = dwn->messages.end(); mItr != end; ++mItr) { - emit fileLocalPathResponse(*mItr, path); - } - dwn->reply->deleteLater(); delete dwn; downloads.erase(itr); } } -void Core::NetworkAccess::startDownload(const QString& messageId, const QString& url) +void Core::NetworkAccess::startDownload(const std::list& msgs, const QString& url) { - Transfer* dwn = new Transfer({{messageId}, 0, 0, true, "", url, 0}); + Transfer* dwn = new Transfer({msgs, 0, 0, true, "", url, 0}); QNetworkRequest req(url); dwn->reply = manager->get(req); connect(dwn->reply, &QNetworkReply::downloadProgress, this, &NetworkAccess::onDownloadProgress); @@ -341,7 +305,7 @@ void Core::NetworkAccess::startDownload(const QString& messageId, const QString& #endif connect(dwn->reply, &QNetworkReply::finished, this, &NetworkAccess::onDownloadFinished); downloads.insert(std::make_pair(url, dwn)); - emit downloadFileProgress(messageId, 0); + emit loadFileProgress(dwn->messages, 0, false); } void Core::NetworkAccess::onUploadError(QNetworkReply::NetworkError code) @@ -350,16 +314,16 @@ void Core::NetworkAccess::onUploadError(QNetworkReply::NetworkError code) QString url = rpl->url().toString(); std::map::const_iterator itr = uploads.find(url); if (itr == uploads.end()) { - qDebug() << "an error uploading" << url << ": the request is reporting an error but seems like noone is waiting for it, skipping"; + qDebug() << "an error uploading" << url << ": the request is reporting an error but there is no record of it being uploading, ignoring"; } else { QString errorText = getErrorText(code); if (errorText.size() > 0) { itr->second->success = false; Transfer* upl = itr->second; - for (std::set::const_iterator mItr = upl->messages.begin(), end = upl->messages.end(); mItr != end; ++mItr) { - emit uploadFileError(*mItr, errorText); - } + emit loadFileError(upl->messages, errorText, true); } + + //TODO deletion? } } @@ -369,17 +333,14 @@ void Core::NetworkAccess::onUploadFinished() QString url = rpl->url().toString(); std::map::const_iterator itr = uploads.find(url); if (itr == downloads.end()) { - qDebug() << "an error uploading" << url << ": the request is done but seems like no one is waiting for it, skipping"; + qDebug() << "an error uploading" << url << ": the request is done there is no record of it being uploading, ignoring"; } else { Transfer* upl = itr->second; if (upl->success) { qDebug() << "upload success for" << url; - files.addRecord(upl->url, upl->path); - - for (std::set::const_iterator mItr = upl->messages.begin(), end = upl->messages.end(); mItr != end; ++mItr) { - emit fileLocalPathResponse(*mItr, upl->path); - emit uploadFileComplete(*mItr, upl->url); - } + + storage.addFile(upl->messages, upl->url, upl->path); + emit uploadFileComplete(upl->messages, upl->url); } upl->reply->deleteLater(); @@ -403,94 +364,29 @@ void Core::NetworkAccess::onUploadProgress(qint64 bytesReceived, qint64 bytesTot qreal total = bytesTotal; qreal progress = received/total; upl->progress = progress; - for (std::set::const_iterator mItr = upl->messages.begin(), end = upl->messages.end(); mItr != end; ++mItr) { - emit uploadFileProgress(*mItr, progress); - } - } -} - -void Core::NetworkAccess::startUpload(const QString& messageId, const QString& url, const QString& path) -{ - Transfer* upl = new Transfer({{messageId}, 0, 0, true, path, url, 0}); - QNetworkRequest req(url); - QFile* file = new QFile(path); - if (file->open(QIODevice::ReadOnly)) { - upl->reply = manager->put(req, file); - - connect(upl->reply, &QNetworkReply::uploadProgress, this, &NetworkAccess::onUploadProgress); -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) - connect(upl->reply, qOverload(&QNetworkReply::errorOccurred), this, &NetworkAccess::onUploadError); -#else - connect(upl->reply, qOverload(&QNetworkReply::error), this, &NetworkAccess::onUploadError); -#endif - - connect(upl->reply, &QNetworkReply::finished, this, &NetworkAccess::onUploadFinished); - uploads.insert(std::make_pair(url, upl)); - emit downloadFileProgress(messageId, 0); - } else { - qDebug() << "couldn't upload file" << path; - emit uploadFileError(messageId, "Error opening file"); - delete file; - } -} - -void Core::NetworkAccess::uploadFileRequest(const QString& messageId, const QString& url, const QString& path) -{ - std::map::iterator itr = uploads.find(url); - if (itr != uploads.end()) { - Transfer* upl = itr->second; - std::set::const_iterator mItr = upl->messages.find(messageId); - if (mItr == upl->messages.end()) { - upl->messages.insert(messageId); - } - emit uploadFileProgress(messageId, upl->progress); - } else { - try { - QString ePath = files.getRecord(url); - if (ePath == path) { - QFileInfo info(path); - if (info.exists() && info.isFile()) { - emit fileLocalPathResponse(messageId, path); - } else { - files.removeRecord(url); - startUpload(messageId, url, path); - } - } else { - QFileInfo info(path); - if (info.exists() && info.isFile()) { - files.changeRecord(url, path); - emit fileLocalPathResponse(messageId, path); - } else { - files.removeRecord(url); - startUpload(messageId, url, path); - } - } - } catch (const Archive::NotFound& e) { - startUpload(messageId, url, path); - } catch (const Archive::Unknown& e) { - qDebug() << "Error requesting file path on upload:" << e.what(); - emit uploadFileError(messageId, QString("Database error: ") + e.what()); - } + emit loadFileProgress(upl->messages, progress, true); } } QString Core::NetworkAccess::getFileRemoteUrl(const QString& path) { - return ""; //TODO this is a way not to upload some file more then 1 time, here I'm supposed to return that file GET url + QString p; + + try { + QString p = storage.getUrl(path); + } catch (const Archive::NotFound& err) { + + } catch (...) { + throw; + } + + return p; } -bool Core::NetworkAccess::isUploading(const QString& path, const QString& messageId) -{ - return false; //TODO this is a way to avoid parallel uploading of the same files by different chats - // message is is supposed to be added to the uploading messageids list - // the result should be true if there was an uploading file with this path - // message id can be empty, then it's just to check and not to add -} - -void Core::NetworkAccess::uploadFile(const QString& messageId, const QString& path, const QUrl& put, const QUrl& get, const QMap headers) +void Core::NetworkAccess::uploadFile(const Shared::MessageInfo& info, const QString& path, const QUrl& put, const QUrl& get, const QMap headers) { QFile* file = new QFile(path); - Transfer* upl = new Transfer({{messageId}, 0, 0, true, path, get.toString(), file}); + Transfer* upl = new Transfer({{info}, 0, 0, true, path, get.toString(), file}); QNetworkRequest req(put); for (QMap::const_iterator itr = headers.begin(), end = headers.end(); itr != end; itr++) { req.setRawHeader(itr.key().toUtf8(), itr.value().toUtf8()); @@ -506,10 +402,94 @@ void Core::NetworkAccess::uploadFile(const QString& messageId, const QString& pa #endif connect(upl->reply, &QNetworkReply::finished, this, &NetworkAccess::onUploadFinished); uploads.insert(std::make_pair(put.toString(), upl)); - emit downloadFileProgress(messageId, 0); + emit loadFileProgress(upl->messages, 0, true); } else { qDebug() << "couldn't upload file" << path; - emit uploadFileError(messageId, "Error opening file"); + emit loadFileError(upl->messages, "Error opening file", true); delete file; + delete upl; } } + +void Core::NetworkAccess::registerFile(const QString& url, const QString& account, const QString& jid, const QString& id) +{ + storage.addFile(url, account, jid, id); + std::map::iterator itr = downloads.find(url); + if (itr != downloads.end()) { + itr->second->messages.emplace_back(account, jid, id); //TODO notification is going to happen the next tick, is that okay? + } +} + +void Core::NetworkAccess::registerFile(const QString& url, const QString& path, const QString& account, const QString& jid, const QString& id) +{ + storage.addFile(url, path, account, jid, id); +} + +bool Core::NetworkAccess::checkAndAddToUploading(const QString& acc, const QString& jid, const QString id, const QString path) +{ + for (const std::pair& pair : uploads) { + Transfer* info = pair.second; + if (pair.second->path == path) { + std::list& messages = info->messages; + bool dup = false; + for (const Shared::MessageInfo& info : messages) { + if (info.account == acc && info.jid == jid && info.messageId == id) { + dup = true; + break; + } + } + if (!dup) { + info->messages.emplace_back(acc, jid, id); //TODO notification is going to happen the next tick, is that okay? + return true; + } + } + } + + return false; +} + +QString Core::NetworkAccess::prepareDirectory(const QString& jid) +{ + QString path = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); + path += "/" + QApplication::applicationName(); + if (jid.size() > 0) { + path += "/" + jid; + } + QDir location(path); + + if (!location.exists()) { + bool res = location.mkpath(path); + if (!res) { + return ""; + } else { + return path; + } + } + return path; +} + +QString Core::NetworkAccess::checkFileName(const QString& name, const QString& path) +{ + QStringList parts = name.split("."); + QString suffix(""); + QStringList::const_iterator sItr = parts.begin(); + QString realName = *sItr; + ++sItr; + for (QStringList::const_iterator sEnd = parts.end(); sItr != sEnd; ++sItr) { + suffix += "." + (*sItr); + } + QString postfix(""); + QFileInfo proposedName(path + realName + suffix); + int counter = 0; + while (proposedName.exists()) { + QString count = QString("(") + std::to_string(++counter).c_str() + ")"; + proposedName = QFileInfo(path + realName + count + suffix); + } + + return proposedName.absoluteFilePath(); +} + +QString Core::NetworkAccess::addMessageAndCheckForPath(const QString& url, const QString& account, const QString& jid, const QString& id) +{ + return storage.addMessageAndCheckForPath(url, account, jid, id); +} diff --git a/core/networkaccess.h b/core/networkaccess.h index c931393..a116e6d 100644 --- a/core/networkaccess.h +++ b/core/networkaccess.h @@ -36,6 +36,8 @@ namespace Core { /** * @todo write docs */ + +//TODO Need to describe how to get rid of records when file is no longer reachable; class NetworkAccess : public QObject { Q_OBJECT @@ -48,26 +50,26 @@ public: void stop(); QString getFileRemoteUrl(const QString& path); - bool isUploading(const QString& path, const QString& messageId = ""); - void uploadFile(const QString& messageId, const QString& path, const QUrl& put, const QUrl& get, const QMap headers); + QString addMessageAndCheckForPath(const QString& url, const QString& account, const QString& jid, const QString& id); + void uploadFile(const Shared::MessageInfo& info, const QString& path, const QUrl& put, const QUrl& get, const QMap headers); + bool checkAndAddToUploading(const QString& acc, const QString& jid, const QString id, const QString path); signals: - void fileLocalPathResponse(const QString& messageId, const QString& path); - void downloadFileProgress(const QString& messageId, qreal value); - void downloadFileError(const QString& messageId, const QString& path); - void uploadFileProgress(const QString& messageId, qreal value); - void uploadFileError(const QString& messageId, const QString& path); - void uploadFileComplete(const QString& messageId, const QString& url); + void loadFileProgress(const std::list& msgs, qreal value, bool up); + void loadFileError(const std::list& msgs, const QString& text, bool up); + void uploadFileComplete(const std::list& msgs, const QString& url); + void downloadFileComplete(const std::list& msgs, const QString& path); public slots: - void fileLocalPathRequest(const QString& messageId, const QString& url); - void downladFileRequest(const QString& messageId, const QString& url); - void uploadFileRequest(const QString& messageId, const QString& url, const QString& path); + void downladFile(const QString& url); + void registerFile(const QString& url, const QString& account, const QString& jid, const QString& id); + void registerFile(const QString& url, const QString& path, const QString& account, const QString& jid, const QString& id); private: - void startDownload(const QString& messageId, const QString& url); - void startUpload(const QString& messageId, const QString& url, const QString& path); + void startDownload(const std::list& msgs, const QString& url); QString getErrorText(QNetworkReply::NetworkError code); + QString prepareDirectory(const QString& jid); + QString checkFileName(const QString& name, const QString& path); private slots: void onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal); @@ -85,7 +87,7 @@ private: std::map uploads; struct Transfer { - std::set messages; + std::list messages; qreal progress; QNetworkReply* reply; bool success; diff --git a/core/squawk.cpp b/core/squawk.cpp index a64d418..83fedb6 100644 --- a/core/squawk.cpp +++ b/core/squawk.cpp @@ -32,11 +32,10 @@ Core::Squawk::Squawk(QObject* parent): ,kwallet() #endif { - connect(&network, &NetworkAccess::fileLocalPathResponse, this, &Squawk::onNetworkAccessfileLocalPathResponse); - connect(&network, &NetworkAccess::downloadFileProgress, this, &Squawk::downloadFileProgress); - connect(&network, &NetworkAccess::downloadFileError, this, &Squawk::downloadFileError); - connect(&network, &NetworkAccess::uploadFileProgress, this, &Squawk::uploadFileProgress); - connect(&network, &NetworkAccess::uploadFileError, this, &Squawk::uploadFileError); + connect(&network, &NetworkAccess::loadFileProgress, this, &Squawk::fileProgress); + connect(&network, &NetworkAccess::loadFileError, this, &Squawk::fileError); + connect(&network, &NetworkAccess::downloadFileComplete, this, &Squawk::fileDownloadComplete); + connect(&network, &NetworkAccess::uploadFileComplete, this, &Squawk::fileUploadComplete); #ifdef WITH_KWALLET if (kwallet.supportState() == PSE::KWallet::success) { @@ -168,7 +167,7 @@ void Core::Squawk::addAccount( connect(acc, &Account::receivedVCard, this, &Squawk::responseVCard); - connect(acc, &Account::uploadFileError, this, &Squawk::uploadFileError); + connect(acc, &Account::uploadFileError, this, &Squawk::onAccountUploadFileError); QMap map = { {"login", login}, @@ -593,14 +592,9 @@ void Core::Squawk::addRoomRequest(const QString& account, const QString& jid, co itr->second->addRoomRequest(jid, nick, password, autoJoin); } -void Core::Squawk::fileLocalPathRequest(const QString& messageId, const QString& url) +void Core::Squawk::fileDownloadRequest(const QString& url) { - network.fileLocalPathRequest(messageId, url); -} - -void Core::Squawk::downloadFileRequest(const QString& messageId, const QString& url) -{ - network.downladFileRequest(messageId, url); + network.downladFile(url); } void Core::Squawk::addContactToGroupRequest(const QString& account, const QString& jid, const QString& groupName) @@ -752,7 +746,8 @@ void Core::Squawk::onWalletResponsePassword(const QString& login, const QString& accountReady(); } -void Core::Squawk::onNetworkAccessfileLocalPathResponse(const QString& messageId, const QString& path) +void Core::Squawk::onAccountUploadFileError(const QString& jid, const QString id, const QString& errorText) { - + Account* acc = static_cast(sender()); + emit fileError({{acc->getName(), jid, id}}, errorText, true); } diff --git a/core/squawk.h b/core/squawk.h index 4b6fbea..36301d8 100644 --- a/core/squawk.h +++ b/core/squawk.h @@ -51,30 +51,39 @@ public: signals: void quit(); void ready(); + void newAccount(const QMap&); void changeAccount(const QString& account, const QMap& data); void removeAccount(const QString& account); + void addGroup(const QString& account, const QString& name); void removeGroup(const QString& account, const QString& name); + void addContact(const QString& account, const QString& jid, const QString& group, const QMap& data); void removeContact(const QString& account, const QString& jid); void removeContact(const QString& account, const QString& jid, const QString& group); void changeContact(const QString& account, const QString& jid, const QMap& data); + void addPresence(const QString& account, const QString& jid, const QString& name, const QMap& data); void removePresence(const QString& account, const QString& jid, const QString& name); + void stateChanged(Shared::Availability state); + void accountMessage(const QString& account, const Shared::Message& data); void responseArchive(const QString& account, const QString& jid, const std::list& list, bool last); + void addRoom(const QString& account, const QString jid, const QMap& data); void changeRoom(const QString& account, const QString jid, const QMap& data); void removeRoom(const QString& account, const QString jid); void addRoomParticipant(const QString& account, const QString& jid, const QString& name, const QMap& data); void changeRoomParticipant(const QString& account, const QString& jid, const QString& name, const QMap& data); void removeRoomParticipant(const QString& account, const QString& jid, const QString& name); - void downloadFileError(const QString& messageId, const QString& error); - void downloadFileProgress(const QString& messageId, qreal value); - void uploadFileError(const QString& messageId, const QString& error); - void uploadFileProgress(const QString& messageId, qreal value); + + void fileError(const std::list msgs, const QString& error, bool up); + void fileProgress(const std::list msgs, qreal value, bool up); + void fileDownloadComplete(const std::list msgs, const QString& path); + void fileUploadComplete(const std::list msgs, const QString& path); + void responseVCard(const QString& jid, const Shared::VCard& card); void changeMessage(const QString& account, const QString& jid, const QString& id, const QMap& data); void requestPassword(const QString& account); @@ -82,14 +91,18 @@ signals: public slots: void start(); void stop(); + void newAccountRequest(const QMap& map); void modifyAccountRequest(const QString& name, const QMap& map); void removeAccountRequest(const QString& name); void connectAccount(const QString& account); void disconnectAccount(const QString& account); + void changeState(Shared::Availability state); + void sendMessage(const QString& account, const Shared::Message& data); void requestArchive(const QString& account, const QString& jid, int count, const QString& before); + void subscribeContact(const QString& account, const QString& jid, const QString& reason); void unsubscribeContact(const QString& account, const QString& jid, const QString& reason); void addContactToGroupRequest(const QString& account, const QString& jid, const QString& groupName); @@ -97,12 +110,14 @@ public slots: void removeContactRequest(const QString& account, const QString& jid); void renameContactRequest(const QString& account, const QString& jid, const QString& newName); void addContactRequest(const QString& account, const QString& jid, const QString& name, const QSet& groups); + void setRoomJoined(const QString& account, const QString& jid, bool joined); void setRoomAutoJoin(const QString& account, const QString& jid, bool joined); void addRoomRequest(const QString& account, const QString& jid, const QString& nick, const QString& password, bool autoJoin); void removeRoomRequest(const QString& account, const QString& jid); - void fileLocalPathRequest(const QString& messageId, const QString& url); - void downloadFileRequest(const QString& messageId, const QString& url); + + void fileDownloadRequest(const QString& url); + void requestVCard(const QString& account, const QString& jid); void uploadVCard(const QString& account, const Shared::VCard& card); void responsePassword(const QString& account, const QString& password); @@ -153,12 +168,12 @@ private slots: void onAccountRemoveRoomPresence(const QString& jid, const QString& nick); void onAccountChangeMessage(const QString& jid, const QString& id, const QMap& data); + void onAccountUploadFileError(const QString& jid, const QString id, const QString& errorText); + void onWalletOpened(bool success); void onWalletResponsePassword(const QString& login, const QString& password); void onWalletRejectPassword(const QString& login); - void onNetworkAccessfileLocalPathResponse(const QString& messageId, const QString& path); - private: void readSettings(); void accountReady(); diff --git a/core/urlstorage.cpp b/core/urlstorage.cpp index a8a9179..1ce7957 100644 --- a/core/urlstorage.cpp +++ b/core/urlstorage.cpp @@ -165,8 +165,7 @@ void Core::UrlStorage::addFile(const QString& url) throw Archive::Closed("addFile(no message, no path)", name.toStdString()); } - UrlInfo info; - writeInfo(url, info); + addToInfo(url, "", "", ""); } void Core::UrlStorage::addFile(const QString& url, const QString& path) @@ -175,8 +174,7 @@ void Core::UrlStorage::addFile(const QString& url, const QString& path) throw Archive::Closed("addFile(no message, with path)", name.toStdString()); } - UrlInfo info(path); - writeInfo(url, info); + addToInfo(url, "", "", "", path); } void Core::UrlStorage::addFile(const QString& url, const QString& account, const QString& jid, const QString& id) @@ -185,9 +183,7 @@ void Core::UrlStorage::addFile(const QString& url, const QString& account, const throw Archive::Closed("addFile(with message, no path)", name.toStdString()); } - UrlInfo info; - info.addMessage(account, jid, id); - writeInfo(url, info); + addToInfo(url, account, jid, id); } void Core::UrlStorage::addFile(const QString& url, const QString& path, const QString& account, const QString& jid, const QString& id) @@ -196,50 +192,74 @@ void Core::UrlStorage::addFile(const QString& url, const QString& path, const QS throw Archive::Closed("addFile(with message, with path)", name.toStdString()); } - UrlInfo info(path); - info.addMessage(account, jid, id); - writeInfo(url, info); + addToInfo(url, account, jid, id, path); +} + +void Core::UrlStorage::addFile(const std::list& msgs, const QString& url, const QString& path) +{ + if (!opened) { + throw Archive::Closed("addFile(with list)", name.toStdString()); + } + + UrlInfo info (path, msgs); + writeInfo(url, info, true);; } QString Core::UrlStorage::addMessageAndCheckForPath(const QString& url, const QString& account, const QString& jid, const QString& id) { - QString path; + if (!opened) { + throw Archive::Closed("addMessageAndCheckForPath", name.toStdString()); + } + return addToInfo(url, account, jid, id).getPath(); +} + +Core::UrlStorage::UrlInfo Core::UrlStorage::addToInfo(const QString& url, const QString& account, const QString& jid, const QString& id, const QString& path) +{ + UrlInfo info; MDB_txn *txn; mdb_txn_begin(environment, NULL, 0, &txn); - UrlInfo info; try { readInfo(url, info, txn); - path = info.getPath(); - info.addMessage(account, jid, id); - try { - writeInfo(url, info, txn, true); - mdb_txn_commit(txn); - } catch (...) { - mdb_txn_abort(txn); - throw; - } } catch (const Archive::NotFound& e) { - info.addMessage(account, jid, id); - try { - writeInfo(url, info, txn, true); - mdb_txn_commit(txn); - } catch (...) { - mdb_txn_abort(txn); - throw; - } + } catch (...) { mdb_txn_abort(txn); throw; } - return path; + bool pathChange = false; + bool listChange = false; + if (path != "-s") { + if (info.getPath() != path) { + info.setPath(path); + pathChange = true; + } + } + + if (account.size() > 0 && jid.size() > 0 && id.size() > 0) { + listChange = info.addMessage(account, jid, id); + } + + if (pathChange || listChange) { + try { + writeInfo(url, info, txn, true); + mdb_txn_commit(txn); + } catch (...) { + mdb_txn_abort(txn); + throw; + } + } else { + mdb_txn_abort(txn); + } + + return info; } -std::list Core::UrlStorage::setPath(const QString& url, const QString& path) +std::list Core::UrlStorage::setPath(const QString& url, const QString& path) { - std::list list; + std::list list; MDB_txn *txn; mdb_txn_begin(environment, NULL, 0, &txn); @@ -247,24 +267,17 @@ std::list Core::UrlStorage::setPath(const QString try { readInfo(url, info, txn); - info.setPath(path); info.getMessages(list); - try { - writeInfo(url, info, txn, true); - mdb_txn_commit(txn); - } catch (...) { - mdb_txn_abort(txn); - throw; - } } catch (const Archive::NotFound& e) { - info.setPath(path); - try { - writeInfo(url, info, txn, true); - mdb_txn_commit(txn); - } catch (...) { - mdb_txn_abort(txn); - throw; - } + } catch (...) { + mdb_txn_abort(txn); + throw; + } + + info.setPath(path); + try { + writeInfo(url, info, txn, true); + mdb_txn_commit(txn); } catch (...) { mdb_txn_abort(txn); throw; @@ -273,9 +286,9 @@ std::list Core::UrlStorage::setPath(const QString return list; } -std::list Core::UrlStorage::removeFile(const QString& url) +std::list Core::UrlStorage::removeFile(const QString& url) { - std::list list; + std::list list; MDB_txn *txn; mdb_txn_begin(environment, NULL, 0, &txn); @@ -313,9 +326,9 @@ std::list Core::UrlStorage::removeFile(const QStr return list; } -std::list Core::UrlStorage::deletedFile(const QString& path) +std::list Core::UrlStorage::deletedFile(const QString& path) { - std::list list; + std::list list; MDB_txn *txn; mdb_txn_begin(environment, NULL, 0, &txn); @@ -362,6 +375,46 @@ std::list Core::UrlStorage::deletedFile(const QSt } +QString Core::UrlStorage::getUrl(const QString& path) +{ + std::list list; + + MDB_txn *txn; + mdb_txn_begin(environment, NULL, MDB_RDONLY, &txn); + + std::string spath = path.toStdString(); + + MDB_val lmdbKey, lmdbData; + lmdbKey.mv_size = spath.size(); + lmdbKey.mv_data = (char*)spath.c_str(); + + QString url; + int rc = mdb_get(txn, map, &lmdbKey, &lmdbData); + + if (rc == 0) { + std::string surl((char*)lmdbData.mv_data, lmdbData.mv_size); + url = QString(surl.c_str()); + + mdb_txn_abort(txn); + return url; + } else if (rc == MDB_NOTFOUND) { + mdb_txn_abort(txn); + throw Archive::NotFound(spath, name.toStdString()); + } else { + mdb_txn_abort(txn); + throw Archive::Unknown(name.toStdString(), mdb_strerror(rc)); + } +} + +std::pair> Core::UrlStorage::getPath(const QString& url) +{ + UrlInfo info; + readInfo(url, info); + std::list container; + info.getMessages(container); + return std::make_pair(info.getPath(), container); +} + Core::UrlStorage::UrlInfo::UrlInfo(): localPath(), messages() {} @@ -370,19 +423,29 @@ Core::UrlStorage::UrlInfo::UrlInfo(const QString& path): localPath(path), messages() {} +Core::UrlStorage::UrlInfo::UrlInfo(const QString& path, const std::list& msgs): + localPath(path), + messages(msgs) {} + Core::UrlStorage::UrlInfo::~UrlInfo() {} -void Core::UrlStorage::UrlInfo::addMessage(const QString& acc, const QString& jid, const QString& id) +bool Core::UrlStorage::UrlInfo::addMessage(const QString& acc, const QString& jid, const QString& id) { + for (const Shared::MessageInfo& info : messages) { + if (info.account == acc && info.jid == jid && info.messageId == id) { + return false; + } + } messages.emplace_back(acc, jid, id); + return true; } void Core::UrlStorage::UrlInfo::serialize(QDataStream& data) const { data << localPath; - std::list::size_type size = messages.size(); + std::list::size_type size = messages.size(); data << quint32(size); - for (const MessageInfo& info : messages) { + for (const Shared::MessageInfo& info : messages) { data << info.account; data << info.jid; data << info.messageId; @@ -396,16 +459,18 @@ void Core::UrlStorage::UrlInfo::deserialize(QDataStream& data) data >> size; for (quint32 i = 0; i < size; ++i) { messages.emplace_back(); - MessageInfo& info = messages.back(); + Shared::MessageInfo& info = messages.back(); data >> info.account; data >> info.jid; data >> info.messageId; } } -void Core::UrlStorage::UrlInfo::getMessages(std::list& container) const +void Core::UrlStorage::UrlInfo::getMessages(std::list& container) const { - std::copy(messages.begin(), messages.end(), container.end()); + for (const Shared::MessageInfo& info : messages) { + container.emplace_back(info); + } } QString Core::UrlStorage::UrlInfo::getPath() const @@ -423,13 +488,3 @@ void Core::UrlStorage::UrlInfo::setPath(const QString& path) { localPath = path; } - -Core::UrlStorage::MessageInfo::MessageInfo(): - account(), - jid(), - messageId() {} - -Core::UrlStorage::MessageInfo::MessageInfo(const QString& acc, const QString& j, const QString& id): - account(acc), - jid(j), - messageId(id) {} diff --git a/core/urlstorage.h b/core/urlstorage.h index 17adfdd..3dc5c21 100644 --- a/core/urlstorage.h +++ b/core/urlstorage.h @@ -25,6 +25,7 @@ #include #include "archive.h" +#include namespace Core { @@ -35,15 +36,6 @@ class UrlStorage { class UrlInfo; public: - struct MessageInfo { - MessageInfo(); - MessageInfo(const QString& acc, const QString& j, const QString& id); - - QString account; - QString jid; - QString messageId; - }; - UrlStorage(const QString& name); ~UrlStorage(); @@ -54,10 +46,13 @@ public: void addFile(const QString& url, const QString& path); void addFile(const QString& url, const QString& account, const QString& jid, const QString& id); void addFile(const QString& url, const QString& path, const QString& account, const QString& jid, const QString& id); - std::list removeFile(const QString& url); //removes entry like it never was in the database, returns affected message infos - std::list deletedFile(const QString& path); //empties the localPath of the entry, returns affected message infos - std::list setPath(const QString& url, const QString& path); + void addFile(const std::list& msgs, const QString& url, const QString& path); //this one overwrites all that was + std::list removeFile(const QString& url); //removes entry like it never was in the database, returns affected message infos + std::list deletedFile(const QString& path); //empties the localPath of the entry, returns affected message infos + std::list setPath(const QString& url, const QString& path); + QString getUrl(const QString& path); QString addMessageAndCheckForPath(const QString& url, const QString& account, const QString& jid, const QString& id); + std::pair> getPath(const QString& url); private: QString name; @@ -71,11 +66,13 @@ private: void writeInfo(const QString& key, const UrlInfo& info, MDB_txn* txn, bool overwrite = false); void readInfo(const QString& key, UrlInfo& info); void readInfo(const QString& key, UrlInfo& info, MDB_txn* txn); + UrlInfo addToInfo(const QString& url, const QString& account, const QString& jid, const QString& id, const QString& path = "-s"); private: class UrlInfo { public: UrlInfo(const QString& path); + UrlInfo(const QString& path, const std::list& msgs); UrlInfo(); ~UrlInfo(); @@ -86,12 +83,12 @@ private: bool hasPath() const; void setPath(const QString& path); - void addMessage(const QString& acc, const QString& jid, const QString& id); - void getMessages(std::list& container) const; + bool addMessage(const QString& acc, const QString& jid, const QString& id); + void getMessages(std::list& container) const; private: QString localPath; - std::list messages; + std::list messages; }; diff --git a/main.cpp b/main.cpp index 0373af8..45232cf 100644 --- a/main.cpp +++ b/main.cpp @@ -20,6 +20,7 @@ #include "core/squawk.h" #include "signalcatcher.h" #include "shared/global.h" +#include "shared/messageinfo.h" #include #include #include @@ -31,8 +32,10 @@ int main(int argc, char *argv[]) { qRegisterMetaType("Shared::Message"); + qRegisterMetaType("Shared::MessageInfo"); qRegisterMetaType("Shared::VCard"); qRegisterMetaType>("std::list"); + qRegisterMetaType>("std::list"); qRegisterMetaType>("QSet"); qRegisterMetaType("Shared::ConnectionState"); qRegisterMetaType("Shared::Availability"); @@ -106,8 +109,7 @@ int main(int argc, char *argv[]) QObject::connect(&w, &Squawk::setRoomAutoJoin, squawk, &Core::Squawk::setRoomAutoJoin); QObject::connect(&w, &Squawk::removeRoomRequest, squawk, &Core::Squawk::removeRoomRequest); QObject::connect(&w, &Squawk::addRoomRequest, squawk, &Core::Squawk::addRoomRequest); - QObject::connect(&w, &Squawk::fileLocalPathRequest, squawk, &Core::Squawk::fileLocalPathRequest); - QObject::connect(&w, &Squawk::downloadFileRequest, squawk, &Core::Squawk::downloadFileRequest); + QObject::connect(&w, &Squawk::fileDownloadRequest, squawk, &Core::Squawk::fileDownloadRequest); QObject::connect(&w, &Squawk::addContactToGroupRequest, squawk, &Core::Squawk::addContactToGroupRequest); QObject::connect(&w, &Squawk::removeContactFromGroupRequest, squawk, &Core::Squawk::removeContactFromGroupRequest); QObject::connect(&w, &Squawk::renameContactRequest, squawk, &Core::Squawk::renameContactRequest); @@ -138,11 +140,10 @@ int main(int argc, char *argv[]) QObject::connect(squawk, &Core::Squawk::addRoomParticipant, &w, &Squawk::addRoomParticipant); QObject::connect(squawk, &Core::Squawk::changeRoomParticipant, &w, &Squawk::changeRoomParticipant); QObject::connect(squawk, &Core::Squawk::removeRoomParticipant, &w, &Squawk::removeRoomParticipant); - QObject::connect(squawk, &Core::Squawk::fileLocalPathResponse, &w, &Squawk::fileLocalPathResponse); - QObject::connect(squawk, &Core::Squawk::downloadFileProgress, &w, &Squawk::fileProgress); - QObject::connect(squawk, &Core::Squawk::downloadFileError, &w, &Squawk::fileError); - QObject::connect(squawk, &Core::Squawk::uploadFileProgress, &w, &Squawk::fileProgress); - QObject::connect(squawk, &Core::Squawk::uploadFileError, &w, &Squawk::fileError); + QObject::connect(squawk, &Core::Squawk::fileDownloadComplete, &w, &Squawk::fileDownloadComplete); + QObject::connect(squawk, &Core::Squawk::fileUploadComplete, &w, &Squawk::fileUploadComplete); + QObject::connect(squawk, &Core::Squawk::fileProgress, &w, &Squawk::fileProgress); + QObject::connect(squawk, &Core::Squawk::fileError, &w, &Squawk::fileError); QObject::connect(squawk, &Core::Squawk::responseVCard, &w, &Squawk::responseVCard); QObject::connect(squawk, &Core::Squawk::requestPassword, &w, &Squawk::requestPassword); QObject::connect(squawk, &Core::Squawk::ready, &w, &Squawk::readSettings); diff --git a/shared.h b/shared.h index 83bcd76..3925ce2 100644 --- a/shared.h +++ b/shared.h @@ -25,5 +25,6 @@ #include "shared/message.h" #include "shared/vcard.h" #include "shared/global.h" +#include "shared/messageinfo.h" #endif // SHARED_H diff --git a/shared/messageinfo.cpp b/shared/messageinfo.cpp new file mode 100644 index 0000000..7502a6e --- /dev/null +++ b/shared/messageinfo.cpp @@ -0,0 +1,45 @@ +/* + * Squawk messenger. + * Copyright (C) 2019 Yury Gubich + * + * 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 3 of the License, or + * (at your option) any later version. + * + * 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 "messageinfo.h" + +using namespace Shared; + +Shared::MessageInfo::MessageInfo(): + account(), + jid(), + messageId() {} + +Shared::MessageInfo::MessageInfo(const QString& acc, const QString& j, const QString& id): + account(acc), + jid(j), + messageId(id) {} + +Shared::MessageInfo::MessageInfo(const Shared::MessageInfo& other): + account(other.account), + jid(other.jid), + messageId(other.messageId) {} + +Shared::MessageInfo & Shared::MessageInfo::operator=(const Shared::MessageInfo& other) +{ + account = other.account; + jid = other.jid; + messageId = other.messageId; + + return *this; +} diff --git a/shared/messageinfo.h b/shared/messageinfo.h new file mode 100644 index 0000000..942d88c --- /dev/null +++ b/shared/messageinfo.h @@ -0,0 +1,43 @@ +/* + * Squawk messenger. + * Copyright (C) 2019 Yury Gubich + * + * 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 3 of the License, or + * (at your option) any later version. + * + * 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 SHARED_MESSAGEINFO_H +#define SHARED_MESSAGEINFO_H + +#include + +namespace Shared { + +/** + * @todo write docs + */ +struct MessageInfo { + MessageInfo(); + MessageInfo(const QString& acc, const QString& j, const QString& id); + MessageInfo(const MessageInfo& other); + + QString account; + QString jid; + QString messageId; + + MessageInfo& operator=(const MessageInfo& other); +}; + +} + +#endif // SHARED_MESSAGEINFO_H diff --git a/ui/models/element.cpp b/ui/models/element.cpp index 7b0e70f..d372e8d 100644 --- a/ui/models/element.cpp +++ b/ui/models/element.cpp @@ -30,7 +30,7 @@ Models::Element::Element(Type p_type, const Models::Account* acc, const QString& feed(new MessageFeed(this)) { connect(feed, &MessageFeed::requestArchive, this, &Element::requestArchive); - connect(feed, &MessageFeed::fileLocalPathRequest, this, &Element::fileLocalPathRequest); + connect(feed, &MessageFeed::fileDownloadRequest, this, &Element::fileDownloadRequest); QMap::const_iterator itr = data.find("avatarState"); if (itr != data.end()) { @@ -156,8 +156,17 @@ bool Models::Element::isRoom() const return type != contact; } -void Models::Element::fileProgress(const QString& messageId, qreal value) +void Models::Element::fileProgress(const QString& messageId, qreal value, bool up) { - feed->fileProgress(messageId, value); + feed->fileProgress(messageId, value, up); } +void Models::Element::fileComplete(const QString& messageId, bool up) +{ + feed->fileComplete(messageId, up); +} + +void Models::Element::fileError(const QString& messageId, const QString& error, bool up) +{ + feed->fileError(messageId, error, up); +} diff --git a/ui/models/element.h b/ui/models/element.h index f537f9b..db6cda1 100644 --- a/ui/models/element.h +++ b/ui/models/element.h @@ -43,11 +43,13 @@ public: unsigned int getMessagesCount() const; void responseArchive(const std::list list, bool last); bool isRoom() const; - void fileProgress(const QString& messageId, qreal value); + void fileProgress(const QString& messageId, qreal value, bool up); + void fileError(const QString& messageId, const QString& error, bool up); + void fileComplete(const QString& messageId, bool up); signals: void requestArchive(const QString& before); - void fileLocalPathRequest(const QString& messageId, const QString& url); + void fileDownloadRequest(const QString& url); protected: void setJid(const QString& p_jid); diff --git a/ui/models/messagefeed.cpp b/ui/models/messagefeed.cpp index 01b1a9d..99951d5 100644 --- a/ui/models/messagefeed.cpp +++ b/ui/models/messagefeed.cpp @@ -305,7 +305,7 @@ void Models::MessageFeed::downloadAttachment(const QString& messageId) if (progressPair.second) { //Only to take action if we weren't already downloading it Shared::Message* msg = static_cast(ind.internalPointer()); emit dataChanged(ind, ind); - emit fileLocalPathRequest(messageId, msg->getOutOfBandUrl()); + emit fileDownloadRequest(msg->getOutOfBandUrl()); } else { qDebug() << "Attachment download for message with id" << messageId << "is already in progress, skipping"; } @@ -319,16 +319,34 @@ void Models::MessageFeed::uploadAttachment(const QString& messageId) qDebug() << "request to upload attachment of the message" << messageId; } -void Models::MessageFeed::fileProgress(const QString& messageId, qreal value) +void Models::MessageFeed::fileProgress(const QString& messageId, qreal value, bool up) { - Progress::iterator itr = downloads.find(messageId); - if (itr != downloads.end()) { + Progress* pr = 0; + if (up) { + pr = &uploads; + } else { + pr = &downloads; + } + + Progress::iterator itr = pr->find(messageId); + if (itr != pr->end()) { itr->second = value; QModelIndex ind = modelIndexById(messageId); emit dataChanged(ind, ind); } } +void Models::MessageFeed::fileComplete(const QString& messageId, bool up) +{ + //TODO +} + +void Models::MessageFeed::fileError(const QString& messageId, const QString& error, bool up) +{ + //TODO +} + + QModelIndex Models::MessageFeed::modelIndexById(const QString& id) const { StorageById::const_iterator itr = indexById.find(id); diff --git a/ui/models/messagefeed.h b/ui/models/messagefeed.h index e8995d5..f4c2c28 100644 --- a/ui/models/messagefeed.h +++ b/ui/models/messagefeed.h @@ -59,12 +59,14 @@ public: void uploadAttachment(const QString& messageId); unsigned int unreadMessagesCount() const; - void fileProgress(const QString& messageId, qreal value); + void fileProgress(const QString& messageId, qreal value, bool up); + void fileError(const QString& messageId, const QString& error, bool up); + void fileComplete(const QString& messageId, bool up); signals: void requestArchive(const QString& before); void requestStateChange(bool requesting); - void fileLocalPathRequest(const QString& messageId, const QString& url); + void fileDownloadRequest(const QString& url); protected: bool sentByMe(const Shared::Message& msg) const; @@ -141,6 +143,8 @@ enum AttachmentType { local, downloading, uploading, + errorDownload, + errorUpload, ready }; diff --git a/ui/models/roster.cpp b/ui/models/roster.cpp index a7bc74e..5e3a1ac 100644 --- a/ui/models/roster.cpp +++ b/ui/models/roster.cpp @@ -27,8 +27,7 @@ Models::Roster::Roster(QObject* parent): root(new Item(Item::root, {{"name", "root"}})), accounts(), groups(), - contacts(), - requestedFiles() + contacts() { connect(accountsModel, &Accounts::dataChanged, this, &Roster::onAccountDataChanged); connect(root, &Item::childChanged, this, &Roster::onChildChanged); @@ -448,7 +447,7 @@ void Models::Roster::addContact(const QString& account, const QString& jid, cons if (itr == contacts.end()) { contact = new Contact(acc, jid, data); connect(contact, &Contact::requestArchive, this, &Roster::onElementRequestArchive); - connect(contact, &Contact::fileLocalPathRequest, this, &Roster::onElementFileLocalPathRequest); + connect(contact, &Contact::fileDownloadRequest, this, &Roster::fileDownloadRequest); contacts.insert(std::make_pair(id, contact)); } else { contact = itr->second; @@ -534,35 +533,19 @@ void Models::Roster::removeGroup(const QString& account, const QString& name) void Models::Roster::changeContact(const QString& account, const QString& jid, const QMap& data) { - ElId id(account, jid); - std::map::iterator cItr = contacts.find(id); - - if (cItr != contacts.end()) { + Element* el = getElement({account, jid}); + if (el != NULL) { for (QMap::const_iterator itr = data.begin(), end = data.end(); itr != end; ++itr) { - cItr->second->update(itr.key(), itr.value()); - } - } else { - std::map::iterator rItr = rooms.find(id); - if (rItr != rooms.end()) { - for (QMap::const_iterator itr = data.begin(), end = data.end(); itr != end; ++itr) { - rItr->second->update(itr.key(), itr.value()); - } + el->update(itr.key(), itr.value()); } } } void Models::Roster::changeMessage(const QString& account, const QString& jid, const QString& id, const QMap& data) { - ElId elid(account, jid); - std::map::iterator cItr = contacts.find(elid); - - if (cItr != contacts.end()) { - cItr->second->changeMessage(id, data); - } else { - std::map::iterator rItr = rooms.find(elid); - if (rItr != rooms.end()) { - rItr->second->changeMessage(id, data); - } + Element* el = getElement({account, jid}); + if (el != NULL) { + el->changeMessage(id, data); } } @@ -626,7 +609,6 @@ void Models::Roster::removeContact(const QString& account, const QString& jid, c } else { delete ref; } - if (gr->childCount() == 0) { removeGroup(account, group); } @@ -707,15 +689,9 @@ void Models::Roster::removePresence(const QString& account, const QString& jid, void Models::Roster::addMessage(const QString& account, const Shared::Message& data) { - ElId id(account, data.getPenPalJid()); - std::map::iterator itr = contacts.find(id); - if (itr != contacts.end()) { - itr->second->addMessage(data); - } else { - std::map::const_iterator rItr = rooms.find(id); - if (rItr != rooms.end()) { - rItr->second->addMessage(data); - } + Element* el = getElement({account, data.getPenPalJid()}); + if (el != NULL) { + el->addMessage(data); } } @@ -808,7 +784,7 @@ void Models::Roster::addRoom(const QString& account, const QString jid, const QM Room* room = new Room(acc, jid, data); connect(room, &Contact::requestArchive, this, &Roster::onElementRequestArchive); - connect(room, &Contact::fileLocalPathRequest, this, &Roster::onElementFileLocalPathRequest); + connect(room, &Contact::fileDownloadRequest, this, &Roster::fileDownloadRequest); rooms.insert(std::make_pair(id, room)); acc->appendChild(room); } @@ -971,51 +947,55 @@ void Models::Roster::onElementRequestArchive(const QString& before) void Models::Roster::responseArchive(const QString& account, const QString& jid, const std::list& list, bool last) { ElId id(account, jid); - std::map::iterator itr = contacts.find(id); - if (itr != contacts.end()) { - itr->second->responseArchive(list, last); + Element* el = getElement(id); + if (el != NULL) { + el->responseArchive(list, last); + } +} + +void Models::Roster::fileProgress(const std::list& msgs, qreal value, bool up) +{ + for (const Shared::MessageInfo& info : msgs) { + Element* el = getElement({info.account, info.jid}); + if (el != NULL) { + el->fileProgress(info.messageId, value, up); + } + } +} + +void Models::Roster::fileComplete(const std::list& msgs, bool up) +{ + for (const Shared::MessageInfo& info : msgs) { + Element* el = getElement({info.account, info.jid}); + if (el != NULL) { + el->fileComplete(info.messageId, up); + } + } +} + +void Models::Roster::fileError(const std::list& msgs, const QString& err, bool up) +{ + for (const Shared::MessageInfo& info : msgs) { + Element* el = getElement({info.account, info.jid}); + if (el != NULL) { + el->fileError(info.messageId, err, up); + } + } +} + +Models::Element * Models::Roster::getElement(const Models::Roster::ElId& id) +{ + std::map::iterator cItr = contacts.find(id); + + if (cItr != contacts.end()) { + return cItr->second; } else { - std::map::const_iterator rItr = rooms.find(id); + std::map::iterator rItr = rooms.find(id); if (rItr != rooms.end()) { - rItr->second->responseArchive(list, last); - } - } -} - -void Models::Roster::onElementFileLocalPathRequest(const QString& messageId, const QString& url) -{ - Element* el = static_cast(sender()); - std::map>::iterator itr = requestedFiles.find(messageId); - bool created = false; - if (itr == requestedFiles.end()) { - itr = requestedFiles.insert(std::make_pair(messageId, std::set())).first; - created = true; - } - itr->second.insert(Models::Roster::ElId(el->getAccountName(), el->getJid())); - if (created) { - emit fileLocalPathRequest(messageId, url); - } -} - -void Models::Roster::fileProgress(const QString& messageId, qreal value) -{ - std::map>::const_iterator itr = requestedFiles.find(messageId); - if (itr == requestedFiles.end()) { - qDebug() << "fileProgress in UI but there is nobody waiting for that id:" << messageId << ", skipping"; - return; - } else { - const std::set& convs = itr->second; - for (const Models::Roster::ElId& id : convs) { - std::map::const_iterator cItr = contacts.find(id); - if (cItr != contacts.end()) { - cItr->second->fileProgress(messageId, value); - } else { - std::map::const_iterator rItr = rooms.find(id); - if (rItr != rooms.end()) { - rItr->second->fileProgress(messageId, value); - } - } + return rItr->second; } } + + return NULL; } diff --git a/ui/models/roster.h b/ui/models/roster.h index 1f398d8..775d8de 100644 --- a/ui/models/roster.h +++ b/ui/models/roster.h @@ -26,6 +26,7 @@ #include "shared/message.h" #include "shared/global.h" +#include "shared/messageinfo.h" #include "accounts.h" #include "item.h" #include "account.h" @@ -81,21 +82,19 @@ public: QModelIndex getAccountIndex(const QString& name); QModelIndex getGroupIndex(const QString& account, const QString& name); void responseArchive(const QString& account, const QString& jid, const std::list& list, bool last); - void fileProgress(const QString& messageId, qreal value); + + void fileProgress(const std::list& msgs, qreal value, bool up); + void fileError(const std::list& msgs, const QString& err, bool up); + void fileComplete(const std::list& msgs, bool up); Accounts* accountsModel; signals: void requestArchive(const QString& account, const QString& jid, const QString& before); - void fileLocalPathRequest(const QString& messageId, const QString& url); + void fileDownloadRequest(const QString& url); private: - Item* root; - std::map accounts; - std::map groups; - std::map contacts; - std::map rooms; - std::map> requestedFiles; + Element* getElement(const ElId& id); private slots: void onAccountDataChanged(const QModelIndex& tl, const QModelIndex& br, const QVector& roles); @@ -107,7 +106,13 @@ private slots: void onChildIsAboutToBeMoved(Item* source, int first, int last, Item* destination, int newIndex); void onChildMoved(); void onElementRequestArchive(const QString& before); - void onElementFileLocalPathRequest(const QString& messageId, const QString& url); + +private: + Item* root; + std::map accounts; + std::map groups; + std::map contacts; + std::map rooms; public: class ElId { diff --git a/ui/squawk.cpp b/ui/squawk.cpp index 6b8416f..22c1051 100644 --- a/ui/squawk.cpp +++ b/ui/squawk.cpp @@ -29,7 +29,6 @@ Squawk::Squawk(QWidget *parent) : conversations(), contextMenu(new QMenu()), dbus("org.freedesktop.Notifications", "/org/freedesktop/Notifications", "org.freedesktop.Notifications", QDBusConnection::sessionBus()), - requestedFiles(), vCards(), requestedAccountsForPasswords(), prompt(0), @@ -62,8 +61,8 @@ Squawk::Squawk(QWidget *parent) : connect(m_ui->roster->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &Squawk::onRosterSelectionChanged); connect(rosterModel.accountsModel, &Models::Accounts::sizeChanged, this, &Squawk::onAccountsSizeChanged); - connect(&rosterModel, &Models::Roster::requestArchive, this, &Squawk::onConversationRequestArchive); - connect(&rosterModel, &Models::Roster::fileLocalPathRequest, this, &Squawk::fileLocalPathRequest); + connect(&rosterModel, &Models::Roster::requestArchive, this, &Squawk::onRequestArchive); + connect(&rosterModel, &Models::Roster::fileDownloadRequest, this, &Squawk::fileDownloadRequest); connect(contextMenu, &QMenu::aboutToHide, this, &Squawk::onContextAboutToHide); //m_ui->mainToolBar->addWidget(m_ui->comboBox); @@ -389,86 +388,24 @@ void Squawk::onConversationClosed(QObject* parent) } } -void Squawk::onConversationDownloadFile(const QString& messageId, const QString& url) +void Squawk::fileProgress(const std::list msgs, qreal value, bool up) { - Conversation* conv = static_cast(sender()); - std::map>::iterator itr = requestedFiles.find(messageId); - bool created = false; - if (itr == requestedFiles.end()) { - itr = requestedFiles.insert(std::make_pair(messageId, std::set())).first; - created = true; - } - itr->second.insert(Models::Roster::ElId(conv->getAccount(), conv->getJid())); - if (created) { - emit downloadFileRequest(messageId, url); - } + rosterModel.fileProgress(msgs, value, up); } -void Squawk::fileProgress(const QString& messageId, qreal value) +void Squawk::fileDownloadComplete(const std::list msgs, const QString& path) { - rosterModel.fileProgress(messageId, value); + rosterModel.fileComplete(msgs, false); } -void Squawk::fileError(const QString& messageId, const QString& error) +void Squawk::fileError(const std::list msgs, const QString& error, bool up) { - std::map>::const_iterator itr = requestedFiles.find(messageId); - if (itr == requestedFiles.end()) { - qDebug() << "fileError in UI Squawk but there is nobody waiting for that id" << messageId << ", skipping"; - return; - } else { - const std::set& convs = itr->second; - for (std::set::const_iterator cItr = convs.begin(), cEnd = convs.end(); cItr != cEnd; ++cItr) { - const Models::Roster::ElId& id = *cItr; - Conversations::const_iterator c = conversations.find(id); - if (c != conversations.end()) { - c->second->fileError(messageId, error); - } - if (currentConversation != 0 && currentConversation->getId() == id) { - currentConversation->fileError(messageId, error); - } - } - requestedFiles.erase(itr); - } + rosterModel.fileError(msgs, error, up); } - -//TODO! Need to make it look like a standard message change event! -void Squawk::fileLocalPathResponse(const QString& messageId, const QString& path) +void Squawk::fileUploadComplete(const std::list msgs, const QString& path) { - std::map>::const_iterator itr = requestedFiles.find(messageId); - if (itr == requestedFiles.end()) { - qDebug() << "fileLocalPathResponse in UI Squawk but there is nobody waiting for that path, skipping"; - return; - } else { - const std::set& convs = itr->second; - for (std::set::const_iterator cItr = convs.begin(), cEnd = convs.end(); cItr != cEnd; ++cItr) { - const Models::Roster::ElId& id = *cItr; - Conversations::const_iterator c = conversations.find(id); - if (c != conversations.end()) { - c->second->responseLocalFile(messageId, path); - } - if (currentConversation != 0 && currentConversation->getId() == id) { - currentConversation->responseLocalFile(messageId, path); - } - } - - requestedFiles.erase(itr); - } -} - -void Squawk::onConversationRequestLocalFile(const QString& messageId, const QString& url) -{ - Conversation* conv = static_cast(sender()); - std::map>::iterator itr = requestedFiles.find(messageId); - bool created = false; - if (itr == requestedFiles.end()) { - itr = requestedFiles.insert(std::make_pair(messageId, std::set())).first; - created = true; - } - itr->second.insert(Models::Roster::ElId(conv->getAccount(), conv->getJid())); - if (created) { - emit fileLocalPathRequest(messageId, url); - } + rosterModel.fileComplete(msgs, true); } void Squawk::accountMessage(const QString& account, const Shared::Message& data) @@ -565,23 +502,13 @@ void Squawk::notify(const QString& account, const Shared::Message& msg) void Squawk::onConversationMessage(const Shared::Message& msg) { Conversation* conv = static_cast(sender()); - Models::Roster::ElId id = conv->getId(); + QString acc = conv->getAccount(); - rosterModel.addMessage(conv->getAccount(), msg); - - QString ap = msg.getAttachPath(); - QString oob = msg.getOutOfBandUrl(); - if ((ap.size() > 0 && oob.size() == 0) || (ap.size() == 0 && oob.size() > 0)) { - std::map>::iterator itr = requestedFiles.insert(std::make_pair(msg.getId(), std::set())).first; - itr->second.insert(id); - - //TODO can also start downloading here if someone attached the message with the remote url - } - - emit sendMessage(conv->getAccount(), msg); + rosterModel.addMessage(acc, msg); + emit sendMessage(acc, msg); } -void Squawk::onConversationRequestArchive(const QString& account, const QString& jid, const QString& before) +void Squawk::onRequestArchive(const QString& account, const QString& jid, const QString& before) { emit requestArchive(account, jid, 20, before); //TODO amount as a settings value } @@ -1029,8 +956,6 @@ void Squawk::subscribeConversation(Conversation* conv) { connect(conv, &Conversation::destroyed, this, &Squawk::onConversationClosed); connect(conv, &Conversation::sendMessage, this, &Squawk::onConversationMessage); - connect(conv, &Conversation::requestLocalFile, this, &Squawk::onConversationRequestLocalFile); - connect(conv, &Conversation::downloadFile, this, &Squawk::onConversationDownloadFile); } void Squawk::onRosterSelectionChanged(const QModelIndex& current, const QModelIndex& previous) diff --git a/ui/squawk.h b/ui/squawk.h index 26f7753..ada13fc 100644 --- a/ui/squawk.h +++ b/ui/squawk.h @@ -75,8 +75,7 @@ signals: void setRoomAutoJoin(const QString& account, const QString& jid, bool joined); void addRoomRequest(const QString& account, const QString& jid, const QString& nick, const QString& password, bool autoJoin); void removeRoomRequest(const QString& account, const QString& jid); - void fileLocalPathRequest(const QString& messageId, const QString& url); - void downloadFileRequest(const QString& messageId, const QString& url); + void fileDownloadRequest(const QString& url); void requestVCard(const QString& account, const QString& jid); void uploadVCard(const QString& account, const Shared::VCard& card); void responsePassword(const QString& account, const QString& password); @@ -103,9 +102,10 @@ public slots: void addRoomParticipant(const QString& account, const QString& jid, const QString& name, const QMap& data); void changeRoomParticipant(const QString& account, const QString& jid, const QString& name, const QMap& data); void removeRoomParticipant(const QString& account, const QString& jid, const QString& name); - void fileLocalPathResponse(const QString& messageId, const QString& path); - void fileError(const QString& messageId, const QString& error); - void fileProgress(const QString& messageId, qreal value); + void fileError(const std::list msgs, const QString& error, bool up); + void fileProgress(const std::list msgs, qreal value, bool up); + void fileDownloadComplete(const std::list msgs, const QString& path); + void fileUploadComplete(const std::list msgs, const QString& path); void responseVCard(const QString& jid, const Shared::VCard& card); void changeMessage(const QString& account, const QString& jid, const QString& id, const QMap& data); void requestPassword(const QString& account); @@ -119,7 +119,6 @@ private: Conversations conversations; QMenu* contextMenu; QDBusInterface dbus; - std::map> requestedFiles; std::map vCards; std::deque requestedAccountsForPasswords; QInputDialog* prompt; @@ -146,10 +145,8 @@ private slots: void onComboboxActivated(int index); void onRosterItemDoubleClicked(const QModelIndex& item); void onConversationMessage(const Shared::Message& msg); - void onConversationRequestArchive(const QString& account, const QString& jid, const QString& before); + void onRequestArchive(const QString& account, const QString& jid, const QString& before); void onRosterContextMenu(const QPoint& point); - void onConversationRequestLocalFile(const QString& messageId, const QString& url); - void onConversationDownloadFile(const QString& messageId, const QString& url); void onItemCollepsed(const QModelIndex& index); void onPasswordPromptAccepted(); void onPasswordPromptRejected();