diff --git a/CHANGELOG.md b/CHANGELOG.md index bf90231..06c4ce1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,14 +6,10 @@ - requesting the history of the current chat after reconnection - global availability (in drop down list) gets restored after reconnection - status icon in active chat changes when presence of the pen pal changes -- infinite progress when open the dialogue with something that has no history to show ### Improvements - slightly reduced the traffic on the startup by not requesting history of all MUCs -- completely rewritten message feed, now it works way faster -- OPTIONAL RUNTIME dependency: "KIO Widgets" that is supposed to allow you to open a file in your default file manager -- show in folder now is supposed to try it's best to show file in folder, even you don't have KIO installed -- once uploaded local files don't get second time uploaded - the remote URL is reused + ## Squawk 0.1.5 (Jul 29, 2020) ### Bug fixes diff --git a/CMakeLists.txt b/CMakeLists.txt index e88fdc8..771481f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,8 @@ -cmake_minimum_required(VERSION 3.4) +cmake_minimum_required(VERSION 3.0) project(squawk) set(CMAKE_INCLUDE_CURRENT_DIR ON) -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 14) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) @@ -32,7 +32,6 @@ set(squawk_SRC shared/message.cpp shared/vcard.cpp shared/icons.cpp - shared/messageinfo.cpp ) set(squawk_HEAD @@ -45,7 +44,6 @@ set(squawk_HEAD shared/utils.h shared/vcard.h shared/icons.h - shared/messageinfo.h ) configure_file(resources/images/logo.svg squawk.svg COPYONLY) @@ -66,7 +64,6 @@ qt5_add_resources(RCC resources/resources.qrc) option(SYSTEM_QXMPP "Use system qxmpp lib" ON) option(WITH_KWALLET "Build KWallet support module" ON) -option(WITH_KIO "Build KIO support module" ON) if (SYSTEM_QXMPP) find_package(QXmpp CONFIG) @@ -98,21 +95,8 @@ endif() add_executable(squawk ${squawk_SRC} ${squawk_HEAD} ${RCC}) target_link_libraries(squawk Qt5::Widgets) -if (WITH_KIO) - find_package(KF5KIO CONFIG) - - if (NOT KF5KIO_FOUND) - set(WITH_KIO OFF) - message("KIO package wasn't found, KIO support modules wouldn't be built") - else() - add_definitions(-DWITH_KIO) - message("Building with support of KIO") - endif() -endif() - add_subdirectory(ui) add_subdirectory(core) -add_subdirectory(plugins) add_subdirectory(external/simpleCrypt) @@ -120,8 +104,6 @@ target_link_libraries(squawk squawkUI) target_link_libraries(squawk squawkCORE) target_link_libraries(squawk uuid) - - add_dependencies(${CMAKE_PROJECT_NAME} translations) # Install the executable diff --git a/README.md b/README.md index f2101d6..30c6473 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,7 @@ - lmdb - CMake 3.0 or higher - qxmpp 1.1.0 or higher -- KDE Frameworks: kwallet (optional) -- KDE Frameworks: KIO (optional) +- kwallet (optional) ### Getting @@ -68,7 +67,6 @@ Here is the list of keys you can pass to configuration phase of `cmake ..`. - `CMAKE_BUILD_TYPE` - `Debug` just builds showing all warnings, `Release` builds with no warnings and applies optimizations (default is `Debug`) - `SYSTEM_QXMPP` - `True` tries to link against `qxmpp` installed in the system, `False` builds bundled `qxmpp` library (default is `True`) - `WITH_KWALLET` - `True` builds the `KWallet` capability module if `KWallet` is installed and if not goes to `False`. `False` disables `KWallet` support (default is `True`) -- `WITH_KIO` - `True` builds the `KIO` capability module if `KIO` is installed and if not goes to `False`. `False` disables `KIO` support (default is `True`) ## License diff --git a/cmake/FindLMDB.cmake b/cmake/FindLMDB.cmake deleted file mode 100644 index 8bf48b4..0000000 --- a/cmake/FindLMDB.cmake +++ /dev/null @@ -1,47 +0,0 @@ -#This file is taken from here https://gitlab.ralph.or.at/causal-rt/causal-cpp/, it was GPLv3 license -#Thank you so much, mr. Ralph Alexander Bariz, I hope you don't mind me using your code - -# Try to find LMDB headers and library. -# -# Usage of this module as follows: -# -# find_package(LMDB) -# -# Variables used by this module, they can change the default behaviour and need -# to be set before calling find_package: -# -# LMDB_ROOT_DIR Set this variable to the root installation of -# LMDB if the module has problems finding the -# proper installation path. -# -# Variables defined by this module: -# -# LMDB_FOUND System has LMDB library/headers. -# LMDB_LIBRARIES The LMDB library. -# LMDB_INCLUDE_DIRS The location of LMDB headers. - -find_path(LMDB_ROOT_DIR - NAMES include/lmdb.h -) - -find_library(LMDB_LIBRARIES - NAMES lmdb - HINTS ${LMDB_ROOT_DIR}/lib -) - -find_path(LMDB_INCLUDE_DIRS - NAMES lmdb.h - HINTS ${LMDB_ROOT_DIR}/include -) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(LMDB DEFAULT_MSG - LMDB_LIBRARIES - LMDB_INCLUDE_DIRS -) - -mark_as_advanced( - LMDB_ROOT_DIR - LMDB_LIBRARIES - LMDB_INCLUDE_DIRS -) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index f8aa267..b74a055 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -1,15 +1,12 @@ -cmake_minimum_required(VERSION 3.3) +cmake_minimum_required(VERSION 3.0) project(squawkCORE) -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake") - set(CMAKE_AUTOMOC ON) find_package(Qt5Core CONFIG REQUIRED) find_package(Qt5Gui CONFIG REQUIRED) find_package(Qt5Network CONFIG REQUIRED) find_package(Qt5Xml CONFIG REQUIRED) -find_package(LMDB REQUIRED) set(squawkCORE_SRC squawk.cpp @@ -18,7 +15,7 @@ set(squawkCORE_SRC rosteritem.cpp contact.cpp conference.cpp - urlstorage.cpp + storage.cpp networkaccess.cpp adapterFuctions.cpp handlers/messagehandler.cpp @@ -28,7 +25,7 @@ set(squawkCORE_SRC add_subdirectory(passwordStorageEngines) # Tell CMake to create the helloworld executable -add_library(squawkCORE STATIC ${squawkCORE_SRC}) +add_library(squawkCORE ${squawkCORE_SRC}) if(SYSTEM_QXMPP) diff --git a/core/account.cpp b/core/account.cpp index 5ce29ee..094fd3c 100644 --- a/core/account.cpp +++ b/core/account.cpp @@ -84,9 +84,8 @@ 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::onUploadFileComplete); - QObject::connect(network, &NetworkAccess::downloadFileComplete, mh, &MessageHandler::onDownloadFileComplete); - QObject::connect(network, &NetworkAccess::loadFileError, mh, &MessageHandler::onLoadFileError); + QObject::connect(network, &NetworkAccess::uploadFileComplete, mh, &MessageHandler::onFileUploaded); + QObject::connect(network, &NetworkAccess::uploadFileError, mh, &MessageHandler::onFileUploadError); client.addExtension(rcpm); QObject::connect(rcpm, &QXmppMessageReceiptManager::messageDelivered, mh, &MessageHandler::onReceiptReceived); @@ -156,9 +155,8 @@ Account::~Account() reconnectTimer->stop(); } - QObject::disconnect(network, &NetworkAccess::uploadFileComplete, mh, &MessageHandler::onUploadFileComplete); - QObject::disconnect(network, &NetworkAccess::downloadFileComplete, mh, &MessageHandler::onDownloadFileComplete); - QObject::disconnect(network, &NetworkAccess::loadFileError, mh, &MessageHandler::onLoadFileError); + QObject::disconnect(network, &NetworkAccess::uploadFileComplete, mh, &MessageHandler::onFileUploaded); + QObject::disconnect(network, &NetworkAccess::uploadFileError, mh, &MessageHandler::onFileUploadError); delete mh; delete rh; @@ -404,6 +402,9 @@ QString Core::Account::getFullJid() const { void Core::Account::sendMessage(const Shared::Message& data) { mh->sendMessage(data);} +void Core::Account::sendMessage(const Shared::Message& data, const QString& path) { + mh->sendMessage(data, path);} + void Core::Account::onMamMessageReceived(const QString& queryId, const QXmppMessage& msg) { if (msg.id().size() > 0 && (msg.body().size() > 0 || msg.outOfBandUrl().size() > 0)) { @@ -433,13 +434,13 @@ void Core::Account::requestArchive(const QString& jid, int count, const QString& if (contact == 0) { qDebug() << "An attempt to request archive for" << jid << "in account" << name << ", but the contact with such id wasn't found, skipping"; - emit responseArchive(jid, std::list(), true); + emit responseArchive(jid, std::list()); return; } if (state != Shared::ConnectionState::connected) { qDebug() << "An attempt to request archive for" << jid << "in account" << name << ", but the account is not online, skipping"; - emit responseArchive(contact->jid, std::list(), false); + emit responseArchive(contact->jid, std::list()); } contact->requestHistory(count, before); @@ -551,11 +552,9 @@ 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; @@ -910,16 +909,3 @@ void Core::Account::handleDisconnection() ownVCardRequestInProgress = false; } -void Core::Account::onContactHistoryResponse(const std::list& list, bool last) -{ - RosterItem* contact = static_cast(sender()); - - qDebug() << "Collected history for contact " << contact->jid << list.size() << "elements"; - if (last) { - qDebug() << "The response contains the first accounted message"; - } - emit responseArchive(contact->jid, list, last); -} - -void Core::Account::requestChangeMessage(const QString& jid, const QString& messageId, const QMap& data){ - mh->requestChangeMessage(jid, messageId, data);} diff --git a/core/account.h b/core/account.h index ce3b754..49c7ca9 100644 --- a/core/account.h +++ b/core/account.h @@ -88,6 +88,7 @@ public: void setPasswordType(Shared::AccountPassword pt); QString getFullJid() const; void sendMessage(const Shared::Message& data); + void sendMessage(const Shared::Message& data, const QString& path); void requestArchive(const QString& jid, int count, const QString& before); void subscribeToContact(const QString& jid, const QString& reason); void unsubscribeFromContact(const QString& jid, const QString& reason); @@ -96,7 +97,6 @@ public: void addContactToGroupRequest(const QString& jid, const QString& groupName); void removeContactFromGroupRequest(const QString& jid, const QString& groupName); void renameContactRequest(const QString& jid, const QString& newName); - void requestChangeMessage(const QString& jid, const QString& messageId, const QMap& data); void setRoomJoined(const QString& jid, bool joined); void setRoomAutoJoin(const QString& jid, bool joined); @@ -127,14 +127,14 @@ signals: void removePresence(const QString& jid, const QString& name); void message(const Shared::Message& data); void changeMessage(const QString& jid, const QString& id, const QMap& data); - void responseArchive(const QString& jid, const std::list& list, bool last); + void responseArchive(const QString& jid, const std::list& list); void error(const QString& text); void addRoomParticipant(const QString& jid, const QString& nickName, const QMap& data); void changeRoomParticipant(const QString& jid, const QString& nickName, const QMap& data); 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& jid, const QString& messageId, const QString& error); + void uploadFileError(const QString& messageId, const QString& error); private: QString name; @@ -183,7 +183,6 @@ private slots: void onDiscoveryItemsReceived (const QXmppDiscoveryIq& items); void onDiscoveryInfoReceived (const QXmppDiscoveryIq& info); - void onContactHistoryResponse(const std::list& list, bool last); private: void handleDisconnection(); diff --git a/core/archive.cpp b/core/archive.cpp index c29c9a0..a1f8b76 100644 --- a/core/archive.cpp +++ b/core/archive.cpp @@ -271,8 +271,6 @@ void Core::Archive::changeMessage(const QString& id, const QMap 0; QDateTime oTime = msg.getTime(); bool idChange = msg.change(data); - QDateTime nTime = msg.getTime(); - bool orderChange = oTime != nTime; MDB_val lmdbKey, lmdbData; QByteArray ba; @@ -282,21 +280,15 @@ void Core::Archive::changeMessage(const QString& id, const QMap Core::Archive::getBefore(int count, const QString& id) @@ -612,10 +603,10 @@ void Core::Archive::setFromTheBeginning(bool is) MDB_txn *txn; mdb_txn_begin(environment, NULL, 0, &txn); bool success = setStatValue("beginning", is, txn); - if (success) { - mdb_txn_commit(txn); - } else { + if (success != 0) { mdb_txn_abort(txn); + } else { + mdb_txn_commit(txn); } } } diff --git a/core/handlers/messagehandler.cpp b/core/handlers/messagehandler.cpp index dc37c3b..0f0e09d 100644 --- a/core/handlers/messagehandler.cpp +++ b/core/handlers/messagehandler.cpp @@ -23,6 +23,7 @@ Core::MessageHandler::MessageHandler(Core::Account* account): QObject(), acc(account), pendingStateMessages(), + pendingMessages(), uploadingSlotsQueue() { } @@ -53,7 +54,7 @@ void Core::MessageHandler::onMessageReceived(const QXmppMessage& msg) if (cnt != 0) { cnt->changeMessage(id, cData); } - + ; emit acc->changeMessage(jid, id, cData); pendingStateMessages.erase(itr); handled = true; @@ -167,16 +168,14 @@ void Core::MessageHandler::initializeMessage(Shared::Message& target, const QXmp id = source.id(); #endif target.setId(id); - QString messageId = target.getId(); - if (messageId.size() == 0) { + if (target.getId().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; @@ -190,12 +189,6 @@ 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) @@ -239,23 +232,11 @@ void Core::MessageHandler::onReceiptReceived(const QString& jid, const QString& } } -void Core::MessageHandler::sendMessage(const Shared::Message& data) -{ - if (data.getOutOfBandUrl().size() == 0 && data.getAttachPath().size() > 0) { - prepareUpload(data); - } else { - performSending(data); - } -} - -void Core::MessageHandler::performSending(Shared::Message data, bool newMessage) +void Core::MessageHandler::sendMessage(Shared::Message data) { QString jid = data.getPenPalJid(); QString id = data.getId(); - QString oob = data.getOutOfBandUrl(); RosterItem* ri = acc->rh->getRosterItem(jid); - bool sent = false; - QMap changes; if (acc->state == Shared::ConnectionState::connected) { QXmppMessage msg(acc->getFullJid(), data.getTo(), data.getBody(), data.getThread()); @@ -264,16 +245,23 @@ void Core::MessageHandler::performSending(Shared::Message data, bool newMessage) #endif msg.setId(id); msg.setType(static_cast(data.getType())); //it is safe here, my type is compatible - msg.setOutOfBandUrl(oob); + msg.setOutOfBandUrl(data.getOutOfBandUrl()); msg.setReceiptRequested(true); - sent = acc->client.sendPacket(msg); + bool sent = acc->client.sendPacket(msg); if (sent) { data.setState(Shared::Message::State::sent); } else { data.setState(Shared::Message::State::error); - data.setErrorText("Couldn't send message: internal QXMPP library error, probably need to check out the logs"); + data.setErrorText("Couldn't send message via QXMPP library check out logs"); + } + + if (ri != 0) { + ri->appendMessageToArchive(data); + if (sent) { + pendingStateMessages.insert(std::make_pair(id, jid)); + } } } else { @@ -281,74 +269,41 @@ void Core::MessageHandler::performSending(Shared::Message data, bool newMessage) data.setErrorText("You are is offline or reconnecting"); } - Shared::Message::State mstate = data.getState(); - changes.insert("state", static_cast(mstate)); - if (mstate == Shared::Message::State::error) { - changes.insert("errorText", data.getErrorText()); - } - if (oob.size() > 0) { - changes.insert("outOfBandUrl", oob); - } - if (!newMessage) { - changes.insert("stamp", data.getTime()); - } - - if (ri != 0) { - if (newMessage) { - ri->appendMessageToArchive(data); - } else { - ri->changeMessage(id, changes); - } - if (sent) { - pendingStateMessages.insert(std::make_pair(id, jid)); - } else { - pendingStateMessages.erase(id); - } - } - - emit acc->changeMessage(jid, id, changes); + emit acc->changeMessage(jid, id, { + {"state", static_cast(data.getState())}, + {"errorText", data.getErrorText()} + }); } -void Core::MessageHandler::prepareUpload(const Shared::Message& data) +void Core::MessageHandler::sendMessage(const Shared::Message& data, const QString& path) { if (acc->state == Shared::ConnectionState::connected) { - QString jid = data.getPenPalJid(); - QString id = data.getId(); - RosterItem* ri = acc->rh->getRosterItem(jid); - if (!ri) { - qDebug() << "An attempt to initialize upload in" << acc->name << "for pal" << jid << "but the object for this pal wasn't found, something went terrebly wrong, skipping send"; - return; - } - QString path = data.getAttachPath(); QString url = acc->network->getFileRemoteUrl(path); if (url.size() != 0) { sendMessageWithLocalUploadedFile(data, url); } else { - if (acc->network->checkAndAddToUploading(acc->getName(), jid, id, path)) { - ri->appendMessageToArchive(data); - pendingStateMessages.insert(std::make_pair(id, jid)); + if (acc->network->isUploading(path, data.getId())) { + pendingMessages.emplace(data.getId(), data); } else { if (acc->um->serviceFound()) { QFileInfo file(path); if (file.exists() && file.isReadable()) { - ri->appendMessageToArchive(data); - pendingStateMessages.insert(std::make_pair(id, jid)); - uploadingSlotsQueue.emplace_back(path, id); + uploadingSlotsQueue.emplace_back(path, data); if (uploadingSlotsQueue.size() == 1) { acc->um->requestUploadSlot(file); } } else { - handleUploadError(jid, id, "Uploading file no longer exists or your system user has no permission to read it"); + onFileUploadError(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 { - handleUploadError(jid, id, "Your server doesn't support file upload service, or it's prohibited for your account"); + onFileUploadError(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 { - handleUploadError(data.getPenPalJid(), data.getId(), "Account is offline or reconnecting"); + onFileUploadError(data.getId(), "Account is offline or reconnecting"); qDebug() << "An attempt to send message with not connected account " << acc->name << ", skipping"; } } @@ -359,12 +314,12 @@ void Core::MessageHandler::onUploadSlotReceived(const QXmppHttpUploadSlotIq& slo if (uploadingSlotsQueue.size() == 0) { qDebug() << "HTTP Upload manager of account" << acc->name << "reports about success requesting upload slot, but none was requested"; } else { - const std::pair& pair = uploadingSlotsQueue.front(); - const QString& mId = pair.second; - QString palJid = pendingStateMessages.at(mId); - acc->network->uploadFile({acc->name, palJid, mId}, pair.first, slot.putUrl(), slot.getUrl(), slot.putHeaders()); - + const std::pair& pair = uploadingSlotsQueue.front(); + const QString& mId = pair.second.getId(); + acc->network->uploadFile(mId, pair.first, slot.putUrl(), slot.getUrl(), slot.putHeaders()); + pendingMessages.emplace(mId, pair.second); uploadingSlotsQueue.pop_front(); + if (uploadingSlotsQueue.size() > 0) { acc->um->requestUploadSlot(uploadingSlotsQueue.front().first); } @@ -373,111 +328,44 @@ 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() << err; + qDebug() << request.error().text(); } else { - const std::pair& pair = uploadingSlotsQueue.front(); - qDebug() << "Error requesting upload slot for file" << pair.first << "in account" << acc->name << ":" << err; - handleUploadError(pendingStateMessages.at(pair.second), pair.second, err); + 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()); - uploadingSlotsQueue.pop_front(); if (uploadingSlotsQueue.size() > 0) { acc->um->requestUploadSlot(uploadingSlotsQueue.front().first); } + uploadingSlotsQueue.pop_front(); } } -void Core::MessageHandler::onDownloadFileComplete(const std::list& msgs, const QString& path) +void Core::MessageHandler::onFileUploaded(const QString& messageId, const QString& url) { - QMap cData = { - {"attachPath", path} - }; - for (const Shared::MessageInfo& info : msgs) { - if (info.account == acc->getName()) { - RosterItem* cnt = acc->rh->getRosterItem(info.jid); - if (cnt != 0) { - if (cnt->changeMessage(info.messageId, cData)) { - emit acc->changeMessage(info.jid, info.messageId, cData); - } - } - } + std::map::const_iterator itr = pendingMessages.find(messageId); + if (itr != pendingMessages.end()) { + sendMessageWithLocalUploadedFile(itr->second, url); + pendingMessages.erase(itr); } } -void Core::MessageHandler::onLoadFileError(const std::list& msgs, const QString& text, bool up) +void Core::MessageHandler::onFileUploadError(const QString& messageId, const QString& errMsg) { - if (up) { - for (const Shared::MessageInfo& info : msgs) { - if (info.account == acc->getName()) { - handleUploadError(info.jid, info.messageId, text); - } - } + std::map::const_iterator itr = pendingMessages.find(messageId); + if (itr != pendingMessages.end()) { + pendingMessages.erase(itr); } } -void Core::MessageHandler::handleUploadError(const QString& jid, const QString& messageId, const QString& errorText) -{ - emit acc->uploadFileError(jid, messageId, "Error requesting slot to upload file: " + errorText); - pendingStateMessages.erase(jid); - requestChangeMessage(jid, messageId, { - {"state", static_cast(Shared::Message::State::error)}, - {"errorText", errorText} - }); -} - -void Core::MessageHandler::onUploadFileComplete(const std::list& msgs, const QString& path) -{ - for (const Shared::MessageInfo& info : msgs) { - if (info.account == acc->getName()) { - RosterItem* ri = acc->rh->getRosterItem(info.jid); - if (ri != 0) { - Shared::Message msg = ri->getMessage(info.messageId); - sendMessageWithLocalUploadedFile(msg, path, false); - } else { - qDebug() << "A signal received about complete upload to" << acc->name << "for pal" << info.jid << "but the object for this pal wasn't found, something went terrebly wrong, skipping send"; - } - } - } -} - -void Core::MessageHandler::sendMessageWithLocalUploadedFile(Shared::Message msg, const QString& url, bool newMessage) +void Core::MessageHandler::sendMessageWithLocalUploadedFile(Shared::Message msg, const QString& url) { msg.setOutOfBandUrl(url); - if (msg.getBody().size() == 0) { //not sure why, but most messages do that - msg.setBody(url); //they duplicate oob in body, some of them wouldn't even show an attachment if you don't do that - } - performSending(msg, newMessage); + if (msg.getBody().size() == 0) { + msg.setBody(url); + } + sendMessage(msg); //TODO removal/progress update } - -static const std::set allowerToChangeKeys({ - "attachPath", - "outOfBandUrl", - "state", - "errorText" -}); - -void Core::MessageHandler::requestChangeMessage(const QString& jid, const QString& messageId, const QMap& data) -{ - RosterItem* cnt = acc->rh->getRosterItem(jid); - if (cnt != 0) { - bool allSupported = true; - QString unsupportedString; - for (QMap::const_iterator itr = data.begin(); itr != data.end(); ++itr) { //I need all this madness - if (allowerToChangeKeys.count(itr.key()) != 1) { //to not allow this method - allSupported = false; //to make a message to look like if it was edited - unsupportedString = itr.key(); //basically I needed to control who exaclty calls this method - break; //because the underlying tech assumes that the change is initiated by user - } //not by system - } - if (allSupported) { - cnt->changeMessage(messageId, data); - emit acc->changeMessage(jid, messageId, data); - } else { - qDebug() << "A request to change message" << messageId << "of conversation" << jid << "with following data" << data; - qDebug() << "only limited set of dataFields are supported yet here, and" << unsupportedString << "isn't one of them, skipping"; - } - } -} diff --git a/core/handlers/messagehandler.h b/core/handlers/messagehandler.h index 9138245..be1545f 100644 --- a/core/handlers/messagehandler.h +++ b/core/handlers/messagehandler.h @@ -28,7 +28,6 @@ #include #include -#include namespace Core { @@ -45,7 +44,8 @@ public: MessageHandler(Account* account); public: - void sendMessage(const Shared::Message& data); + void sendMessage(Shared::Message data); + void sendMessage(const Shared::Message& data, const QString& path); void initializeMessage(Shared::Message& target, const QXmppMessage& source, bool outgoing = false, bool forwarded = false, bool guessing = false) const; public slots: @@ -55,24 +55,20 @@ public slots: void onReceiptReceived(const QString& jid, const QString& id); void onUploadSlotReceived(const QXmppHttpUploadSlotIq& slot); void onUploadSlotRequestFailed(const QXmppHttpUploadRequestIq& request); - 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); - void requestChangeMessage(const QString& jid, const QString& messageId, const QMap& data); + void onFileUploaded(const QString& messageId, const QString& url); + void onFileUploadError(const QString& messageId, const QString& errMsg); private: bool handleChatMessage(const QXmppMessage& msg, bool outgoing = false, bool forwarded = false, bool guessing = false); bool handleGroupMessage(const QXmppMessage& msg, bool outgoing = false, bool forwarded = false, bool guessing = false); void logMessage(const QXmppMessage& msg, const QString& reason = "Message wasn't handled: "); - void sendMessageWithLocalUploadedFile(Shared::Message msg, const QString& url, bool newMessage = true); - void performSending(Shared::Message data, bool newMessage = true); - void prepareUpload(const Shared::Message& data); - void handleUploadError(const QString& jid, const QString& messageId, const QString& errorText); + void sendMessageWithLocalUploadedFile(Shared::Message msg, const QString& url); private: Account* acc; - std::map pendingStateMessages; //key is message id, value is JID - std::deque> uploadingSlotsQueue; + std::map pendingStateMessages; + std::map pendingMessages; + std::deque> uploadingSlotsQueue; }; } diff --git a/core/handlers/rosterhandler.cpp b/core/handlers/rosterhandler.cpp index ce5f1b7..82ca8c3 100644 --- a/core/handlers/rosterhandler.cpp +++ b/core/handlers/rosterhandler.cpp @@ -190,7 +190,7 @@ void Core::RosterHandler::removeContactRequest(const QString& jid) void Core::RosterHandler::handleNewRosterItem(Core::RosterItem* contact) { connect(contact, &RosterItem::needHistory, this->acc, &Account::onContactNeedHistory); - connect(contact, &RosterItem::historyResponse, this->acc, &Account::onContactHistoryResponse); + connect(contact, &RosterItem::historyResponse, this, &RosterHandler::onContactHistoryResponse); connect(contact, &RosterItem::nameChanged, this, &RosterHandler::onContactNameChanged); connect(contact, &RosterItem::avatarChanged, this, &RosterHandler::onContactAvatarChanged); connect(contact, &RosterItem::requestVCard, this->acc, &Account::requestVCard); @@ -315,6 +315,14 @@ void Core::RosterHandler::removeFromGroup(const QString& jid, const QString& gro } } +void Core::RosterHandler::onContactHistoryResponse(const std::list& list) +{ + RosterItem* contact = static_cast(sender()); + + qDebug() << "Collected history for contact " << contact->jid << list.size() << "elements"; + emit acc->responseArchive(contact->jid, list); +} + Core::RosterItem * Core::RosterHandler::getRosterItem(const QString& jid) { RosterItem* item = 0; diff --git a/core/handlers/rosterhandler.h b/core/handlers/rosterhandler.h index b1dfc45..c01f396 100644 --- a/core/handlers/rosterhandler.h +++ b/core/handlers/rosterhandler.h @@ -86,6 +86,7 @@ private slots: void onContactGroupRemoved(const QString& group); void onContactNameChanged(const QString& name); void onContactSubscriptionStateChanged(Shared::SubscriptionState state); + void onContactHistoryResponse(const std::list& list); void onContactAvatarChanged(Shared::Avatar, const QString& path); private: diff --git a/core/networkaccess.cpp b/core/networkaccess.cpp index eece379..2d66a70 100644 --- a/core/networkaccess.cpp +++ b/core/networkaccess.cpp @@ -16,17 +16,13 @@ * along with this program. If not, see . */ - -#include -#include - #include "networkaccess.h" Core::NetworkAccess::NetworkAccess(QObject* parent): QObject(parent), running(false), manager(0), - storage("fileURLStorage"), + files("files"), downloads(), uploads() { @@ -37,31 +33,60 @@ Core::NetworkAccess::~NetworkAccess() stop(); } -void Core::NetworkAccess::downladFile(const QString& url) +void Core::NetworkAccess::fileLocalPathRequest(const QString& messageId, const QString& url) { std::map::iterator itr = downloads.find(url); if (itr != downloads.end()) { - qDebug() << "NetworkAccess received a request to download a file" << url << ", but the file is currently downloading, skipping"; + 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 { - 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); - } + QString path = files.getRecord(url); + QFileInfo info(path); + if (info.exists() && info.isFile()) { + emit fileLocalPathResponse(messageId, path); } else { - startDownload(p.second, url); + files.removeRecord(url); + emit fileLocalPathResponse(messageId, ""); } } catch (const Archive::NotFound& e) { - 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); + emit fileLocalPathResponse(messageId, ""); } catch (const Archive::Unknown& e) { qDebug() << "Error requesting file path:" << e.what(); - emit loadFileError(std::list(), QString("Database error: ") + e.what(), false); + 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()); } } } @@ -70,7 +95,7 @@ void Core::NetworkAccess::start() { if (!running) { manager = new QNetworkAccessManager(); - storage.open(); + files.open(); running = true; } } @@ -78,7 +103,7 @@ void Core::NetworkAccess::start() void Core::NetworkAccess::stop() { if (running) { - storage.close(); + files.close(); manager->deleteLater(); manager = 0; running = false; @@ -103,7 +128,9 @@ void Core::NetworkAccess::onDownloadProgress(qint64 bytesReceived, qint64 bytesT qreal total = bytesTotal; qreal progress = received/total; dwn->progress = progress; - emit loadFileProgress(dwn->messages, progress, false); + for (std::set::const_iterator mItr = dwn->messages.begin(), end = dwn->messages.end(); mItr != end; ++mItr) { + emit downloadFileProgress(*mItr, progress); + } } } @@ -119,7 +146,9 @@ void Core::NetworkAccess::onDownloadError(QNetworkReply::NetworkError code) if (errorText.size() > 0) { itr->second->success = false; Transfer* dwn = itr->second; - emit loadFileError(dwn->messages, errorText, false); + for (std::set::const_iterator mItr = dwn->messages.begin(), end = dwn->messages.end(); mItr != end; ++mItr) { + emit downloadFileError(*mItr, errorText); + } } } } @@ -247,54 +276,61 @@ 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 there is no record of it being downloaded, ignoring"; + qDebug() << "an error downloading" << url << ": the request is done but seems like noone is waiting for it, skipping"; } else { Transfer* dwn = itr->second; if (dwn->success) { qDebug() << "download success for" << url; QStringList hops = url.split("/"); QString fileName = hops.back(); - QString jid; - if (dwn->messages.size() > 0) { - jid = dwn->messages.front().jid; + 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 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(); - } + 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); } - if (path.size() > 0) { - emit downloadFileComplete(dwn->messages, path); + 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"; } else { - //TODO do I need to handle the failure here or it's already being handled in error? - //emit loadFileError(dwn->messages, path, false); + qDebug() << "couldn't save file" << path; + path = ""; } } + 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 std::list& msgs, const QString& url) +void Core::NetworkAccess::startDownload(const QString& messageId, const QString& url) { - Transfer* dwn = new Transfer({msgs, 0, 0, true, "", url, 0}); + Transfer* dwn = new Transfer({{messageId}, 0, 0, true, "", url, 0}); QNetworkRequest req(url); dwn->reply = manager->get(req); connect(dwn->reply, &QNetworkReply::downloadProgress, this, &NetworkAccess::onDownloadProgress); @@ -305,7 +341,7 @@ void Core::NetworkAccess::startDownload(const std::list& ms #endif connect(dwn->reply, &QNetworkReply::finished, this, &NetworkAccess::onDownloadFinished); downloads.insert(std::make_pair(url, dwn)); - emit loadFileProgress(dwn->messages, 0, false); + emit downloadFileProgress(messageId, 0); } void Core::NetworkAccess::onUploadError(QNetworkReply::NetworkError code) @@ -314,16 +350,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 there is no record of it being uploading, ignoring"; + qDebug() << "an error uploading" << url << ": the request is reporting an error but seems like noone is waiting for it, skipping"; } else { QString errorText = getErrorText(code); if (errorText.size() > 0) { itr->second->success = false; Transfer* upl = itr->second; - emit loadFileError(upl->messages, errorText, true); + for (std::set::const_iterator mItr = upl->messages.begin(), end = upl->messages.end(); mItr != end; ++mItr) { + emit uploadFileError(*mItr, errorText); + } } - - //TODO deletion? } } @@ -333,14 +369,17 @@ 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 there is no record of it being uploading, ignoring"; + qDebug() << "an error uploading" << url << ": the request is done but seems like no one is waiting for it, skipping"; } else { Transfer* upl = itr->second; if (upl->success) { qDebug() << "upload success for" << url; - - storage.addFile(upl->messages, upl->url, upl->path); - emit uploadFileComplete(upl->messages, upl->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); + } } upl->reply->deleteLater(); @@ -364,29 +403,94 @@ void Core::NetworkAccess::onUploadProgress(qint64 bytesReceived, qint64 bytesTot qreal total = bytesTotal; qreal progress = received/total; upl->progress = progress; - emit loadFileProgress(upl->messages, progress, true); + 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()); + } } } QString Core::NetworkAccess::getFileRemoteUrl(const QString& path) { - QString p; - - try { - p = storage.getUrl(path); - } catch (const Archive::NotFound& err) { - - } catch (...) { - throw; - } - - return p; + 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 } -void Core::NetworkAccess::uploadFile(const Shared::MessageInfo& info, const QString& path, const QUrl& put, const QUrl& get, const QMap headers) +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) { QFile* file = new QFile(path); - Transfer* upl = new Transfer({{info}, 0, 0, true, path, get.toString(), file}); + Transfer* upl = new Transfer({{messageId}, 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()); @@ -402,99 +506,10 @@ void Core::NetworkAccess::uploadFile(const Shared::MessageInfo& info, const QStr #endif connect(upl->reply, &QNetworkReply::finished, this, &NetworkAccess::onUploadFinished); uploads.insert(std::make_pair(put.toString(), upl)); - emit loadFileProgress(upl->messages, 0, true); + emit downloadFileProgress(messageId, 0); } else { qDebug() << "couldn't upload file" << path; - emit loadFileError(upl->messages, "Error opening file", true); + emit uploadFileError(messageId, "Error opening file"); 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); -} - -std::list Core::NetworkAccess::reportPathInvalid(const QString& path) -{ - return storage.deletedFile(path); -} diff --git a/core/networkaccess.h b/core/networkaccess.h index 5b9eae2..824b1af 100644 --- a/core/networkaccess.h +++ b/core/networkaccess.h @@ -29,15 +29,13 @@ #include -#include "urlstorage.h" +#include "storage.h" 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 @@ -50,27 +48,26 @@ public: void stop(); QString getFileRemoteUrl(const QString& path); - 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); - std::list reportPathInvalid(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); signals: - 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); + 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); public slots: - 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); + 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); private: - void startDownload(const std::list& msgs, const QString& url); + void startDownload(const QString& messageId, const QString& url); + void startUpload(const QString& messageId, const QString& url, const QString& path); 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); @@ -83,12 +80,12 @@ private slots: private: bool running; QNetworkAccessManager* manager; - UrlStorage storage; + Storage files; std::map downloads; std::map uploads; struct Transfer { - std::list messages; + std::set messages; qreal progress; QNetworkReply* reply; bool success; diff --git a/core/passwordStorageEngines/CMakeLists.txt b/core/passwordStorageEngines/CMakeLists.txt index 735c0ad..e824f77 100644 --- a/core/passwordStorageEngines/CMakeLists.txt +++ b/core/passwordStorageEngines/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.3) +cmake_minimum_required(VERSION 3.0) project(pse) if (WITH_KWALLET) @@ -14,7 +14,7 @@ if (WITH_KWALLET) kwallet.cpp ) - add_library(kwalletPSE STATIC ${kwalletPSE_SRC}) + add_library(kwalletPSE ${kwalletPSE_SRC}) target_include_directories(kwalletPSE PUBLIC ${KWALLET_INTERFACE_INCLUDE_DIRECTORIES}) target_include_directories(kwalletPSE PUBLIC ${Qt5GUI_INTERFACE_INCLUDE_DIRECTORIES}) diff --git a/core/rosteritem.cpp b/core/rosteritem.cpp index b1951d6..32b70f4 100644 --- a/core/rosteritem.cpp +++ b/core/rosteritem.cpp @@ -122,22 +122,7 @@ void Core::RosterItem::nextRequest() { if (syncronizing) { if (requestedCount != -1) { - bool last = false; - if (archiveState == beginning || archiveState == complete) { - QString firstId = archive->oldestId(); - if (responseCache.size() == 0) { - if (requestedBefore == firstId) { - last = true; - } - } else { - if (responseCache.front().getId() == firstId) { - last = true; - } - } - } else if (archiveState == empty && responseCache.size() == 0) { - last = true; - } - emit historyResponse(responseCache, last); + emit historyResponse(responseCache); } } if (requestCache.size() > 0) { @@ -375,11 +360,6 @@ void Core::RosterItem::flushMessagesToArchive(bool finished, const QString& firs archiveState = complete; archive->setFromTheBeginning(true); } - if (added == 0 && wasEmpty) { - archiveState = empty; - nextRequest(); - break; - } if (requestedCount != -1) { QString before; if (responseCache.size() > 0) { @@ -398,7 +378,7 @@ void Core::RosterItem::flushMessagesToArchive(bool finished, const QString& firs } catch (const Archive::Empty& e) { } - if (!found || requestedCount > int(responseCache.size())) { + if (!found || requestedCount > responseCache.size()) { if (archiveState == complete) { nextRequest(); } else { @@ -549,7 +529,7 @@ void Core::RosterItem::clearArchiveRequests() requestedBefore = ""; for (const std::pair& pair : requestCache) { if (pair.first != -1) { - emit historyResponse(responseCache, false); //just to notify those who still waits with whatever happened to be left in caches yet + emit historyResponse(responseCache); //just to notify those who still waits with whatever happened to be left in caches yet } responseCache.clear(); } @@ -569,20 +549,3 @@ void Core::RosterItem::downgradeDatabaseState() archiveState = ArchiveState::chunk; } } - -Shared::Message Core::RosterItem::getMessage(const QString& id) -{ - for (const Shared::Message& msg : appendCache) { - if (msg.getId() == id) { - return msg; - } - } - - for (Shared::Message& msg : hisoryCache) { - if (msg.getId() == id) { - return msg; - } - } - - return archive->getElement(id); -} diff --git a/core/rosteritem.h b/core/rosteritem.h index 237a46a..4113b37 100644 --- a/core/rosteritem.h +++ b/core/rosteritem.h @@ -78,12 +78,10 @@ public: void clearArchiveRequests(); void downgradeDatabaseState(); - Shared::Message getMessage(const QString& id); - signals: void nameChanged(const QString& name); void subscriptionStateChanged(Shared::SubscriptionState state); - void historyResponse(const std::list& messages, bool last); + void historyResponse(const std::list& messages); void needHistory(const QString& before, const QString& after, const QDateTime& afterTime = QDateTime()); void avatarChanged(Shared::Avatar, const QString& path); void requestVCard(const QString& jid); diff --git a/core/squawk.cpp b/core/squawk.cpp index 411d4ab..1689d71 100644 --- a/core/squawk.cpp +++ b/core/squawk.cpp @@ -32,10 +32,11 @@ Core::Squawk::Squawk(QObject* parent): ,kwallet() #endif { - 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); + connect(&network, &NetworkAccess::fileLocalPathResponse, this, &Squawk::fileLocalPathResponse); + 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); #ifdef WITH_KWALLET if (kwallet.supportState() == PSE::KWallet::success) { @@ -167,7 +168,7 @@ void Core::Squawk::addAccount( connect(acc, &Account::receivedVCard, this, &Squawk::responseVCard); - connect(acc, &Account::uploadFileError, this, &Squawk::onAccountUploadFileError); + connect(acc, &Account::uploadFileError, this, &Squawk::uploadFileError); QMap map = { {"login", login}, @@ -335,6 +336,17 @@ void Core::Squawk::sendMessage(const QString& account, const Shared::Message& da itr->second->sendMessage(data); } +void Core::Squawk::sendMessage(const QString& account, const Shared::Message& data, const QString& path) +{ + AccountsMap::const_iterator itr = amap.find(account); + if (itr == amap.end()) { + qDebug("An attempt to send a message with non existing account, skipping"); + return; + } + + itr->second->sendMessage(data, path); +} + void Core::Squawk::requestArchive(const QString& account, const QString& jid, int count, const QString& before) { AccountsMap::const_iterator itr = amap.find(account); @@ -345,10 +357,10 @@ void Core::Squawk::requestArchive(const QString& account, const QString& jid, in itr->second->requestArchive(jid, count, before); } -void Core::Squawk::onAccountResponseArchive(const QString& jid, const std::list& list, bool last) +void Core::Squawk::onAccountResponseArchive(const QString& jid, const std::list& list) { Account* acc = static_cast(sender()); - emit responseArchive(acc->getName(), jid, list, last); + emit responseArchive(acc->getName(), jid, list); } void Core::Squawk::modifyAccountRequest(const QString& name, const QMap& map) @@ -592,9 +604,14 @@ void Core::Squawk::addRoomRequest(const QString& account, const QString& jid, co itr->second->addRoomRequest(jid, nick, password, autoJoin); } -void Core::Squawk::fileDownloadRequest(const QString& url) +void Core::Squawk::fileLocalPathRequest(const QString& messageId, const QString& url) { - network.downladFile(url); + network.fileLocalPathRequest(messageId, url); +} + +void Core::Squawk::downloadFileRequest(const QString& messageId, const QString& url) +{ + network.downladFileRequest(messageId, url); } void Core::Squawk::addContactToGroupRequest(const QString& account, const QString& jid, const QString& groupName) @@ -671,7 +688,7 @@ void Core::Squawk::readSettings() settings.value("login").toString(), settings.value("server").toString(), settings.value("password", "").toString(), - settings.value("name").toString(), + settings.value("name").toString(), settings.value("resource").toString(), Shared::Global::fromInt(settings.value("passwordType", static_cast(Shared::AccountPassword::plain)).toInt()) ); @@ -745,26 +762,3 @@ void Core::Squawk::onWalletResponsePassword(const QString& login, const QString& emit changeAccount(login, {{"password", password}}); accountReady(); } - -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); -} - -void Core::Squawk::onLocalPathInvalid(const QString& path) -{ - std::list list = network.reportPathInvalid(path); - - QMap data({ - {"attachPath", ""} - }); - for (const Shared::MessageInfo& info : list) { - AccountsMap::const_iterator itr = amap.find(info.account); - if (itr != amap.end()) { - itr->second->requestChangeMessage(info.jid, info.messageId, data); - } else { - qDebug() << "Reacting on failure to reach file" << path << "there was an attempt to change message in account" << info.account << "which doesn't exist, skipping"; - } - } -} diff --git a/core/squawk.h b/core/squawk.h index 25fdbda..31812d2 100644 --- a/core/squawk.h +++ b/core/squawk.h @@ -51,39 +51,31 @@ 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 responseArchive(const QString& account, const QString& jid, const std::list& list); 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 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 fileLocalPathResponse(const QString& messageId, const QString& path); + 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 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); @@ -91,18 +83,15 @@ 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 sendMessage(const QString& account, const Shared::Message& data, const QString& path); 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); @@ -110,18 +99,15 @@ 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 fileDownloadRequest(const QString& url); - + void fileLocalPathRequest(const QString& messageId, const QString& url); + void downloadFileRequest(const QString& messageId, 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); - void onLocalPathInvalid(const QString& path); private: typedef std::deque Accounts; @@ -160,7 +146,7 @@ private slots: void onAccountAddPresence(const QString& jid, const QString& name, const QMap& data); void onAccountRemovePresence(const QString& jid, const QString& name); void onAccountMessage(const Shared::Message& data); - void onAccountResponseArchive(const QString& jid, const std::list& list, bool last); + void onAccountResponseArchive(const QString& jid, const std::list& list); void onAccountAddRoom(const QString jid, const QMap& data); void onAccountChangeRoom(const QString jid, const QMap& data); void onAccountRemoveRoom(const QString jid); @@ -169,8 +155,6 @@ 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); diff --git a/core/urlstorage.cpp b/core/urlstorage.cpp deleted file mode 100644 index 109cfea..0000000 --- a/core/urlstorage.cpp +++ /dev/null @@ -1,491 +0,0 @@ -/* - * 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 -#include -#include - -#include "urlstorage.h" - -Core::UrlStorage::UrlStorage(const QString& p_name): - name(p_name), - opened(false), - environment(), - base(), - map() -{ -} - -Core::UrlStorage::~UrlStorage() -{ - close(); -} - -void Core::UrlStorage::open() -{ - if (!opened) { - mdb_env_create(&environment); - QString path(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)); - path += "/" + name; - QDir cache(path); - - if (!cache.exists()) { - bool res = cache.mkpath(path); - if (!res) { - throw Archive::Directory(path.toStdString()); - } - } - - mdb_env_set_maxdbs(environment, 2); - mdb_env_set_mapsize(environment, 10UL * 1024UL * 1024UL); - mdb_env_open(environment, path.toStdString().c_str(), 0, 0664); - - MDB_txn *txn; - mdb_txn_begin(environment, NULL, 0, &txn); - mdb_dbi_open(txn, "base", MDB_CREATE, &base); - mdb_dbi_open(txn, "map", MDB_CREATE, &map); - mdb_txn_commit(txn); - opened = true; - } -} - -void Core::UrlStorage::close() -{ - if (opened) { - mdb_dbi_close(environment, map); - mdb_dbi_close(environment, base); - mdb_env_close(environment); - opened = false; - } -} - -void Core::UrlStorage::writeInfo(const QString& key, const Core::UrlStorage::UrlInfo& info, bool overwrite) -{ - MDB_txn *txn; - mdb_txn_begin(environment, NULL, 0, &txn); - - try { - writeInfo(key, info, txn, overwrite); - mdb_txn_commit(txn); - } catch (...) { - mdb_txn_abort(txn); - throw; - } -} - -void Core::UrlStorage::writeInfo(const QString& key, const Core::UrlStorage::UrlInfo& info, MDB_txn* txn, bool overwrite) -{ - QByteArray ba; - QDataStream ds(&ba, QIODevice::WriteOnly); - info.serialize(ds); - - const std::string& id = key.toStdString(); - MDB_val lmdbKey, lmdbData; - lmdbKey.mv_size = id.size(); - lmdbKey.mv_data = (char*)id.c_str(); - lmdbData.mv_size = ba.size(); - lmdbData.mv_data = (uint8_t*)ba.data(); - - int rc; - rc = mdb_put(txn, base, &lmdbKey, &lmdbData, overwrite ? 0 : MDB_NOOVERWRITE); - - if (rc != 0) { - if (rc == MDB_KEYEXIST) { - if (!overwrite) { - throw Archive::Exist(name.toStdString(), id); - } - } else { - throw Archive::Unknown(name.toStdString(), mdb_strerror(rc)); - } - } - - if (info.hasPath()) { - std::string sp = info.getPath().toStdString(); - lmdbData.mv_size = sp.size(); - lmdbData.mv_data = (char*)sp.c_str(); - rc = mdb_put(txn, map, &lmdbData, &lmdbKey, 0); - if (rc != 0) { - throw Archive::Unknown(name.toStdString(), mdb_strerror(rc)); - } - } -} - -void Core::UrlStorage::readInfo(const QString& key, Core::UrlStorage::UrlInfo& info, MDB_txn* txn) -{ - const std::string& id = key.toStdString(); - MDB_val lmdbKey, lmdbData; - lmdbKey.mv_size = id.size(); - lmdbKey.mv_data = (char*)id.c_str(); - int rc = mdb_get(txn, base, &lmdbKey, &lmdbData); - - if (rc == 0) { - QByteArray ba((char*)lmdbData.mv_data, lmdbData.mv_size); - QDataStream ds(&ba, QIODevice::ReadOnly); - - info.deserialize(ds); - } else if (rc == MDB_NOTFOUND) { - throw Archive::NotFound(id, name.toStdString()); - } else { - throw Archive::Unknown(name.toStdString(), mdb_strerror(rc)); - } -} - -void Core::UrlStorage::readInfo(const QString& key, Core::UrlStorage::UrlInfo& info) -{ - MDB_txn *txn; - mdb_txn_begin(environment, NULL, MDB_RDONLY, &txn); - - try { - readInfo(key, info, txn); - mdb_txn_commit(txn); - } catch (...) { - mdb_txn_abort(txn); - throw; - } -} - -void Core::UrlStorage::addFile(const QString& url) -{ - if (!opened) { - throw Archive::Closed("addFile(no message, no path)", name.toStdString()); - } - - addToInfo(url, "", "", ""); -} - -void Core::UrlStorage::addFile(const QString& url, const QString& path) -{ - if (!opened) { - throw Archive::Closed("addFile(no message, with path)", name.toStdString()); - } - - addToInfo(url, "", "", "", path); -} - -void Core::UrlStorage::addFile(const QString& url, const QString& account, const QString& jid, const QString& id) -{ - if (!opened) { - throw Archive::Closed("addFile(with message, no path)", name.toStdString()); - } - - addToInfo(url, account, jid, id); -} - -void Core::UrlStorage::addFile(const QString& url, const QString& path, const QString& account, const QString& jid, const QString& id) -{ - if (!opened) { - throw Archive::Closed("addFile(with message, with path)", name.toStdString()); - } - - 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) -{ - 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); - - try { - readInfo(url, info, txn); - } catch (const Archive::NotFound& e) { - - } catch (...) { - mdb_txn_abort(txn); - throw; - } - - 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 list; - - MDB_txn *txn; - mdb_txn_begin(environment, NULL, 0, &txn); - UrlInfo info; - - try { - readInfo(url, info, txn); - info.getMessages(list); - } catch (const Archive::NotFound& e) { - } 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; - } - - return list; -} - -std::list Core::UrlStorage::removeFile(const QString& url) -{ - std::list list; - - MDB_txn *txn; - mdb_txn_begin(environment, NULL, 0, &txn); - UrlInfo info; - - try { - std::string id = url.toStdString(); - readInfo(url, info, txn); - info.getMessages(list); - - MDB_val lmdbKey; - lmdbKey.mv_size = id.size(); - lmdbKey.mv_data = (char*)id.c_str(); - int rc = mdb_del(txn, base, &lmdbKey, NULL); - if (rc != 0) { - throw Archive::Unknown(name.toStdString(), mdb_strerror(rc)); - } - - if (info.hasPath()) { - std::string path = info.getPath().toStdString(); - lmdbKey.mv_size = path.size(); - lmdbKey.mv_data = (char*)path.c_str(); - - int rc = mdb_del(txn, map, &lmdbKey, NULL); - if (rc != 0) { - throw Archive::Unknown(name.toStdString(), mdb_strerror(rc)); - } - } - mdb_txn_commit(txn); - } catch (...) { - mdb_txn_abort(txn); - throw; - } - - return list; -} - -std::list Core::UrlStorage::deletedFile(const QString& path) -{ - std::list list; - - MDB_txn *txn; - mdb_txn_begin(environment, NULL, 0, &txn); - - try { - 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()); - } else if (rc == MDB_NOTFOUND) { - qDebug() << "Have been asked to remove file" << path << ", which isn't in the database, skipping"; - mdb_txn_abort(txn); - return list; - } else { - throw Archive::Unknown(name.toStdString(), mdb_strerror(rc)); - } - - UrlInfo info; - std::string id = url.toStdString(); - readInfo(url, info, txn); - info.getMessages(list); - info.setPath(QString()); - writeInfo(url, info, txn, true); - - rc = mdb_del(txn, map, &lmdbKey, NULL); - if (rc != 0) { - throw Archive::Unknown(name.toStdString(), mdb_strerror(rc)); - } - - mdb_txn_commit(txn); - } catch (...) { - mdb_txn_abort(txn); - throw; - } - - return list; -} - - -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() {} - -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() {} - -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(); - data << quint32(size); - for (const Shared::MessageInfo& info : messages) { - data << info.account; - data << info.jid; - data << info.messageId; - } -} - -void Core::UrlStorage::UrlInfo::deserialize(QDataStream& data) -{ - data >> localPath; - quint32 size; - data >> size; - for (quint32 i = 0; i < size; ++i) { - messages.emplace_back(); - Shared::MessageInfo& info = messages.back(); - data >> info.account; - data >> info.jid; - data >> info.messageId; - } -} - -void Core::UrlStorage::UrlInfo::getMessages(std::list& container) const -{ - for (const Shared::MessageInfo& info : messages) { - container.emplace_back(info); - } -} - -QString Core::UrlStorage::UrlInfo::getPath() const -{ - return localPath; -} - -bool Core::UrlStorage::UrlInfo::hasPath() const -{ - return localPath.size() > 0; -} - - -void Core::UrlStorage::UrlInfo::setPath(const QString& path) -{ - localPath = path; -} diff --git a/core/urlstorage.h b/core/urlstorage.h deleted file mode 100644 index 3dc5c21..0000000 --- a/core/urlstorage.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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 CORE_URLSTORAGE_H -#define CORE_URLSTORAGE_H - -#include -#include -#include -#include - -#include "archive.h" -#include - -namespace Core { - -/** - * @todo write docs - */ -class UrlStorage -{ - class UrlInfo; -public: - UrlStorage(const QString& name); - ~UrlStorage(); - - void open(); - void close(); - - void addFile(const QString& url); - 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); - 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; - bool opened; - MDB_env* environment; - MDB_dbi base; - MDB_dbi map; - -private: - void writeInfo(const QString& key, const UrlInfo& info, bool overwrite = false); - 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(); - - void serialize(QDataStream& data) const; - void deserialize(QDataStream& data); - - QString getPath() const; - bool hasPath() const; - void setPath(const QString& path); - - bool addMessage(const QString& acc, const QString& jid, const QString& id); - void getMessages(std::list& container) const; - - private: - QString localPath; - std::list messages; - }; - - -}; - -} - -#endif // CORE_URLSTORAGE_H diff --git a/external/simpleCrypt/CMakeLists.txt b/external/simpleCrypt/CMakeLists.txt index 88f5d23..bdb62c6 100644 --- a/external/simpleCrypt/CMakeLists.txt +++ b/external/simpleCrypt/CMakeLists.txt @@ -10,7 +10,7 @@ set(simplecrypt_SRC ) # Tell CMake to create the helloworld executable -add_library(simpleCrypt STATIC ${simplecrypt_SRC}) +add_library(simpleCrypt ${simplecrypt_SRC}) # Use the Widgets module from Qt 5. target_link_libraries(simpleCrypt Qt5::Core) diff --git a/main.cpp b/main.cpp index 210dd70..4c4b3ea 100644 --- a/main.cpp +++ b/main.cpp @@ -20,7 +20,6 @@ #include "core/squawk.h" #include "signalcatcher.h" #include "shared/global.h" -#include "shared/messageinfo.h" #include #include #include @@ -32,10 +31,8 @@ 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"); @@ -99,7 +96,10 @@ int main(int argc, char *argv[]) QObject::connect(&w, &Squawk::connectAccount, squawk, &Core::Squawk::connectAccount); QObject::connect(&w, &Squawk::disconnectAccount, squawk, &Core::Squawk::disconnectAccount); QObject::connect(&w, &Squawk::changeState, squawk, &Core::Squawk::changeState); - QObject::connect(&w, &Squawk::sendMessage, squawk,&Core::Squawk::sendMessage); + QObject::connect(&w, qOverload(&Squawk::sendMessage), + squawk, qOverload(&Core::Squawk::sendMessage)); + QObject::connect(&w, qOverload(&Squawk::sendMessage), + squawk, qOverload(&Core::Squawk::sendMessage)); QObject::connect(&w, &Squawk::requestArchive, squawk, &Core::Squawk::requestArchive); QObject::connect(&w, &Squawk::subscribeContact, squawk, &Core::Squawk::subscribeContact); QObject::connect(&w, &Squawk::unsubscribeContact, squawk, &Core::Squawk::unsubscribeContact); @@ -109,14 +109,14 @@ 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::fileDownloadRequest, squawk, &Core::Squawk::fileDownloadRequest); + QObject::connect(&w, &Squawk::fileLocalPathRequest, squawk, &Core::Squawk::fileLocalPathRequest); + QObject::connect(&w, &Squawk::downloadFileRequest, squawk, &Core::Squawk::downloadFileRequest); 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); QObject::connect(&w, &Squawk::requestVCard, squawk, &Core::Squawk::requestVCard); QObject::connect(&w, &Squawk::uploadVCard, squawk, &Core::Squawk::uploadVCard); QObject::connect(&w, &Squawk::responsePassword, squawk, &Core::Squawk::responsePassword); - QObject::connect(&w, &Squawk::localPathInvalid, squawk, &Core::Squawk::onLocalPathInvalid); QObject::connect(squawk, &Core::Squawk::newAccount, &w, &Squawk::newAccount); QObject::connect(squawk, &Core::Squawk::addContact, &w, &Squawk::addContact); @@ -141,10 +141,11 @@ 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::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::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::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/plugins/CMakeLists.txt b/plugins/CMakeLists.txt deleted file mode 100644 index 69a5e94..0000000 --- a/plugins/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -cmake_minimum_required(VERSION 3.3) -project(plugins) - -if (WITH_KIO) - set(CMAKE_AUTOMOC ON) - - find_package(Qt5Core CONFIG REQUIRED) - - set(openFileManagerWindowJob_SRC - openfilemanagerwindowjob.cpp - ) - - add_library(openFileManagerWindowJob SHARED ${openFileManagerWindowJob_SRC}) - - get_target_property(Qt5CORE_INTERFACE_INCLUDE_DIRECTORIES Qt5::Core INTERFACE_INCLUDE_DIRECTORIES) - get_target_property(KIO_WIDGETS_INTERFACE_INCLUDE_DIRECTORIES KF5::KIOWidgets INTERFACE_INCLUDE_DIRECTORIES) - get_target_property(CORE_ADDONS_INTERFACE_INCLUDE_DIRECTORIES KF5::CoreAddons INTERFACE_INCLUDE_DIRECTORIES) - target_include_directories(openFileManagerWindowJob PUBLIC ${KIO_WIDGETS_INTERFACE_INCLUDE_DIRECTORIES}) - target_include_directories(openFileManagerWindowJob PUBLIC ${CORE_ADDONS_INTERFACE_INCLUDE_DIRECTORIES}) - target_include_directories(openFileManagerWindowJob PUBLIC ${Qt5CORE_INTERFACE_INCLUDE_DIRECTORIES}) - - target_link_libraries(openFileManagerWindowJob KF5::KIOWidgets) - target_link_libraries(openFileManagerWindowJob Qt5::Core) - - install(TARGETS openFileManagerWindowJob DESTINATION ${CMAKE_INSTALL_LIBDIR}) -endif() diff --git a/plugins/openfilemanagerwindowjob.cpp b/plugins/openfilemanagerwindowjob.cpp deleted file mode 100644 index 904fbcf..0000000 --- a/plugins/openfilemanagerwindowjob.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include -#include -#include - -extern "C" void highlightInFileManager(const QUrl& url) { - KIO::OpenFileManagerWindowJob* job = KIO::highlightInFileManager({url}); - QObject::connect(job, &KIO::OpenFileManagerWindowJob::result, job, &KIO::OpenFileManagerWindowJob::deleteLater); -} diff --git a/resources/images/fallback/dark/big/document-preview.svg b/resources/images/fallback/dark/big/document-preview.svg deleted file mode 100644 index 49a3feb..0000000 --- a/resources/images/fallback/dark/big/document-preview.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - diff --git a/resources/images/fallback/dark/big/folder.svg b/resources/images/fallback/dark/big/folder.svg deleted file mode 100644 index 2acb4ab..0000000 --- a/resources/images/fallback/dark/big/folder.svg +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/images/fallback/dark/small/document-preview.svg b/resources/images/fallback/dark/small/document-preview.svg deleted file mode 100644 index 43d19bf..0000000 --- a/resources/images/fallback/dark/small/document-preview.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/resources/images/fallback/dark/small/folder.svg b/resources/images/fallback/dark/small/folder.svg deleted file mode 100644 index 1061f4d..0000000 --- a/resources/images/fallback/dark/small/folder.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - diff --git a/resources/images/fallback/light/big/document-preview.svg b/resources/images/fallback/light/big/document-preview.svg deleted file mode 100644 index 6f6e346..0000000 --- a/resources/images/fallback/light/big/document-preview.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - diff --git a/resources/images/fallback/light/big/folder.svg b/resources/images/fallback/light/big/folder.svg deleted file mode 100644 index 2acb4ab..0000000 --- a/resources/images/fallback/light/big/folder.svg +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/images/fallback/light/small/document-preview.svg b/resources/images/fallback/light/small/document-preview.svg deleted file mode 100644 index f40fcdf..0000000 --- a/resources/images/fallback/light/small/document-preview.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/resources/images/fallback/light/small/folder.svg b/resources/images/fallback/light/small/folder.svg deleted file mode 100644 index a5f66cd..0000000 --- a/resources/images/fallback/light/small/folder.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - diff --git a/resources/resources.qrc b/resources/resources.qrc index 58565fc..4fb3e5b 100644 --- a/resources/resources.qrc +++ b/resources/resources.qrc @@ -40,8 +40,6 @@ images/fallback/dark/big/favorite.svg images/fallback/dark/big/unfavorite.svg images/fallback/dark/big/add.svg - images/fallback/dark/big/folder.svg - images/fallback/dark/big/document-preview.svg images/fallback/dark/small/absent.svg @@ -82,8 +80,6 @@ images/fallback/dark/small/favorite.svg images/fallback/dark/small/unfavorite.svg images/fallback/dark/small/add.svg - images/fallback/dark/small/folder.svg - images/fallback/dark/small/document-preview.svg images/fallback/light/big/absent.svg @@ -124,8 +120,6 @@ images/fallback/light/big/favorite.svg images/fallback/light/big/unfavorite.svg images/fallback/light/big/add.svg - images/fallback/light/big/folder.svg - images/fallback/light/big/document-preview.svg images/fallback/light/small/absent.svg @@ -166,7 +160,5 @@ images/fallback/light/small/favorite.svg images/fallback/light/small/unfavorite.svg images/fallback/light/small/add.svg - images/fallback/light/small/folder.svg - images/fallback/light/small/document-preview.svg diff --git a/shared.h b/shared.h index 3925ce2..83bcd76 100644 --- a/shared.h +++ b/shared.h @@ -25,6 +25,5 @@ #include "shared/message.h" #include "shared/vcard.h" #include "shared/global.h" -#include "shared/messageinfo.h" #endif // SHARED_H diff --git a/shared/global.cpp b/shared/global.cpp index 62843ed..a6b7b60 100644 --- a/shared/global.cpp +++ b/shared/global.cpp @@ -23,11 +23,6 @@ Shared::Global* Shared::Global::instance = 0; const std::set Shared::Global::supportedImagesExts = {"png", "jpg", "webp", "jpeg", "gif", "svg"}; -#ifdef WITH_KIO -QLibrary Shared::Global::openFileManagerWindowJob("openFileManagerWindowJob"); -Shared::Global::HighlightInFileManager Shared::Global::hfm = 0; -#endif - Shared::Global::Global(): availability({ tr("Online", "Availability"), @@ -85,61 +80,16 @@ Shared::Global::Global(): tr("Your password is going to be stored in KDE wallet storage (KWallet). You're going to be queried for permissions", "AccountPasswordDescription") }), pluginSupport({ - {"KWallet", false}, - {"openFileManagerWindowJob", false} - }), - fileCache() + {"KWallet", false} + }) { if (instance != 0) { throw 551; } instance = this; - -#ifdef WITH_KIO - openFileManagerWindowJob.load(); - if (openFileManagerWindowJob.isLoaded()) { - hfm = (HighlightInFileManager) openFileManagerWindowJob.resolve("highlightInFileManager"); - if (hfm) { - setSupported("openFileManagerWindowJob", true); - qDebug() << "KIO::OpenFileManagerWindow support enabled"; - } else { - qDebug() << "KIO::OpenFileManagerWindow support disabled: couldn't resolve required methods in the library"; - } - } else { - qDebug() << "KIO::OpenFileManagerWindow support disabled: couldn't load the library" << openFileManagerWindowJob.errorString(); - } -#endif } -Shared::Global::FileInfo Shared::Global::getFileInfo(const QString& path) -{ - std::map::const_iterator itr = instance->fileCache.find(path); - if (itr == instance->fileCache.end()) { - QMimeDatabase db; - QMimeType type = db.mimeTypeForFile(path); - QStringList parts = type.name().split("/"); - QString big = parts.front(); - QFileInfo info(path); - - FileInfo::Preview p = FileInfo::Preview::none; - QSize size; - if (big == "image") { - if (parts.back() == "gif") { - //TODO need to consider GIF as a movie - } - p = FileInfo::Preview::picture; - QImage img(path); - size = img.size(); - } - - itr = instance->fileCache.insert(std::make_pair(path, FileInfo({info.fileName(), size, type, p}))).first; - } - - return itr->second; -} - - Shared::Global * Shared::Global::getInstance() { return instance; @@ -202,69 +152,6 @@ QString Shared::Global::getDescription(Shared::AccountPassword ap) return instance->accountPasswordDescription[static_cast(ap)]; } - -static const QStringList query = {"query", "default", "inode/directory"}; -static const QRegularExpression dolphinReg("[Dd]olphin"); -static const QRegularExpression nautilusReg("[Nn]autilus"); -static const QRegularExpression cajaReg("[Cc]aja"); -static const QRegularExpression nemoReg("[Nn]emo"); -static const QRegularExpression konquerorReg("kfmclient"); -static const QRegularExpression pcmanfmQtReg("pcmanfm-qt"); -static const QRegularExpression pcmanfmReg("pcmanfm"); -static const QRegularExpression thunarReg("thunar"); - -void Shared::Global::highlightInFileManager(const QString& path) -{ -#ifdef WITH_KIO - if (supported("openFileManagerWindowJob")) { - hfm(path); - return; - } else { - qDebug() << "requested to highlight in file manager url" << path << "but it's not supported: KIO plugin isn't loaded, trying fallback"; - } -#else - qDebug() << "requested to highlight in file manager url" << path << "but it's not supported: squawk wasn't compiled to support it, trying fallback"; -#endif - - QFileInfo info = path; - if (info.exists()) { - QProcess proc; - proc.start("xdg-mime", query); - proc.waitForFinished(); - QString output = proc.readLine().simplified(); - - QString folder; - if (info.isDir()) { - folder = info.canonicalFilePath(); - } else { - folder = info.canonicalPath(); - } - - if (output.contains(dolphinReg)) { - //there is a bug on current (21.04.0) dolphin, it works correct only if you already have dolphin launched - proc.startDetached("dolphin", QStringList() << "--select" << info.canonicalFilePath()); - //KIO::highlightInFileManager({QUrl(info.canonicalFilePath())}); - } else if (output.contains(nautilusReg)) { - proc.startDetached("nautilus", QStringList() << "--select" << info.canonicalFilePath()); //this worked on nautilus - } else if (output.contains(cajaReg)) { - proc.startDetached("caja", QStringList() << folder); //caja doesn't seem to support file selection command line, gonna just open directory - } else if (output.contains(nemoReg)) { - proc.startDetached("nemo", QStringList() << info.canonicalFilePath()); //nemo supports selecting files without keys - } else if (output.contains(konquerorReg)) { - proc.startDetached("konqueror", QStringList() << "--select" << info.canonicalFilePath()); //this worked on konqueror - } else if (output.contains(pcmanfmQtReg)) { - proc.startDetached("pcmanfm-qt", QStringList() << folder); //pcmanfm-qt doesn't seem to support open with selection, gonna just open directory - } else if (output.contains(pcmanfmReg)) { - proc.startDetached("pcmanfm", QStringList() << folder); //pcmanfm also doesn't seem to support open with selection, gonna just open directory - } else if (output.contains(thunarReg)) { - proc.startDetached("thunar", QStringList() << folder); //thunar doesn't seem to support open with selection, gonna just open directory - } else { - QDesktopServices::openUrl(QUrl::fromLocalFile(folder)); - } - } -} - - #define FROM_INT_INPL(Enum) \ template<> \ Enum Shared::Global::fromInt(int src) \ diff --git a/shared/global.h b/shared/global.h index b6bbe37..54e1584 100644 --- a/shared/global.h +++ b/shared/global.h @@ -29,17 +29,6 @@ #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include namespace Shared { @@ -47,19 +36,6 @@ namespace Shared { Q_DECLARE_TR_FUNCTIONS(Global) public: - struct FileInfo { - enum class Preview { - none, - picture, - movie - }; - - QString name; - QSize size; - QMimeType mime; - Preview preview; - }; - Global(); static Global* getInstance(); @@ -88,9 +64,6 @@ namespace Shared { static const std::set supportedImagesExts; - static FileInfo getFileInfo(const QString& path); - static void highlightInFileManager(const QString& path); - template static T fromInt(int src); @@ -114,15 +87,6 @@ namespace Shared { static Global* instance; std::map pluginSupport; - std::map fileCache; - -#ifdef WITH_KIO - static QLibrary openFileManagerWindowJob; - - typedef void (*HighlightInFileManager)(const QUrl &); - - static HighlightInFileManager hfm; -#endif }; } diff --git a/shared/icons.h b/shared/icons.h index 540d3e9..48ecc37 100644 --- a/shared/icons.h +++ b/shared/icons.h @@ -170,8 +170,6 @@ static const std::map> icons = { {"favorite", {"favorite", "favorite"}}, {"unfavorite", {"draw-star", "unfavorite"}}, {"list-add", {"list-add", "add"}}, - {"folder", {"folder", "folder"}}, - {"document-preview", {"document-preview", "document-preview"}} }; } diff --git a/shared/message.cpp b/shared/message.cpp index e6b47b2..af4f9e0 100644 --- a/shared/message.cpp +++ b/shared/message.cpp @@ -36,8 +36,7 @@ Shared::Message::Message(Shared::Message::Type p_type): errorText(), originalMessage(), lastModified(), - stanzaId(), - attachPath() + stanzaId() {} Shared::Message::Message(): @@ -57,8 +56,7 @@ Shared::Message::Message(): errorText(), originalMessage(), lastModified(), - stanzaId(), - attachPath() + stanzaId() {} QString Shared::Message::getBody() const @@ -313,7 +311,6 @@ void Shared::Message::serialize(QDataStream& data) const data << lastModified; } data << stanzaId; - data << attachPath; } void Shared::Message::deserialize(QDataStream& data) @@ -344,7 +341,6 @@ void Shared::Message::deserialize(QDataStream& data) data >> lastModified; } data >> stanzaId; - data >> attachPath; } bool Shared::Message::change(const QMap& data) @@ -354,16 +350,6 @@ bool Shared::Message::change(const QMap& data) setState(static_cast(itr.value().toUInt())); } - itr = data.find("outOfBandUrl"); - if (itr != data.end()) { - setOutOfBandUrl(itr.value().toString()); - } - - itr = data.find("attachPath"); - if (itr != data.end()) { - setAttachPath(itr.value().toString()); - } - if (state == State::error) { itr = data.find("errorText"); if (itr != data.end()) { @@ -394,29 +380,18 @@ bool Shared::Message::change(const QMap& data) itr = data.find("body"); if (itr != data.end()) { - QString b = itr.value().toString(); - if (body != b) { - QMap::const_iterator dItr = data.find("stamp"); - QDateTime correctionDate; - if (dItr != data.end()) { - correctionDate = dItr.value().toDateTime(); - } else { - correctionDate = QDateTime::currentDateTimeUtc(); //in case there is no information about time of this correction it's applied - } - if (!edited || lastModified < correctionDate) { - originalMessage = body; - lastModified = correctionDate; - setBody(body); - setEdited(true); - } - } - } else { QMap::const_iterator dItr = data.find("stamp"); + QDateTime correctionDate; if (dItr != data.end()) { - QDateTime ntime = dItr.value().toDateTime(); - if (time != ntime) { - setTime(ntime); - } + correctionDate = dItr.value().toDateTime(); + } else { + correctionDate = QDateTime::currentDateTimeUtc(); //in case there is no information about time of this correction it's applied + } + if (!edited || lastModified < correctionDate) { + originalMessage = body; + lastModified = correctionDate; + setBody(itr.value().toString()); + setEdited(true); } } @@ -445,7 +420,7 @@ void Shared::Message::setOutOfBandUrl(const QString& url) bool Shared::Message::storable() const { - return id.size() > 0 && (body.size() > 0 || oob.size() > 0 || attachPath.size() > 0); + return id.size() > 0 && (body.size() > 0 || oob.size()) > 0; } void Shared::Message::setStanzaId(const QString& sid) @@ -457,33 +432,3 @@ QString Shared::Message::getStanzaId() const { return stanzaId; } - -QString Shared::Message::getAttachPath() const -{ - return attachPath; -} - -void Shared::Message::setAttachPath(const QString& path) -{ - attachPath = path; -} - -Shared::Message::Change::Change(const QMap& _data): - data(_data), - idModified(false) {} - -void Shared::Message::Change::operator()(Shared::Message& msg) -{ - idModified = msg.change(data); -} - -void Shared::Message::Change::operator()(Shared::Message* msg) -{ - idModified = msg->change(data); -} - -bool Shared::Message::Change::hasIdBeenModified() const -{ - return idModified; -} - diff --git a/shared/message.h b/shared/message.h index aa91af6..d84053f 100644 --- a/shared/message.h +++ b/shared/message.h @@ -16,15 +16,15 @@ * along with this program. If not, see . */ -#ifndef SHAPER_MESSAGE_H -#define SHAPER_MESSAGE_H - #include #include #include #include #include +#ifndef SHAPER_MESSAGE_H +#define SHAPER_MESSAGE_H + namespace Shared { /** @@ -46,22 +46,9 @@ public: delivered, error }; - static const State StateHighest = State::error; static const State StateLowest = State::pending; - struct Change //change functor, stores in idModified if ID has been modified during change - { - Change(const QMap& _data); - void operator() (Message& msg); - void operator() (Message* msg); - bool hasIdBeenModified() const; - - private: - const QMap& data; - bool idModified; - }; - Message(Type p_type); Message(); @@ -85,7 +72,6 @@ public: void setErrorText(const QString& err); bool change(const QMap& data); void setStanzaId(const QString& sid); - void setAttachPath(const QString& path); QString getFrom() const; QString getFromJid() const; @@ -114,7 +100,6 @@ public: QDateTime getLastModified() const; QString getOriginalBody() const; QString getStanzaId() const; - QString getAttachPath() const; void serialize(QDataStream& data) const; void deserialize(QDataStream& data); @@ -138,7 +123,6 @@ private: QString originalMessage; QDateTime lastModified; QString stanzaId; - QString attachPath; }; } diff --git a/shared/messageinfo.cpp b/shared/messageinfo.cpp deleted file mode 100644 index 7502a6e..0000000 --- a/shared/messageinfo.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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 deleted file mode 100644 index 942d88c..0000000 --- a/shared/messageinfo.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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/shared/utils.h b/shared/utils.h index a8a17d5..e9e3d29 100644 --- a/shared/utils.h +++ b/shared/utils.h @@ -20,14 +20,11 @@ #define SHARED_UTILS_H #include -#include #include #include -//#include "KIO/OpenFileManagerWindowJob" - #include -#include +#include namespace Shared { diff --git a/ui/CMakeLists.txt b/ui/CMakeLists.txt index 11b8f3d..52913a8 100644 --- a/ui/CMakeLists.txt +++ b/ui/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.3) +cmake_minimum_required(VERSION 3.0) project(squawkUI) # Instruct CMake to run moc automatically when needed. @@ -7,13 +7,9 @@ set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) # Find the QtWidgets library -find_package(Qt5 CONFIG REQUIRED COMPONENTS Widgets DBus Core) -find_package(Boost 1.36.0 REQUIRED) -if(Boost_FOUND) - include_directories(${Boost_INCLUDE_DIRS}) -endif() +find_package(Qt5Widgets CONFIG REQUIRED) +find_package(Qt5DBus CONFIG REQUIRED) -add_subdirectory(utils) add_subdirectory(widgets) set(squawkUI_SRC @@ -29,15 +25,21 @@ set(squawkUI_SRC models/abstractparticipant.cpp models/participant.cpp models/reference.cpp - models/messagefeed.cpp - models/element.cpp + utils/messageline.cpp + utils//message.cpp + utils/resizer.cpp + utils/image.cpp + utils/flowlayout.cpp + utils/badge.cpp + utils/progress.cpp + utils/comboboxdelegate.cpp + utils/dropshadoweffect.cpp ) # Tell CMake to create the helloworld executable -add_library(squawkUI STATIC ${squawkUI_SRC}) +add_library(squawkUI ${squawkUI_SRC}) # Use the Widgets module from Qt 5. target_link_libraries(squawkUI squawkWidgets) -target_link_libraries(squawkUI squawkUIUtils) target_link_libraries(squawkUI Qt5::Widgets) target_link_libraries(squawkUI Qt5::DBus) diff --git a/ui/models/account.cpp b/ui/models/account.cpp index f8d0c37..00dd6b2 100644 --- a/ui/models/account.cpp +++ b/ui/models/account.cpp @@ -231,7 +231,7 @@ void Models::Account::toOfflineState() Item::toOfflineState(); } -QString Models::Account::getAvatarPath() const +QString Models::Account::getAvatarPath() { return avatarPath; } diff --git a/ui/models/account.h b/ui/models/account.h index 686d4da..2563382 100644 --- a/ui/models/account.h +++ b/ui/models/account.h @@ -57,7 +57,7 @@ namespace Models { QString getError() const; void setAvatarPath(const QString& path); - QString getAvatarPath() const; + QString getAvatarPath(); void setAvailability(Shared::Availability p_avail); void setAvailability(unsigned int p_avail); diff --git a/ui/models/contact.cpp b/ui/models/contact.cpp index 4c3432b..57744d8 100644 --- a/ui/models/contact.cpp +++ b/ui/models/contact.cpp @@ -17,26 +17,55 @@ */ #include "contact.h" +#include "account.h" #include Models::Contact::Contact(const Account* acc, const QString& p_jid ,const QMap &data, Item *parentItem): - Element(Item::contact, acc, p_jid, data, parentItem), + Item(Item::contact, data, parentItem), + jid(p_jid), availability(Shared::Availability::offline), state(Shared::SubscriptionState::none), + avatarState(Shared::Avatar::empty), presences(), - status() + messages(), + childMessages(0), + status(), + avatarPath(), + account(acc) { QMap::const_iterator itr = data.find("state"); if (itr != data.end()) { setState(itr.value().toUInt()); } + + itr = data.find("avatarState"); + if (itr != data.end()) { + setAvatarState(itr.value().toUInt()); + } + itr = data.find("avatarPath"); + if (itr != data.end()) { + setAvatarPath(itr.value().toString()); + } } Models::Contact::~Contact() { } +QString Models::Contact::getJid() const +{ + return jid; +} + +void Models::Contact::setJid(const QString p_jid) +{ + if (jid != p_jid) { + jid = p_jid; + changed(1); + } +} + void Models::Contact::setAvailability(unsigned int p_state) { setAvailability(Shared::Global::fromInt(p_state)); @@ -115,12 +144,16 @@ void Models::Contact::update(const QString& field, const QVariant& value) { if (field == "name") { setName(value.toString()); + } else if (field == "jid") { + setJid(value.toString()); } else if (field == "availability") { setAvailability(value.toUInt()); } else if (field == "state") { setState(value.toUInt()); - } else { - Element::update(field, value); + } else if (field == "avatarState") { + setAvatarState(value.toUInt()); + } else if (field == "avatarPath") { + setAvatarPath(value.toString()); } } @@ -159,9 +192,11 @@ void Models::Contact::refresh() { QDateTime lastActivity; Presence* presence = 0; + unsigned int count = 0; for (QMap::iterator itr = presences.begin(), end = presences.end(); itr != end; ++itr) { Presence* pr = itr.value(); QDateTime la = pr->getLastActivity(); + count += pr->getMessagesCount(); if (la > lastActivity) { lastActivity = la; @@ -176,6 +211,11 @@ void Models::Contact::refresh() setAvailability(Shared::Availability::offline); setStatus(""); } + + if (childMessages != count) { + childMessages = count; + changed(4); + } } void Models::Contact::_removeChild(int index) @@ -211,12 +251,87 @@ QIcon Models::Contact::getStatusIcon(bool big) const if (getMessagesCount() > 0) { return Shared::icon("mail-message", big); } else if (state == Shared::SubscriptionState::both || state == Shared::SubscriptionState::to) { - return Shared::availabilityIcon(availability, big); + return Shared::availabilityIcon(availability, big);; } else { return Shared::subscriptionStateIcon(state, big); } } +void Models::Contact::addMessage(const Shared::Message& data) +{ + const QString& res = data.getPenPalResource(); + if (res.size() > 0) { + QMap::iterator itr = presences.find(res); + if (itr == presences.end()) { + // this is actually the place when I can spot someone's invisible presence, and there is nothing criminal in it, cuz the sender sent us a message + // therefore he have revealed himself + // the only issue is to find out when the sender is gone offline + Presence* pr = new Presence({}); + pr->setName(res); + pr->setAvailability(Shared::Availability::invisible); + pr->setLastActivity(QDateTime::currentDateTimeUtc()); + presences.insert(res, pr); + appendChild(pr); + pr->addMessage(data); + return; + } + itr.value()->addMessage(data); + } else { + messages.emplace_back(data); + changed(4); + } +} + +void Models::Contact::changeMessage(const QString& id, const QMap& data) +{ + + bool found = false; + for (Shared::Message& msg : messages) { + if (msg.getId() == id) { + msg.change(data); + found = true; + break; + } + } + if (!found) { + for (Presence* pr : presences) { + found = pr->changeMessage(id, data); + if (found) { + break; + } + } + } +} + +unsigned int Models::Contact::getMessagesCount() const +{ + return messages.size() + childMessages; +} + +void Models::Contact::dropMessages() +{ + if (messages.size() > 0) { + messages.clear(); + changed(4); + } + + for (QMap::iterator itr = presences.begin(), end = presences.end(); itr != end; ++itr) { + itr.value()->dropMessages(); + } +} + +void Models::Contact::getMessages(Models::Contact::Messages& container) const +{ + for (Messages::const_iterator itr = messages.begin(), end = messages.end(); itr != end; ++itr) { + const Shared::Message& msg = *itr; + container.push_back(msg); + } + + for (QMap::const_iterator itr = presences.begin(), end = presences.end(); itr != end; ++itr) { + itr.value()->getMessages(container); + } +} + void Models::Contact::toOfflineState() { std::deque::size_type size = childItems.size(); @@ -240,3 +355,75 @@ QString Models::Contact::getDisplayedName() const return getContactName(); } +bool Models::Contact::columnInvolvedInDisplay(int col) +{ + return Item::columnInvolvedInDisplay(col) && col == 1; +} + +Models::Contact * Models::Contact::copy() const +{ + Contact* cnt = new Contact(*this); + return cnt; +} + +Models::Contact::Contact(const Models::Contact& other): + Item(other), + jid(other.jid), + availability(other.availability), + state(other.state), + presences(), + messages(other.messages), + childMessages(0), + account(other.account) +{ + for (const Presence* pres : other.presences) { + Presence* pCopy = new Presence(*pres); + presences.insert(pCopy->getName(), pCopy); + Item::appendChild(pCopy); + connect(pCopy, &Item::childChanged, this, &Contact::refresh); + } + + refresh(); +} + +QString Models::Contact::getAvatarPath() const +{ + return avatarPath; +} + +Shared::Avatar Models::Contact::getAvatarState() const +{ + return avatarState; +} + +void Models::Contact::setAvatarPath(const QString& path) +{ + if (path != avatarPath) { + avatarPath = path; + changed(7); + } +} + +void Models::Contact::setAvatarState(Shared::Avatar p_state) +{ + if (avatarState != p_state) { + avatarState = p_state; + changed(6); + } +} + +void Models::Contact::setAvatarState(unsigned int p_state) +{ + if (p_state <= static_cast(Shared::Avatar::valid)) { + Shared::Avatar state = static_cast(p_state); + setAvatarState(state); + } else { + qDebug() << "An attempt to set invalid avatar state" << p_state << "to the contact" << jid << ", skipping"; + } +} + +const Models::Account * Models::Contact::getParentAccount() const +{ + return account; +} + diff --git a/ui/models/contact.h b/ui/models/contact.h index 7e76f5b..c8c99b5 100644 --- a/ui/models/contact.h +++ b/ui/models/contact.h @@ -19,7 +19,7 @@ #ifndef MODELS_CONTACT_H #define MODELS_CONTACT_H -#include "element.h" +#include "item.h" #include "presence.h" #include "shared/enums.h" #include "shared/message.h" @@ -31,34 +31,49 @@ #include namespace Models { +class Account; -class Contact : public Element +class Contact : public Item { Q_OBJECT public: + typedef std::deque Messages; Contact(const Account* acc, const QString& p_jid, const QMap &data, Item *parentItem = 0); + Contact(const Contact& other); ~Contact(); + QString getJid() const; Shared::Availability getAvailability() const; Shared::SubscriptionState getState() const; - + Shared::Avatar getAvatarState() const; + QString getAvatarPath() const; QIcon getStatusIcon(bool big = false) const; int columnCount() const override; QVariant data(int column) const override; - void update(const QString& field, const QVariant& value) override; + void update(const QString& field, const QVariant& value); void addPresence(const QString& name, const QMap& data); void removePresence(const QString& name); QString getContactName() const; QString getStatus() const; + + void addMessage(const Shared::Message& data); + void changeMessage(const QString& id, const QMap& data); + unsigned int getMessagesCount() const; + void dropMessages(); + void getMessages(Messages& container) const; QString getDisplayedName() const override; + Contact* copy() const; + protected: void _removeChild(int index) override; void _appendChild(Models::Item * child) override; + bool columnInvolvedInDisplay(int col) override; + const Account* getParentAccount() const override; protected slots: void refresh(); @@ -69,13 +84,23 @@ protected: void setAvailability(unsigned int p_state); void setState(Shared::SubscriptionState p_state); void setState(unsigned int p_state); + void setAvatarState(Shared::Avatar p_state); + void setAvatarState(unsigned int p_state); + void setAvatarPath(const QString& path); + void setJid(const QString p_jid); void setStatus(const QString& p_state); private: + QString jid; Shared::Availability availability; Shared::SubscriptionState state; + Shared::Avatar avatarState; QMap presences; + Messages messages; + unsigned int childMessages; QString status; + QString avatarPath; + const Account* account; }; } diff --git a/ui/models/element.cpp b/ui/models/element.cpp deleted file mode 100644 index 4e741a4..0000000 --- a/ui/models/element.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/* - * 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 "element.h" -#include "account.h" - -#include - -Models::Element::Element(Type p_type, const Models::Account* acc, const QString& p_jid, const QMap& data, Models::Item* parentItem): - Item(p_type, data, parentItem), - jid(p_jid), - avatarPath(), - avatarState(Shared::Avatar::empty), - account(acc), - feed(new MessageFeed(this)) -{ - connect(feed, &MessageFeed::requestArchive, this, &Element::requestArchive); - connect(feed, &MessageFeed::fileDownloadRequest, this, &Element::fileDownloadRequest); - connect(feed, &MessageFeed::unreadMessagesCountChanged, this, &Element::onFeedUnreadMessagesCountChanged); - connect(feed, &MessageFeed::unnoticedMessage, this, &Element::onFeedUnnoticedMessage); - connect(feed, &MessageFeed::localPathInvalid, this, &Element::localPathInvalid); - - QMap::const_iterator itr = data.find("avatarState"); - if (itr != data.end()) { - setAvatarState(itr.value().toUInt()); - } - itr = data.find("avatarPath"); - if (itr != data.end()) { - setAvatarPath(itr.value().toString()); - } -} - -Models::Element::~Element() -{ - delete feed; -} - - -QString Models::Element::getJid() const -{ - return jid; -} - -void Models::Element::setJid(const QString& p_jid) -{ - if (jid != p_jid) { - jid = p_jid; - changed(1); - } -} - -void Models::Element::update(const QString& field, const QVariant& value) -{ - if (field == "jid") { - setJid(value.toString()); - } else if (field == "avatarState") { - setAvatarState(value.toUInt()); - } else if (field == "avatarPath") { - setAvatarPath(value.toString()); - } -} - -QString Models::Element::getAvatarPath() const -{ - return avatarPath; -} - -Shared::Avatar Models::Element::getAvatarState() const -{ - return avatarState; -} - -void Models::Element::setAvatarPath(const QString& path) -{ - if (path != avatarPath) { - avatarPath = path; - if (type == contact) { - changed(7); - } else if (type == room) { - changed(8); - } - } -} - -void Models::Element::setAvatarState(Shared::Avatar p_state) -{ - if (avatarState != p_state) { - avatarState = p_state; - if (type == contact) { - changed(6); - } else if (type == room) { - changed(7); - } - } -} - -void Models::Element::setAvatarState(unsigned int p_state) -{ - if (p_state <= static_cast(Shared::Avatar::valid)) { - Shared::Avatar state = static_cast(p_state); - setAvatarState(state); - } else { - qDebug() << "An attempt to set invalid avatar state" << p_state << "to the element" << jid << ", skipping"; - } -} - -bool Models::Element::columnInvolvedInDisplay(int col) -{ - return Item::columnInvolvedInDisplay(col) && col == 1; -} - -const Models::Account * Models::Element::getParentAccount() const -{ - return account; -} - -unsigned int Models::Element::getMessagesCount() const -{ - return feed->unreadMessagesCount(); -} - -void Models::Element::addMessage(const Shared::Message& data) -{ - feed->addMessage(data); -} - -void Models::Element::changeMessage(const QString& id, const QMap& data) -{ - feed->changeMessage(id, data); -} - -void Models::Element::responseArchive(const std::list list, bool last) -{ - feed->responseArchive(list, last); -} - -bool Models::Element::isRoom() const -{ - return type != contact; -} - -void Models::Element::fileProgress(const QString& messageId, qreal value, bool up) -{ - 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); -} - -void Models::Element::onFeedUnreadMessagesCountChanged() -{ - if (type == contact) { - changed(4); - } else if (type == room) { - changed(5); - } -} - -void Models::Element::onFeedUnnoticedMessage(const Shared::Message& msg) -{ - emit unnoticedMessage(getAccountName(), msg); -} diff --git a/ui/models/element.h b/ui/models/element.h deleted file mode 100644 index af44791..0000000 --- a/ui/models/element.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * 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 ELEMENT_H -#define ELEMENT_H - -#include "item.h" -#include "messagefeed.h" - -namespace Models { - -class Element : public Item -{ - Q_OBJECT -protected: - Element(Type p_type, const Account* acc, const QString& p_jid, const QMap &data, Item *parentItem = 0); - ~Element(); - -public: - QString getJid() const; - Shared::Avatar getAvatarState() const; - QString getAvatarPath() const; - - virtual void update(const QString& field, const QVariant& value); - - void addMessage(const Shared::Message& data); - void changeMessage(const QString& id, const QMap& data); - unsigned int getMessagesCount() const; - void responseArchive(const std::list list, bool last); - bool isRoom() const; - 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 fileDownloadRequest(const QString& url); - void unnoticedMessage(const QString& account, const Shared::Message& msg); - void localPathInvalid(const QString& path); - -protected: - void setJid(const QString& p_jid); - void setAvatarState(Shared::Avatar p_state); - void setAvatarState(unsigned int p_state); - void setAvatarPath(const QString& path); - bool columnInvolvedInDisplay(int col) override; - const Account* getParentAccount() const override; - -protected slots: - void onFeedUnreadMessagesCountChanged(); - void onFeedUnnoticedMessage(const Shared::Message& msg); - -protected: - QString jid; - QString avatarPath; - Shared::Avatar avatarState; - - const Account* account; - -public: - MessageFeed* feed; -}; - -} - -#endif // ELEMENT_H diff --git a/ui/models/item.cpp b/ui/models/item.cpp index 4a88dd2..e006ad0 100644 --- a/ui/models/item.cpp +++ b/ui/models/item.cpp @@ -283,15 +283,6 @@ Shared::ConnectionState Models::Item::getAccountConnectionState() const return acc->getState(); } -QString Models::Item::getAccountAvatarPath() const -{ - const Account* acc = getParentAccount(); - if (acc == nullptr) { - return ""; - } - return acc->getAvatarPath(); -} - QString Models::Item::getDisplayedName() const { return name; diff --git a/ui/models/item.h b/ui/models/item.h index 4661479..4f3e29a 100644 --- a/ui/models/item.h +++ b/ui/models/item.h @@ -80,7 +80,6 @@ class Item : public QObject{ QString getAccountName() const; QString getAccountJid() const; QString getAccountResource() const; - QString getAccountAvatarPath() const; Shared::ConnectionState getAccountConnectionState() const; Shared::Availability getAccountAvailability() const; diff --git a/ui/models/messagefeed.cpp b/ui/models/messagefeed.cpp deleted file mode 100644 index 4187af8..0000000 --- a/ui/models/messagefeed.cpp +++ /dev/null @@ -1,576 +0,0 @@ -/* - * 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 "messagefeed.h" -#include "element.h" -#include "room.h" - -#include - -const QHash Models::MessageFeed::roles = { - {Text, "text"}, - {Sender, "sender"}, - {Date, "date"}, - {DeliveryState, "deliveryState"}, - {Correction, "correction"}, - {SentByMe,"sentByMe"}, - {Avatar, "avatar"}, - {Attach, "attach"}, - {Id, "id"}, - {Error, "error"}, - {Bulk, "bulk"} -}; - -Models::MessageFeed::MessageFeed(const Element* ri, QObject* parent): - QAbstractListModel(parent), - storage(), - indexById(storage.get()), - indexByTime(storage.get