diff --git a/.forgejo/workflows/release.yml b/.gitea/workflows/release.yml similarity index 100% rename from .forgejo/workflows/release.yml rename to .gitea/workflows/release.yml diff --git a/.gitmodules b/.gitmodules index 3742a90..448dae5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,9 @@ [submodule "external/qxmpp"] path = external/qxmpp - url = https://invent.kde.org/libraries/qxmpp/ + url = https://github.com/qxmpp-project/qxmpp.git +[submodule "external/storage"] + path = external/storage + url = https://git.macaw.me/blue/storage [submodule "external/lmdbal"] path = external/lmdbal - url = https://git.macaw.me/blue/lmdbal + url = gitea@git.macaw.me:blue/lmdbal.git diff --git a/CHANGELOG.md b/CHANGELOG.md index 44c00ff..4ca1542 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,5 @@ # Changelog -## Squawk 0.2.4 (UNRELEASED) -### Bug fixes -- messages to the mucs get sent once again - -### Improvements -- it's possible to build against Qt 6 now, Qt6 is the default -- got rid of deprecated SimpleCrypt library -- look up for proper stanzaID - ## Squawk 0.2.3 (February 04, 2024) ### Bug fixes - "Add contact" and "Join conference" menu are enabled once again (pavavno)! diff --git a/CMakeLists.txt b/CMakeLists.txt index 5eb98a0..e2465cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,12 +1,12 @@ -cmake_minimum_required(VERSION 3.16) -project(squawk VERSION 0.2.4 LANGUAGES CXX) +cmake_minimum_required(VERSION 3.5) +project(squawk VERSION 0.2.3 LANGUAGES CXX) cmake_policy(SET CMP0076 NEW) cmake_policy(SET CMP0077 NEW) cmake_policy(SET CMP0079 NEW) -cmake_policy(SET CMP0167 NEW) set(CMAKE_CXX_STANDARD 17) +set(QT_VERSION_MAJOR 5) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTORCC ON) @@ -33,21 +33,18 @@ option(SYSTEM_LMDBAL "Use system lmdbal lib" ON) option(WITH_KWALLET "Build KWallet support module" ON) option(WITH_KIO "Build KIO support module" ON) option(WITH_KCONFIG "Build KConfig support module" ON) -option(WITH_OMEMO "Build OMEMO support module" OFF) #it should be off by default untill I sort the problems out +option(WITH_OMEMO "Build OMEMO support module" OFF) #it should be off by default untill I sourt the problems out # Dependencies -## Qt, detect and prefer Qt6 if available -find_package(Qt6 QUIET CONFIG COMPONENTS Widgets DBus Gui Xml Network Core) -if (Qt6_FOUND) - set(QT_VERSION_MAJOR 6) -else() - find_package(Qt5 REQUIRED CONFIG COMPONENTS Widgets DBus Gui Xml Network Core) - set(QT_VERSION_MAJOR 5) +## Qt +if (NOT DEFINED QT_VERSION_MAJOR) + find_package(QT NAMES Qt6 Qt5 CONFIG REQUIRED COMPONENTS Widgets DBus Gui Xml Network Core) +else () + find_package(Qt${QT_VERSION_MAJOR} CONFIG REQUIRED COMPONENTS Widgets DBus Gui Xml Network Core) endif() -message(STATUS "Building against Qt${QT_VERSION_MAJOR}") - find_package(Boost COMPONENTS) + target_include_directories(squawk PRIVATE ${Boost_INCLUDE_DIRS}) ## OMEMO @@ -70,9 +67,9 @@ endif () ## KIO if (WITH_KIO) - find_package(KF${QT_VERSION_MAJOR}KIO CONFIG) + find_package(KF5KIO CONFIG) - if (NOT KF${QT_VERSION_MAJOR}KIO_FOUND) + if (NOT KF5KIO_FOUND) set(WITH_KIO OFF) message("KIO package wasn't found, KIO support modules wouldn't be built") else () @@ -83,9 +80,9 @@ endif () ## KWallet if (WITH_KWALLET) - find_package(KF${QT_VERSION_MAJOR}Wallet CONFIG) + find_package(KF5Wallet CONFIG) - if (NOT KF${QT_VERSION_MAJOR}Wallet_FOUND) + if (NOT KF5Wallet_FOUND) set(WITH_KWALLET OFF) message("KWallet package wasn't found, KWallet support module wouldn't be built") else () @@ -96,13 +93,13 @@ endif () ## KConfig if (WITH_KCONFIG) - find_package(KF${QT_VERSION_MAJOR}Config CONFIG) - if (NOT KF${QT_VERSION_MAJOR}Config_FOUND) + find_package(KF5Config CONFIG) + if (NOT KF5Config_FOUND) set(WITH_KCONFIG OFF) message("KConfig package wasn't found, KConfig support modules wouldn't be built") else() - find_package(KF${QT_VERSION_MAJOR}ConfigWidgets CONFIG) - if (NOT KF${QT_VERSION_MAJOR}ConfigWidgets_FOUND) + find_package(KF5ConfigWidgets CONFIG) + if (NOT KF5ConfigWidgets_FOUND) set(WITH_KCONFIG OFF) message("KConfigWidgets package wasn't found, KConfigWidgets support modules wouldn't be built") else() @@ -116,12 +113,12 @@ endif() ## QXmpp if (SYSTEM_QXMPP) if (WITH_OMEMO) - find_package(QXmppQt${QT_VERSION_MAJOR} CONFIG COMPONENTS Omemo) + find_package(QXmpp CONFIG COMPONENTS Omemo) else () - find_package(QXmppQt${QT_VERSION_MAJOR} CONFIG) + find_package(QXmpp CONFIG) endif () - if (NOT QXmppQt${QT_VERSION_MAJOR}_FOUND) + if (NOT QXmpp_FOUND) set(SYSTEM_QXMPP OFF) message("QXmpp package wasn't found, trying to build with bundled QXmpp") else () @@ -153,8 +150,8 @@ endif () ## LMDBAL if (SYSTEM_LMDBAL) - find_package(lmdbalqt${QT_VERSION_MAJOR}) - if (NOT lmdbalqt${QT_VERSION_MAJOR}_FOUND) + find_package(lmdbal) + if (NOT lmdbal_FOUND) set(SYSTEM_LMDBAL OFF) message("LMDBAL package wasn't found, trying to build with bundled LMDBAL") else () @@ -164,11 +161,9 @@ else() message("Building with bundled LMDBAL") set(BUILD_STATIC ON) add_subdirectory(external/lmdbal) - add_library(LMDBALQT${QT_VERSION_MAJOR}::LMDBALQT${QT_VERSION_MAJOR} ALIAS LMDBAL) + add_library(LMDBAL::LMDBAL ALIAS LMDBAL) endif() -find_package(OpenSSL REQUIRED) - ## Linking target_link_libraries(squawk PRIVATE @@ -178,9 +173,9 @@ target_link_libraries(squawk Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Xml - LMDBALQT${QT_VERSION_MAJOR}::LMDBALQT${QT_VERSION_MAJOR} - OpenSSL::Crypto + LMDBAL::LMDBAL QXmpp::QXmpp + simpleCrypt ) if (WITH_OMEMO) @@ -207,8 +202,7 @@ if(CMAKE_COMPILER_IS_GNUCXX) list(APPEND COMPILE_OPTIONS -O3) endif() if (CMAKE_BUILD_TYPE STREQUAL Debug) - list(APPEND COMPILE_OPTIONS -O0) - list(APPEND COMPILE_OPTIONS -g3) + list(APPEND COMPILE_OPTIONS -g) list(APPEND COMPILE_OPTIONS -Wall) list(APPEND COMPILE_OPTIONS -Wextra) endif() @@ -217,13 +211,9 @@ if(CMAKE_COMPILER_IS_GNUCXX) target_compile_options(squawk PRIVATE ${COMPILE_OPTIONS}) endif(CMAKE_COMPILER_IS_GNUCXX) -# I am not really sure about this solution -# This should enable plugins to be found in path like /usr/lib/squawk instead of just /usr/lib -set(PLUGIN_PATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/squawk") -add_compile_definitions(PLUGIN_PATH="${PLUGIN_PATH}") - add_subdirectory(main) add_subdirectory(core) +add_subdirectory(external/simpleCrypt) add_subdirectory(packaging) add_subdirectory(plugins) add_subdirectory(resources) diff --git a/README.md b/README.md index b65e5e9..9c835b6 100644 --- a/README.md +++ b/README.md @@ -4,12 +4,12 @@ [![AUR version](https://img.shields.io/aur/version/squawk?style=flat-square)](https://aur.archlinux.org/packages/squawk/) [![Liberapay patrons](https://img.shields.io/liberapay/patrons/macaw.me?logo=liberapay&style=flat-square)](https://liberapay.com/macaw.me) -![Squawk screenshot](https://macaw.me/projects/squawk/0.2.2.png) +![Squawk screenshot](https://macaw.me/images/squawk/0.2.2.png) ### Prerequisites -- QT 5 or 6 -- CMake 3.10 or higher +- QT 5.12 *(lower versions might work but it wasn't tested)* +- CMake 3.4 or higher - qxmpp 1.1.0 or higher - LMDBAL (my own [library](https://git.macaw.me/blue/lmdbal) for lmdb) - KDE Frameworks: kwallet (optional) @@ -108,7 +108,6 @@ Here is the list of keys you can pass to configuration phase of `cmake ..`: - `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`) - `WITH_KCONFIG` - `True` builds the `KConfig` and `KConfigWidgets` capability module if such packages are installed and if not goes to `False`. `False` disables `KConfig` and `KConfigWidgets` support (default is `True`) - `WITH_OMEMO` - `True` builds the OMEMO encryption, requires `qxmpp` of version >= 1.5.0 built with OMEMO support. `False` disables OMEMO support (default is `False`) -- `QT_VERSION_MAJOR` - `6` builds against Qt 6, `5` builds against Qt 6, corresponding version of lmdbal and qxmpp should be installed (default is `6`) ## License diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 8baa5ad..a02bfe6 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -23,7 +23,10 @@ set(HEADER_FILES squawk.h ) -target_sources(squawk PRIVATE ${SOURCE_FILES}) +target_sources(squawk PRIVATE + ${SOURCE_FILES} + ${HEADER_FILES} +) target_include_directories(squawk PRIVATE ${LMDB_INCLUDE_DIRS}) @@ -31,4 +34,3 @@ add_subdirectory(handlers) add_subdirectory(passwordStorageEngines) add_subdirectory(components) add_subdirectory(delayManager) -add_subdirectory(utils) diff --git a/core/account.cpp b/core/account.cpp index e3d14e1..8082aeb 100644 --- a/core/account.cpp +++ b/core/account.cpp @@ -81,8 +81,7 @@ Core::Account::Account( config.setDomain(p_server); config.setPassword(p_password); config.setAutoAcceptSubscriptions(true); - // config.setIgnoreSslErrors(true); - // config.setAutoReconnectionEnabled(false); + //config.setAutoReconnectionEnabled(false); delay = new DelayManager::Manager(getBareJid()); QObject::connect(delay, &DelayManager::Manager::gotInfo, this, &Account::infoReady); QObject::connect(delay, &DelayManager::Manager::gotOwnInfo, this, &Account::infoReady); diff --git a/core/components/CMakeLists.txt b/core/components/CMakeLists.txt index 751a01f..77d290b 100644 --- a/core/components/CMakeLists.txt +++ b/core/components/CMakeLists.txt @@ -12,4 +12,7 @@ set(HEADER_FILES archive.h ) -target_sources(squawk PRIVATE ${SOURCE_FILES}) +target_sources(squawk PRIVATE + ${SOURCE_FILES} + ${HEADER_FILES} +) diff --git a/core/components/networkaccess.cpp b/core/components/networkaccess.cpp index 59e2448..0771dfa 100644 --- a/core/components/networkaccess.cpp +++ b/core/components/networkaccess.cpp @@ -550,8 +550,10 @@ void Core::NetworkAccess::moveFilesDirectory(const QString& newPath) { QDir dir(currentPath); bool success = true; qDebug() << "moving" << currentPath << "to" << newPath; - for (QString fileName : dir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System)) + for (QFileInfo fileInfo : dir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System)) { + QString fileName = fileInfo.fileName(); success = dir.rename(fileName, newPath + QDir::separator() + fileName) && success; + } if (!success) qDebug() << "couldn't move downloads directory, most probably downloads will be broken"; diff --git a/core/handlers/messagehandler.cpp b/core/handlers/messagehandler.cpp index 34f7fd1..094f671 100644 --- a/core/handlers/messagehandler.cpp +++ b/core/handlers/messagehandler.cpp @@ -164,7 +164,19 @@ bool Core::MessageHandler::handleGroupMessage(const QXmppMessage& msg, bool outg } void Core::MessageHandler::initializeMessage(Shared::Message& target, const QXmppMessage& source, bool outgoing, bool forwarded, bool guessing) const { - initializeIDs(target, source); + const QDateTime& time(source.stamp()); + QString id; +#if (QXMPP_VERSION) >= QT_VERSION_CHECK(1, 3, 0) + id = source.originId(); + if (id.size() == 0) + id = source.id(); + + target.setStanzaId(source.stanzaId()); + qDebug() << "initializing message with originId:" << source.originId() << ", id:" << source.id() << ", stansaId:" << source.stanzaId(); +#else + id = source.id(); +#endif + target.setId(id); QString messageId = target.getId(); if (messageId.size() == 0) { target.generateRandomId(); //TODO out of desperation, I need at least a random ID @@ -185,7 +197,6 @@ void Core::MessageHandler::initializeMessage(Shared::Message& target, const QXmp if (guessing) outgoing = target.getFromJid() == acc->getBareJid(); - const QDateTime& time(source.stamp()); target.setOutgoing(outgoing); if (time.isValid()) target.setTime(time); @@ -199,37 +210,6 @@ void Core::MessageHandler::initializeMessage(Shared::Message& target, const QXmp target.setOutOfBandUrl(oob); } -void Core::MessageHandler::initializeIDs(Shared::Message& target, const QXmppMessage& source) const { - QString id; -#if (QXMPP_VERSION) >= QT_VERSION_CHECK(1, 3, 0) - id = source.originId(); - if (id.size() == 0) - id = source.id(); - - QString stanzaID; -#if (QXMPP_VERSION) >= QT_VERSION_CHECK(1, 5, 0) - // here I'm looking preferably for id generated by myself, but if there isn't - any is better than nothing - QVector sIDs = source.stanzaIds(); - for (const QXmppStanzaId& sID : sIDs) { - bool match = sID.by == acc->getBareJid(); - if (stanzaID.isEmpty() || match) - stanzaID = sID.id; - - if (match) - break; - } -#else - stanzaID = source.stanzaId(); -#endif - target.setStanzaId(stanzaID); - qDebug() << "initializing message with originId:" << source.originId() << ", id:" << source.id() << ", stanzaId:" << stanzaID; -#else - id = source.id(); -#endif - target.setId(id); -} - - void Core::MessageHandler::logMessage(const QXmppMessage& msg, const QString& reason) { qDebug() << reason; qDebug() << "- from: " << msg.from(); @@ -239,6 +219,9 @@ void Core::MessageHandler::logMessage(const QXmppMessage& msg, const QString& re qDebug() << "- state: " << msg.state(); qDebug() << "- stamp: " << msg.stamp(); qDebug() << "- id: " << msg.id(); +#if (QXMPP_VERSION) >= QT_VERSION_CHECK(1, 3, 0) + qDebug() << "- stanzaId: " << msg.stanzaId(); +#endif qDebug() << "- outOfBandUrl: " << msg.outOfBandUrl(); qDebug() << "=============================="; } @@ -448,7 +431,7 @@ QMap Core::MessageHandler::getChanges(Shared::Message& data, } QXmppMessage Core::MessageHandler::createPacket(const Shared::Message& data, const QDateTime& time, const QString& originalId) const { - QXmppMessage msg(QString(), data.getTo(), data.getBody(), data.getThread()); + QXmppMessage msg(acc->getFullJid(), data.getTo(), data.getBody(), data.getThread()); QString id(data.getId()); if (originalId.size() > 0) @@ -509,7 +492,7 @@ void Core::MessageHandler::prepareUpload(const Shared::Message& data, bool newMe QFileInfo file(path); if (file.exists() && file.isReadable()) { pendingStateMessages.insert(std::make_pair(id, jid)); - uploadingSlotsQueue.emplace_back(file, id); + uploadingSlotsQueue.emplace_back(path, id); if (uploadingSlotsQueue.size() == 1) acc->um->requestUploadSlot(file); } else { @@ -522,10 +505,10 @@ 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 std::pair& pair = uploadingSlotsQueue.front(); const QString& mId = pair.second; QString palJid = pendingStateMessages.at(mId); - acc->network->uploadFile({acc->name, palJid, mId}, pair.first.path(), slot.putUrl(), slot.getUrl(), slot.putHeaders()); + acc->network->uploadFile({acc->name, palJid, mId}, pair.first, slot.putUrl(), slot.getUrl(), slot.putHeaders()); uploadingSlotsQueue.pop_front(); if (uploadingSlotsQueue.size() > 0) @@ -539,7 +522,7 @@ void Core::MessageHandler::onUploadSlotRequestFailed(const QXmppHttpUploadReques qDebug() << "HTTP Upload manager of account" << acc->name << "reports about an error requesting upload slot, but none was requested"; qDebug() << err; } else { - const std::pair& pair = uploadingSlotsQueue.front(); + 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); diff --git a/core/handlers/messagehandler.h b/core/handlers/messagehandler.h index 3555548..15f99bf 100644 --- a/core/handlers/messagehandler.h +++ b/core/handlers/messagehandler.h @@ -19,7 +19,6 @@ #pragma once #include -#include #include #include @@ -77,13 +76,12 @@ private: bool handlePendingMessageError(const QString& id, const QString& errorText); std::pair scheduleSending(const Shared::Message& message, const QDateTime& sendTime, const QString& originalId); bool adjustPendingMessage(const QString& messageId, const QMap& data, bool final); - void initializeIDs(Shared::Message& target, const QXmppMessage& source) const; private: Account* acc; std::map pendingStateMessages; //key is message id, value is JID std::map pendingCorrectionMessages; //key is new mesage, value is originalOne - std::deque> uploadingSlotsQueue; + std::deque> uploadingSlotsQueue; }; } diff --git a/core/passwordStorageEngines/CMakeLists.txt b/core/passwordStorageEngines/CMakeLists.txt index 2a38931..2afda3f 100644 --- a/core/passwordStorageEngines/CMakeLists.txt +++ b/core/passwordStorageEngines/CMakeLists.txt @@ -1,6 +1,9 @@ if (WITH_KWALLET) - target_sources(squawk PRIVATE kwallet.cpp) + target_sources(squawk PRIVATE + kwallet.cpp + kwallet.h + ) add_subdirectory(wrappers) - target_include_directories(squawk PRIVATE $) + target_include_directories(squawk PRIVATE $) endif () diff --git a/core/passwordStorageEngines/kwallet.cpp b/core/passwordStorageEngines/kwallet.cpp index c92085b..0dfe071 100644 --- a/core/passwordStorageEngines/kwallet.cpp +++ b/core/passwordStorageEngines/kwallet.cpp @@ -28,8 +28,7 @@ Core::PSE::KWallet::CreateFolder Core::PSE::KWallet::createFolder = 0; Core::PSE::KWallet::SetFolder Core::PSE::KWallet::setFolder = 0; Core::PSE::KWallet::SupportState Core::PSE::KWallet::sState = Core::PSE::KWallet::initial; - -QLibrary Core::PSE::KWallet::lib(QString("%1/kwalletWrapper").arg(PLUGIN_PATH)); +QLibrary Core::PSE::KWallet::lib("kwalletWrapper"); Core::PSE::KWallet::KWallet(): QObject(), diff --git a/core/passwordStorageEngines/kwallet.h b/core/passwordStorageEngines/kwallet.h index 1f047e6..28475d2 100644 --- a/core/passwordStorageEngines/kwallet.h +++ b/core/passwordStorageEngines/kwallet.h @@ -27,7 +27,7 @@ #include #include -#include +#include namespace Core { namespace PSE { diff --git a/core/passwordStorageEngines/wrappers/CMakeLists.txt b/core/passwordStorageEngines/wrappers/CMakeLists.txt index 6280cc0..e8420da 100644 --- a/core/passwordStorageEngines/wrappers/CMakeLists.txt +++ b/core/passwordStorageEngines/wrappers/CMakeLists.txt @@ -1,5 +1,4 @@ add_library(kwalletWrapper SHARED kwallet.cpp) +target_link_libraries(kwalletWrapper PRIVATE KF5::Wallet) -target_link_libraries(kwalletWrapper PRIVATE KF${QT_VERSION_MAJOR}::Wallet) - -install(TARGETS kwalletWrapper LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/squawk) +install(TARGETS kwalletWrapper LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/core/passwordStorageEngines/wrappers/kwallet.cpp b/core/passwordStorageEngines/wrappers/kwallet.cpp index 5c7bc99..d899985 100644 --- a/core/passwordStorageEngines/wrappers/kwallet.cpp +++ b/core/passwordStorageEngines/wrappers/kwallet.cpp @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -#include +#include extern "C" KWallet::Wallet* openWallet(const QString &name, WId w, KWallet::Wallet::OpenType ot = KWallet::Wallet::Synchronous) { return KWallet::Wallet::openWallet(name, w, ot); diff --git a/core/squawk.cpp b/core/squawk.cpp index 7f04d9a..1888487 100644 --- a/core/squawk.cpp +++ b/core/squawk.cpp @@ -22,8 +22,6 @@ #include #include -#include "utils/jammer.h" - Core::Squawk::Squawk(QObject* parent): QObject(parent), accounts(), @@ -31,10 +29,10 @@ Core::Squawk::Squawk(QObject* parent): state(Shared::Availability::offline), network(), isInitialized(false), + clientCache(), #ifdef WITH_KWALLET - kwallet(), + kwallet() #endif - clientCache() { connect(&network, &NetworkAccess::loadFileProgress, this, &Squawk::fileProgress); connect(&network, &NetworkAccess::loadFileError, this, &Squawk::fileError); @@ -73,6 +71,7 @@ void Core::Squawk::stop() { QSettings settings; settings.beginGroup("core"); settings.beginWriteArray("accounts"); + SimpleCrypt crypto(passwordHash); for (std::deque::size_type i = 0; i < accounts.size(); ++i) { settings.setArrayIndex(i); Account* acc = accounts[i]; @@ -85,7 +84,7 @@ void Core::Squawk::stop() { password = acc->getPassword(); break; case Shared::AccountPassword::jammed: - password = Jammer::encrypt(acc->getPassword(), passwordHash); + password = crypto.encryptToString(acc->getPassword()); break; default: break; @@ -698,16 +697,17 @@ void Core::Squawk::readSettings() { settings.value("passwordType", static_cast(Shared::AccountPassword::plain)).toInt() ); - QString name = settings.value("name").toString(); QString password = settings.value("password", "").toString(); - if (passwordType == Shared::AccountPassword::jammed) - password = Jammer::decrypt(password, passwordHash); + if (passwordType == Shared::AccountPassword::jammed) { + SimpleCrypt crypto(passwordHash); + password = crypto.decryptToString(password); + } addAccount( settings.value("login").toString(), settings.value("server").toString(), password, - name, + settings.value("name").toString(), settings.value("resource").toString(), settings.value("active").toBool(), passwordType diff --git a/core/squawk.h b/core/squawk.h index 983f5ab..2ee122e 100644 --- a/core/squawk.h +++ b/core/squawk.h @@ -33,6 +33,7 @@ #include "shared/global.h" #include "shared/info.h" #include "shared/clientinfo.h" +#include "external/simpleCrypt/simplecrypt.h" #include #include @@ -41,8 +42,10 @@ #include "passwordStorageEngines/kwallet.h" #endif -namespace Core { -class Squawk : public QObject { +namespace Core +{ +class Squawk : public QObject +{ Q_OBJECT public: @@ -137,12 +140,11 @@ private: Shared::Availability state; NetworkAccess network; bool isInitialized; + ClientCache clientCache; #ifdef WITH_KWALLET PSE::KWallet kwallet; #endif - - ClientCache clientCache; private slots: void addAccount( diff --git a/core/utils/CMakeLists.txt b/core/utils/CMakeLists.txt deleted file mode 100644 index e030130..0000000 --- a/core/utils/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -set(SOURCE_FILES - jammer.cpp -) - -set(HEADER_FILES - jammer.h -) - -target_sources(squawk PRIVATE ${SOURCE_FILES}) diff --git a/core/utils/jammer.cpp b/core/utils/jammer.cpp deleted file mode 100644 index 1714c6b..0000000 --- a/core/utils/jammer.cpp +++ /dev/null @@ -1,94 +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 "jammer.h" - -#include - -#include -#include - -struct CipherCtxDeleter { - void operator()(EVP_CIPHER_CTX* ctx) const { - EVP_CIPHER_CTX_free(ctx); - } -}; -typedef std::unique_ptr CipherCtx; - -QString Core::Jammer::encrypt(const QString& plaintext, qint64 key) { - QByteArray encryptedData = process(plaintext.toUtf8(), intToKey(key), true); - - return QString::fromUtf8(encryptedData.toHex()); -} - -QString Core::Jammer::decrypt(const QString& ciphertext, qint64 key) { - QByteArray encryptedData = QByteArray::fromHex(ciphertext.toUtf8()); - QByteArray decryptedData = process(encryptedData, intToKey(key), false); - - return QString::fromUtf8(decryptedData); -} - -std::string Core::Jammer::getOpenSSLErrorString() { - unsigned long errCode = ERR_get_error(); - if (errCode == 0) { - return "No OpenSSL error"; - } - const char *errMsg = ERR_reason_error_string(errCode); - return errMsg ? std::string(errMsg) : "Unknown OpenSSL error"; -} - -QByteArray Core::Jammer::process(const QByteArray& input, const QByteArray& key, bool encrypt) { - CipherCtx ctx(EVP_CIPHER_CTX_new()); - if (!ctx) - throw std::runtime_error("Failed to create password jammer context"); - - QByteArray output(input.size() + 16, 0); - int outputLength = 0; - int finalLength = 0; - - if (!ctx) - throw std::runtime_error("Failed to create EVP_CIPHER_CTX: " + getOpenSSLErrorString()); - - if (EVP_CipherInit_ex(ctx.get(), EVP_chacha20(), nullptr, toUChar(key), nullptr, encrypt) != 1) - throw std::runtime_error("EVP_CipherInit_ex failed. " + getOpenSSLErrorString()); - - if (EVP_CipherUpdate(ctx.get(), toUChar(output), &outputLength, toUChar(input), input.size()) != 1) - throw std::runtime_error("EVP_CipherUpdate failed. " + getOpenSSLErrorString()); - - if (EVP_CipherFinal_ex(ctx.get(), toUChar(output) + outputLength, &finalLength) != 1) - throw std::runtime_error("EVP_CipherFinal_ex failed. " + getOpenSSLErrorString()); - - output.resize(outputLength + finalLength); - - return output; -} - -QByteArray Core::Jammer::intToKey(qint64 key, int keySize) { - QByteArray keyBytes(reinterpret_cast(&key), sizeof(key)); - while (keyBytes.size() < keySize) - keyBytes.append(keyBytes); - - keyBytes.truncate(keySize); - return keyBytes; -} - -unsigned char* Core::Jammer::toUChar(QByteArray& data) { - return reinterpret_cast(data.data());} - -const unsigned char* Core::Jammer::toUChar(const QByteArray& data) { - return reinterpret_cast(data.constData());} diff --git a/core/utils/jammer.h b/core/utils/jammer.h deleted file mode 100644 index 456c14b..0000000 --- a/core/utils/jammer.h +++ /dev/null @@ -1,44 +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 . - */ - -#pragma once - -#include - -#include -#include - -namespace Core { - -class Jammer { -public: - static QString encrypt(const QString& plaintext, qint64 key); - static QString decrypt(const QString& ciphertext, qint64 key); - -private: - Jammer() = delete; - - static QByteArray process(const QByteArray& input, const QByteArray& key, bool encrypt); - static QByteArray intToKey(qint64 key, int keySize = 32); - - static unsigned char* toUChar(QByteArray& data); - static const unsigned char* toUChar(const QByteArray& data); - static std::string getOpenSSLErrorString(); -}; - -} diff --git a/external/lmdbal b/external/lmdbal index 3701fb9..d62eddc 160000 --- a/external/lmdbal +++ b/external/lmdbal @@ -1 +1 @@ -Subproject commit 3701fb92a1498bd737828d8d1df63d4c4d8f02c7 +Subproject commit d62eddc47edbec9f8c071459e045578f61ab58df diff --git a/external/qxmpp b/external/qxmpp index ca1bdb3..0cd7379 160000 --- a/external/qxmpp +++ b/external/qxmpp @@ -1 +1 @@ -Subproject commit ca1bdb3e46c71ceb334e6dc52291850f0c96cb50 +Subproject commit 0cd7379bd78aa01af7e84f2fad6269ef0c0ba49c diff --git a/external/simpleCrypt/CMakeLists.txt b/external/simpleCrypt/CMakeLists.txt new file mode 100644 index 0000000..5f274ba --- /dev/null +++ b/external/simpleCrypt/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.5) +project(simplecrypt LANGUAGES CXX) + +set(CMAKE_AUTOMOC ON) + +find_package(Qt5 COMPONENTS Core REQUIRED) + +add_library(simpleCrypt STATIC simplecrypt.cpp simplecrypt.h) + +target_link_libraries(simpleCrypt Qt5::Core) diff --git a/external/simpleCrypt/simplecrypt.cpp b/external/simpleCrypt/simplecrypt.cpp new file mode 100644 index 0000000..093403e --- /dev/null +++ b/external/simpleCrypt/simplecrypt.cpp @@ -0,0 +1,248 @@ +/* + Copyright (c) 2011, Andre Somers + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Rathenau Instituut, Andre Somers nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL ANDRE SOMERS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "simplecrypt.h" +#include +#include +#include +#include +#include +#include + +SimpleCrypt::SimpleCrypt(): +m_key(0), +m_compressionMode(CompressionAuto), +m_protectionMode(ProtectionChecksum), +m_lastError(ErrorNoError) {} + +SimpleCrypt::SimpleCrypt(quint64 key): +m_key(key), +m_compressionMode(CompressionAuto), +m_protectionMode(ProtectionChecksum), +m_lastError(ErrorNoError) +{ + splitKey(); +} + +void SimpleCrypt::setKey(quint64 key) +{ + m_key = key; + splitKey(); +} + +void SimpleCrypt::splitKey() +{ + m_keyParts.clear(); + m_keyParts.resize(8); + for (int i=0;i<8;i++) { + quint64 part = m_key; + for (int j=i; j>0; j--) + part = part >> 8; + part = part & 0xff; + m_keyParts[i] = static_cast(part); + } +} + +QByteArray SimpleCrypt::encryptToByteArray(const QString& plaintext) +{ + QByteArray plaintextArray = plaintext.toUtf8(); + return encryptToByteArray(plaintextArray); +} + +QByteArray SimpleCrypt::encryptToByteArray(QByteArray plaintext) +{ + if (m_keyParts.isEmpty()) { + qWarning() << "No key set."; + m_lastError = ErrorNoKeySet; + return QByteArray(); + } + + + QByteArray ba = plaintext; + + CryptoFlags flags = CryptoFlagNone; + if (m_compressionMode == CompressionAlways) { + ba = qCompress(ba, 9); //maximum compression + flags |= CryptoFlagCompression; + } else if (m_compressionMode == CompressionAuto) { + QByteArray compressed = qCompress(ba, 9); + if (compressed.count() < ba.count()) { + ba = compressed; + flags |= CryptoFlagCompression; + } + } + + QByteArray integrityProtection; + if (m_protectionMode == ProtectionChecksum) { + flags |= CryptoFlagChecksum; + QDataStream s(&integrityProtection, QIODevice::WriteOnly); + s << qChecksum(ba.constData(), ba.length()); + } else if (m_protectionMode == ProtectionHash) { + flags |= CryptoFlagHash; + QCryptographicHash hash(QCryptographicHash::Sha1); + hash.addData(ba); + + integrityProtection += hash.result(); + } + + //prepend a random char to the string + char randomChar = char(QRandomGenerator::global()->generate() & 0xFF); + ba = randomChar + integrityProtection + ba; + + int pos(0); + char lastChar(0); + + int cnt = ba.count(); + + while (pos < cnt) { + ba[pos] = ba.at(pos) ^ m_keyParts.at(pos % 8) ^ lastChar; + lastChar = ba.at(pos); + ++pos; + } + + QByteArray resultArray; + resultArray.append(char(0x03)); //version for future updates to algorithm + resultArray.append(char(flags)); //encryption flags + resultArray.append(ba); + + m_lastError = ErrorNoError; + return resultArray; +} + +QString SimpleCrypt::encryptToString(const QString& plaintext) +{ + QByteArray plaintextArray = plaintext.toUtf8(); + QByteArray cypher = encryptToByteArray(plaintextArray); + QString cypherString = QString::fromLatin1(cypher.toBase64()); + return cypherString; +} + +QString SimpleCrypt::encryptToString(QByteArray plaintext) +{ + QByteArray cypher = encryptToByteArray(plaintext); + QString cypherString = QString::fromLatin1(cypher.toBase64()); + return cypherString; +} + +QString SimpleCrypt::decryptToString(const QString &cyphertext) +{ + QByteArray cyphertextArray = QByteArray::fromBase64(cyphertext.toLatin1()); + QByteArray plaintextArray = decryptToByteArray(cyphertextArray); + QString plaintext = QString::fromUtf8(plaintextArray, plaintextArray.size()); + + return plaintext; +} + +QString SimpleCrypt::decryptToString(QByteArray cypher) +{ + QByteArray ba = decryptToByteArray(cypher); + QString plaintext = QString::fromUtf8(ba, ba.size()); + + return plaintext; +} + +QByteArray SimpleCrypt::decryptToByteArray(const QString& cyphertext) +{ + QByteArray cyphertextArray = QByteArray::fromBase64(cyphertext.toLatin1()); + QByteArray ba = decryptToByteArray(cyphertextArray); + + return ba; +} + +QByteArray SimpleCrypt::decryptToByteArray(QByteArray cypher) +{ + if (m_keyParts.isEmpty()) { + qWarning() << "No key set."; + m_lastError = ErrorNoKeySet; + return QByteArray(); + } + + QByteArray ba = cypher; + + if( cypher.count() < 3 ) + return QByteArray(); + + char version = ba.at(0); + + if (version !=3) { //we only work with version 3 + m_lastError = ErrorUnknownVersion; + qWarning() << "Invalid version or not a cyphertext."; + return QByteArray(); + } + + CryptoFlags flags = CryptoFlags(ba.at(1)); + + ba = ba.mid(2); + int pos(0); + int cnt(ba.count()); + char lastChar = 0; + + while (pos < cnt) { + char currentChar = ba[pos]; + ba[pos] = ba.at(pos) ^ lastChar ^ m_keyParts.at(pos % 8); + lastChar = currentChar; + ++pos; + } + + ba = ba.mid(1); //chop off the random number at the start + + bool integrityOk(true); + if (flags.testFlag(CryptoFlagChecksum)) { + if (ba.length() < 2) { + m_lastError = ErrorIntegrityFailed; + return QByteArray(); + } + quint16 storedChecksum; + { + QDataStream s(&ba, QIODevice::ReadOnly); + s >> storedChecksum; + } + ba = ba.mid(2); + quint16 checksum = qChecksum(ba.constData(), ba.length()); + integrityOk = (checksum == storedChecksum); + } else if (flags.testFlag(CryptoFlagHash)) { + if (ba.length() < 20) { + m_lastError = ErrorIntegrityFailed; + return QByteArray(); + } + QByteArray storedHash = ba.left(20); + ba = ba.mid(20); + QCryptographicHash hash(QCryptographicHash::Sha1); + hash.addData(ba); + integrityOk = (hash.result() == storedHash); + } + + if (!integrityOk) { + m_lastError = ErrorIntegrityFailed; + return QByteArray(); + } + + if (flags.testFlag(CryptoFlagCompression)) + ba = qUncompress(ba); + + m_lastError = ErrorNoError; + return ba; +} diff --git a/external/simpleCrypt/simplecrypt.h b/external/simpleCrypt/simplecrypt.h new file mode 100644 index 0000000..0052618 --- /dev/null +++ b/external/simpleCrypt/simplecrypt.h @@ -0,0 +1,226 @@ +/* + Copyright (c) 2011, Andre Somers + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Rathenau Instituut, Andre Somers nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL ANDRE SOMERS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SIMPLECRYPT_H +#define SIMPLECRYPT_H +#include +#include +#include +#include + +/** + @ short Simple encrypt*ion and decryption of strings and byte arrays + + This class provides a simple implementation of encryption and decryption + of strings and byte arrays. + + @warning The encryption provided by this class is NOT strong encryption. It may + help to shield things from curious eyes, but it will NOT stand up to someone + determined to break the encryption. Don't say you were not warned. + + The class uses a 64 bit key. Simply create an instance of the class, set the key, + and use the encryptToString() method to calculate an encrypted version of the input string. + To decrypt that string again, use an instance of SimpleCrypt initialized with + the same key, and call the decryptToString() method with the encrypted string. If the key + matches, the decrypted version of the string will be returned again. + + If you do not provide a key, or if something else is wrong, the encryption and + decryption function will return an empty string or will return a string containing nonsense. + lastError() will return a value indicating if the method was succesful, and if not, why not. + + SimpleCrypt is prepared for the case that the encryption and decryption + algorithm is changed in a later version, by prepending a version identifier to the cypertext. + */ +class SimpleCrypt +{ +public: + /** + CompressionMode describes if compression will be applied to the data to be + encrypted. + */ + enum CompressionMode { + CompressionAuto, /*!< Only apply compression if that results in a shorter plaintext. */ + CompressionAlways, /*!< Always apply compression. Note that for short inputs, a compression may result in longer data */ + CompressionNever /*!< Never apply compression. */ + }; + /** + IntegrityProtectionMode describes measures taken to make it possible to detect problems with the data + or wrong decryption keys. + + Measures involve adding a checksum or a cryptograhpic hash to the data to be encrypted. This + increases the length of the resulting cypertext, but makes it possible to check if the plaintext + appears to be valid after decryption. + */ + enum IntegrityProtectionMode { + ProtectionNone, /*!< The integerity of the encrypted data is not protected. It is not really possible to detect a wrong key, for instance. */ + ProtectionChecksum,/*!< A simple checksum is used to verify that the data is in order. If not, an empty string is returned. */ + ProtectionHash /*!< A cryptographic hash is used to verify the integrity of the data. This method produces a much stronger, but longer check */ + }; + /** + Error describes t*he type of error that occured. + */ + enum Error { + ErrorNoError, /*!< No error occurred. */ + ErrorNoKeySet, /*!< No key was set. You can not encrypt or decrypt without a valid key. */ + ErrorUnknownVersion, /*!< The version of this data is unknown, or the data is otherwise not valid. */ + ErrorIntegrityFailed, /*!< The integrity check of the data failed. Perhaps the wrong key was used. */ + }; + + /** + Constructor. * + + Constructs a SimpleCrypt instance without a valid key set on it. + */ + SimpleCrypt(); + /** + Constructor. * + + Constructs a SimpleCrypt instance and initializes it with the given @arg key. + */ + explicit SimpleCrypt(quint64 key); + + /** + ( Re-) initializes* the key with the given @arg key. + */ + void setKey(quint64 key); + /** + Returns true if SimpleCrypt has been initialized with a key. + */ + bool hasKey() const {return !m_keyParts.isEmpty();} + + /** + Sets the compress*ion mode to use when encrypting data. The default mode is Auto. + + Note that decryption is not influenced by this mode, as the decryption recognizes + what mode was used when encrypting. + */ + void setCompressionMode(CompressionMode mode) {m_compressionMode = mode;} + /** + Returns the CompressionMode that is currently in use. + */ + CompressionMode compressionMode() const {return m_compressionMode;} + + /** + Sets the integrity mode to use when encrypting data. The default mode is Checksum. + + Note that decryption is not influenced by this mode, as the decryption recognizes + what mode was used when encrypting. + */ + void setIntegrityProtectionMode(IntegrityProtectionMode mode) {m_protectionMode = mode;} + /** + Returns the IntegrityProtectionMode that is currently in use. + */ + IntegrityProtectionMode integrityProtectionMode() const {return m_protectionMode;} + + /** + Returns the last *error that occurred. + */ + Error lastError() const {return m_lastError;} + + /** + Encrypts the @arg* plaintext string with the key the class was initialized with, and returns + a cyphertext the result. The result is a base64 encoded version of the binary array that is the + actual result of the string, so it can be stored easily in a text format. + */ + QString encryptToString(const QString& plaintext) ; + /** + Encrypts the @arg* plaintext QByteArray with the key the class was initialized with, and returns + a cyphertext the result. The result is a base64 encoded version of the binary array that is the + actual result of the encryption, so it can be stored easily in a text format. + */ + QString encryptToString(QByteArray plaintext) ; + /** + Encrypts the @arg* plaintext string with the key the class was initialized with, and returns + a binary cyphertext in a QByteArray the result. + + This method returns a byte array, that is useable for storing a binary format. If you need + a string you can store in a text file, use encryptToString() instead. + */ + QByteArray encryptToByteArray(const QString& plaintext) ; + /** + Encrypts the @arg* plaintext QByteArray with the key the class was initialized with, and returns + a binary cyphertext in a QByteArray the result. + + This method returns a byte array, that is useable for storing a binary format. If you need + a string you can store in a text file, use encryptToString() instead. + */ + QByteArray encryptToByteArray(QByteArray plaintext) ; + + /** + Decrypts a cypher*text string encrypted with this class with the set key back to the + plain text version. + + If an error occured, such as non-matching keys between encryption and decryption, + an empty string or a string containing nonsense may be returned. + */ + QString decryptToString(const QString& cyphertext) ; + /** + Decrypts a cypher*text string encrypted with this class with the set key back to the + plain text version. + + If an error occured, such as non-matching keys between encryption and decryption, + an empty string or a string containing nonsense may be returned. + */ + QByteArray decryptToByteArray(const QString& cyphertext) ; + /** + Decrypts a cypher*text binary encrypted with this class with the set key back to the + plain text version. + + If an error occured, such as non-matching keys between encryption and decryption, + an empty string or a string containing nonsense may be returned. + */ + QString decryptToString(QByteArray cypher) ; + /** + Decrypts a cypher*text binary encrypted with this class with the set key back to the + plain text version. + + If an error occured, such as non-matching keys between encryption and decryption, + an empty string or a string containing nonsense may be returned. + */ + QByteArray decryptToByteArray(QByteArray cypher) ; + + //enum to describe options that have been used for the encryption. Currently only one, but + //that only leaves room for future extensions like adding a cryptographic hash... + enum CryptoFlag{CryptoFlagNone = 0, + CryptoFlagCompression = 0x01, + CryptoFlagChecksum = 0x02, + CryptoFlagHash = 0x04 + }; + Q_DECLARE_FLAGS(CryptoFlags, CryptoFlag); +private: + + void splitKey(); + + quint64 m_key; + QVector m_keyParts; + CompressionMode m_compressionMode; + IntegrityProtectionMode m_protectionMode; + Error m_lastError; +}; +Q_DECLARE_OPERATORS_FOR_FLAGS(SimpleCrypt::CryptoFlags) + +#endif // SimpleCrypt_H diff --git a/main/root.cpp b/main/root.cpp index f71951c..d43ae2f 100644 --- a/main/root.cpp +++ b/main/root.cpp @@ -58,42 +58,34 @@ Root::~Root() { delete gui; if (core != nullptr) delete core; - delete coreThread; } delete global; } + void Root::initializeTranslation() { -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - bool defaultLoaded = defaultTranslator.load("qt_" + QLocale::system().name(), QLibraryInfo::path(QLibraryInfo::TranslationsPath)); - if (!defaultLoaded) - qDebug() << "Couldn't load default translation"; -#else defaultTranslator.load("qt_" + QLocale::system().name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath)); -#endif installTranslator(&defaultTranslator); QStringList shares = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation); bool found = false; for (QString share : shares) { found = currentTranslator.load(QLocale(), QLatin1String("squawk"), ".", share + "/l10n"); - if (found) + if (found) { break; + } + } + if (!found) { + currentTranslator.load(QLocale(), QLatin1String("squawk"), ".", QCoreApplication::applicationDirPath()); } - if (!found) - found = currentTranslator.load(QLocale(), QLatin1String("squawk"), ".", QCoreApplication::applicationDirPath()); - - if (found) - installTranslator(¤tTranslator); - else - qDebug() << "Couldn't load current translation"; + installTranslator(¤tTranslator); } void Root::initializeAppIcon() { - for (unsigned int appIconSize : appIconSizes) - appIcon.addFile(":images/logo.svg", QSize(appIconSize, appIconSize)); + for (std::vector::size_type i = 0; i < appIconSizes.size(); ++i) + appIcon.addFile(":images/logo.svg", QSize(appIconSizes[i], appIconSizes[i])); Root::setWindowIcon(appIcon); } @@ -102,16 +94,18 @@ bool Root::initializeSettings() { QVariant vs = settings.value("style"); if (vs.isValid()) { QString style = vs.toString().toLower(); - if (style != "system") + if (style != "system") { Shared::Global::setStyle(style); + } } if (Shared::Global::supported("colorSchemeTools")) { QVariant vt = settings.value("theme"); if (vt.isValid()) { QString theme = vt.toString(); - if (theme.toLower() != "system") + if (theme.toLower() != "system") { Shared::Global::setTheme(theme); + } } } diff --git a/packaging/Archlinux/PKGBUILD b/packaging/Archlinux/PKGBUILD index 0defdc3..29ed800 100644 --- a/packaging/Archlinux/PKGBUILD +++ b/packaging/Archlinux/PKGBUILD @@ -1,19 +1,19 @@ # Maintainer: Yury Gubich pkgname=squawk -pkgver=0.2.4 +pkgver=0.2.3 pkgrel=1 pkgdesc="An XMPP desktop messenger, written on pure c++ (qt)" arch=('i686' 'x86_64') url="https://git.macaw.me/blue/squawk" license=('GPL3') -depends=('hicolor-icon-theme' 'desktop-file-utils' 'lmdbal-qt6' 'qxmpp') -makedepends=('cmake>=3.3' 'imagemagick' 'qt6-tools' 'boost') -optdepends=('kwallet6: secure password storage (requires rebuild)' - 'kconfig6: system themes support (requires rebuild)' - 'kconfigwidgets6: system themes support (requires rebuild)' - 'kio6: better show in folder action (requires rebuild)') +depends=('hicolor-icon-theme' 'desktop-file-utils' 'lmdbal' 'qxmpp-qt5') +makedepends=('cmake>=3.3' 'imagemagick' 'qt5-tools' 'boost') +optdepends=('kwallet5: secure password storage (requires rebuild)' + 'kconfig5: system themes support (requires rebuild)' + 'kconfigwidgets5: system themes support (requires rebuild)' + 'kio5: better show in folder action (requires rebuild)') -source=("$pkgname-$pkgver-$pkgrel.tar.gz::https://git.macaw.me/blue/$pkgname/archive/$pkgver.tar.gz") +source=("$pkgname-$pkgver.tar.gz::https://git.macaw.me/blue/$pkgname/archive/$pkgver.tar.gz") sha256sums=('SKIP') build() { cd "$srcdir/squawk" diff --git a/packaging/CMakeLists.txt b/packaging/CMakeLists.txt index 4bb9c87..4965b37 100644 --- a/packaging/CMakeLists.txt +++ b/packaging/CMakeLists.txt @@ -1,7 +1,3 @@ configure_file(squawk.desktop squawk.desktop COPYONLY) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/squawk.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications) - -configure_file(macaw.me.squawk.appdata.xml macaw.me.squawk.appdata.xml COPYONLY) - -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/macaw.me.squawk.appdata.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/metainfo) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/squawk.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications) \ No newline at end of file diff --git a/packaging/macaw.me.squawk.appdata.xml b/packaging/macaw.me.squawk.appdata.xml deleted file mode 100644 index c188496..0000000 --- a/packaging/macaw.me.squawk.appdata.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - macaw.me.squawk - CC0-1.0 - GPL-3.0+ - Squawk - Desktop Qt based XMPP messenger - -

- Squawk is a lightweight XMPP desktop messenger. - The primary objective of this project is to offer - you a fast and user-friendly messaging experience - that closely aligns with your system’s style, while - also minimizing resource consumption. -

-

- Squawk is still at a very early stage and might not suit - everyone but you are welcome to try it out. -

-
- macaw.me.squawk.desktop - - - https://macaw.me/projects/squawk/0.2.2.png - View XMPP contacts and conversations - - - https://macaw.me/projects/squawk/ - - squawk - - blue@macaw.me -
diff --git a/packaging/squawk.desktop b/packaging/squawk.desktop index c64f9ab..ba0f13c 100644 --- a/packaging/squawk.desktop +++ b/packaging/squawk.desktop @@ -1,7 +1,7 @@ [Desktop Entry] Type=Application -Version=0.2.4 +Version=1.0 Name=Squawk GenericName=Instant Messenger GenericName[ru]=Мгновенные сообщения diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 9eb9070..388c258 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -1,14 +1,14 @@ if (WITH_KIO) add_library(openFileManagerWindowJob SHARED openfilemanagerwindowjob.cpp) - target_link_libraries(openFileManagerWindowJob PRIVATE KF${QT_VERSION_MAJOR}::KIOWidgets) + target_link_libraries(openFileManagerWindowJob PRIVATE KF5::KIOWidgets) - install(TARGETS openFileManagerWindowJob LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/squawk) + install(TARGETS openFileManagerWindowJob LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif () if (WITH_KCONFIG) add_library(colorSchemeTools SHARED colorschemetools.cpp) - target_link_libraries(colorSchemeTools PRIVATE KF${QT_VERSION_MAJOR}::ConfigCore) - target_link_libraries(colorSchemeTools PRIVATE KF${QT_VERSION_MAJOR}::ConfigWidgets) + target_link_libraries(colorSchemeTools PRIVATE KF5::ConfigCore) + target_link_libraries(colorSchemeTools PRIVATE KF5::ConfigWidgets) - install(TARGETS colorSchemeTools LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/squawk) + install(TARGETS colorSchemeTools LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif() diff --git a/plugins/colorschemetools.cpp b/plugins/colorschemetools.cpp index 76eba9b..ea2c23e 100644 --- a/plugins/colorschemetools.cpp +++ b/plugins/colorschemetools.cpp @@ -20,9 +20,9 @@ #include #include -#include -#include -#include +#include +#include +#include QPixmap createPixmap(int size, const QBrush& window, const QBrush& button, const QBrush& view, const QBrush& selection); diff --git a/resources/CMakeLists.txt b/resources/CMakeLists.txt index 717abf2..9288650 100644 --- a/resources/CMakeLists.txt +++ b/resources/CMakeLists.txt @@ -3,8 +3,11 @@ target_sources(squawk PRIVATE resources.qrc) configure_file(images/logo.svg squawk.svg COPYONLY) configure_file(squawk.rc squawk.rc COPYONLY) -set(CONVERT_BIN magick) - +if(WIN32) + set(CONVERT_BIN magick convert) +else(WIN32) + set(CONVERT_BIN convert) +endif(WIN32) execute_process(COMMAND ${CONVERT_BIN} -background none -size 48x48 squawk.svg squawk48.png WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) execute_process(COMMAND ${CONVERT_BIN} -background none -size 64x64 squawk.svg squawk64.png WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) execute_process(COMMAND ${CONVERT_BIN} -background none -size 128x128 squawk.svg squawk128.png WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) @@ -15,20 +18,20 @@ if (WIN32) set(SQUAWK_WIN_RC "${CMAKE_CURRENT_BINARY_DIR}/squawk.rc") set(SQUAWK_WIN_RC "${SQUAWK_WIN_RC}" PARENT_SCOPE) target_sources(squawk PRIVATE ${SQUAWK_WIN_RC}) -endif (WIN32) +endif(WIN32) if (APPLE) file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/icns.iconset") - execute_process(COMMAND ${CONVERT_BIN} -background none -size 16x16 squawk.svg icns.iconset/icon_16x16.png WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - execute_process(COMMAND ${CONVERT_BIN} -background none -resize !32x32 squawk.svg "icns.iconset/icon_16x16@2x.png" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - execute_process(COMMAND ${CONVERT_BIN} -background none -resize !32x32 squawk.svg "icns.iconset/icon_32x32.png" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - execute_process(COMMAND ${CONVERT_BIN} -background none -resize !64x64 squawk.svg "icns.iconset/icon_32x32@2x.png" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - execute_process(COMMAND ${CONVERT_BIN} -background none -resize !128x128 squawk.svg "icns.iconset/icon_128x128.png" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - execute_process(COMMAND ${CONVERT_BIN} -background none -resize !256x256 squawk.svg "icns.iconset/icon_128x128@2x.png" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - execute_process(COMMAND ${CONVERT_BIN} -background none -resize !256x256 squawk.svg "icns.iconset/icon_256x256.png" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - execute_process(COMMAND ${CONVERT_BIN} -background none -resize !512x512 squawk.svg "icns.iconset/icon_256x256@2x.png" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - execute_process(COMMAND ${CONVERT_BIN} -background none -resize !512x512 squawk.svg "icns.iconset/icon_512x512.png" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - execute_process(COMMAND ${CONVERT_BIN} -background none -resize !1024x1024 squawk.svg "icns.iconset/icon_512x512@2x.png" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + execute_process(COMMAND convert -background none -size 16x16 squawk.svg icns.iconset/icon_16x16.png WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + execute_process(COMMAND convert -background none -resize !32x32 squawk.svg "icns.iconset/icon_16x16@2x.png" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + execute_process(COMMAND convert -background none -resize !32x32 squawk.svg "icns.iconset/icon_32x32.png" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + execute_process(COMMAND convert -background none -resize !64x64 squawk.svg "icns.iconset/icon_32x32@2x.png" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + execute_process(COMMAND convert -background none -resize !128x128 squawk.svg "icns.iconset/icon_128x128.png" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + execute_process(COMMAND convert -background none -resize !256x256 squawk.svg "icns.iconset/icon_128x128@2x.png" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + execute_process(COMMAND convert -background none -resize !256x256 squawk.svg "icns.iconset/icon_256x256.png" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + execute_process(COMMAND convert -background none -resize !512x512 squawk.svg "icns.iconset/icon_256x256@2x.png" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + execute_process(COMMAND convert -background none -resize !512x512 squawk.svg "icns.iconset/icon_512x512.png" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + execute_process(COMMAND convert -background none -resize !1024x1024 squawk.svg "icns.iconset/icon_512x512@2x.png" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) execute_process(COMMAND iconutil -c icns "icns.iconset" -o "squawk.icns" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) set(MACOSX_BUNDLE_ICON_FILE squawk.icns) set(MACOSX_BUNDLE_ICON_FILE ${MACOSX_BUNDLE_ICON_FILE} PARENT_SCOPE) @@ -44,8 +47,8 @@ if (APPLE) MACOSX_BUNDLE_ICON_FILE "${MACOSX_BUNDLE_ICON_FILE}" # TODO MACOSX_BUNDLE_BUNDLE_NAME "Squawk" MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/cmake/MacOSXBundleInfo.plist.in) - endif (APPLE) - endif () + endif(APPLE) + endif() endif (APPLE) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/squawk.svg DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps) diff --git a/shared/CMakeLists.txt b/shared/CMakeLists.txt index 45fcfd0..2ef3970 100644 --- a/shared/CMakeLists.txt +++ b/shared/CMakeLists.txt @@ -39,4 +39,7 @@ set(HEADER_FILES defines.h ) -target_sources(squawk PRIVATE ${SOURCE_FILES} ${HEADER_FILES}) +target_sources(squawk PRIVATE + ${SOURCE_FILES} + ${HEADER_FILES} +) diff --git a/shared/clientid.h b/shared/clientid.h index 05bed45..5188b1c 100644 --- a/shared/clientid.h +++ b/shared/clientid.h @@ -14,11 +14,11 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#pragma once +#ifndef SHARED_CLIENTID_H +#define SHARED_CLIENTID_H #include #include -#include namespace Shared { @@ -54,3 +54,5 @@ Q_DECLARE_METATYPE(Shared::ClientId) QDataStream& operator << (QDataStream& stream, const Shared::ClientId& info); QDataStream& operator >> (QDataStream& stream, Shared::ClientId& info); + +#endif // SHARED_CLIENTID_H diff --git a/shared/clientinfo.h b/shared/clientinfo.h index ca66c6d..288e9fa 100644 --- a/shared/clientinfo.h +++ b/shared/clientinfo.h @@ -14,10 +14,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#pragma once +#ifndef SHARED_CLIENTINFO_H +#define SHARED_CLIENTINFO_H #include -#include #include #include @@ -54,3 +54,5 @@ private: QDataStream& operator << (QDataStream& stream, const Shared::ClientInfo& info); QDataStream& operator >> (QDataStream& stream, Shared::ClientInfo& info); + +#endif // SHARED_CLIENTINFO_H diff --git a/shared/defines.h b/shared/defines.h index 8ead3f6..227a714 100644 --- a/shared/defines.h +++ b/shared/defines.h @@ -16,6 +16,9 @@ * along with this program. If not, see . */ -#pragma once +#ifndef SHARED_DEFINES_H +#define SHARED_DEFINES_H #define SHARED_UNUSED(x) (void)(x) + +#endif diff --git a/shared/enums.h b/shared/enums.h index 6f5e9db..43d1583 100644 --- a/shared/enums.h +++ b/shared/enums.h @@ -101,8 +101,8 @@ enum class Avatar { valid }; Q_ENUM_NS(Avatar) -static const Avatar AvatarHighest = Avatar::valid; -static const Avatar AvatarLowest = Avatar::empty; +static const Avatar AvatarHighest = Avatar::valid; +static const Avatar AvatarLowest = Avatar::empty; static const std::deque messageStateThemeIcons = {"state-offline", "state-sync", "state-ok", "state-error"}; diff --git a/shared/global.cpp b/shared/global.cpp index f0e3230..6618426 100644 --- a/shared/global.cpp +++ b/shared/global.cpp @@ -19,10 +19,8 @@ #include "global.h" #include -#include "defines.h" #include "enums.h" #include "ui/models/roster.h" - #ifdef WITH_OMEMO constexpr bool OMEMO_SUPPORT = true; #else @@ -38,10 +36,11 @@ QFont getFont (QFontDatabase::SystemFont type, bool bold = false, bool italic = if (factor != 1.0) { float ps = font.pointSizeF(); - if (ps != -1) + if (ps != -1) { font.setPointSizeF(ps * factor); - else + } else { font.setPointSize(font.pointSize() * factor); + } } return font; @@ -51,12 +50,12 @@ 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(QString("%1/openFileManagerWindowJob").arg(PLUGIN_PATH)); +QLibrary Shared::Global::openFileManagerWindowJob("openFileManagerWindowJob"); Shared::Global::HighlightInFileManager Shared::Global::hfm = 0; #endif #ifdef WITH_KCONFIG -QLibrary Shared::Global::colorSchemeTools(QString("%1/colorSchemeTools").arg(PLUGIN_PATH)); +QLibrary Shared::Global::colorSchemeTools("colorSchemeTools"); Shared::Global::CreatePreview Shared::Global::createPreview = 0; Shared::Global::DeletePreview Shared::Global::deletePreview = 0; Shared::Global::ColorSchemeName Shared::Global::colorSchemeName = 0; @@ -149,7 +148,7 @@ Shared::Global::Global(): smallFontMetrics(smallFont), headerFontMetrics(headerFont), titleFontMetrics(titleFont), - optionalFeatures({ + pluginSupport({ {"KWallet", false}, {"openFileManagerWindowJob", false}, {"colorSchemeTools", false} @@ -198,7 +197,8 @@ Shared::Global::Global(): static const QSize defaultIconFileInfoHeight(50, 50); -Shared::Global::FileInfo Shared::Global::getFileInfo(const QString& path) { +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; @@ -275,17 +275,17 @@ QString Shared::Global::getName(EncryptionProtocol ep) { } void Shared::Global::setSupported(const QString& pluginName, bool support) { - std::map::iterator itr = instance->optionalFeatures.find(pluginName); - if (itr != instance->optionalFeatures.end()) { + std::map::iterator itr = instance->pluginSupport.find(pluginName); + if (itr != instance->pluginSupport.end()) { itr->second = support; } } bool Shared::Global::supported(const QString& pluginName) { - std::map::iterator itr = instance->optionalFeatures.find(pluginName); - if (itr != instance->optionalFeatures.end()) + std::map::iterator itr = instance->pluginSupport.find(pluginName); + if (itr != instance->pluginSupport.end()) { return itr->second; - + } return false; } @@ -317,7 +317,7 @@ void Shared::Global::highlightInFileManager(const QString& path) 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); + QFileInfo info = path; if (info.exists()) { QProcess proc; proc.start("xdg-mime", query); @@ -325,10 +325,11 @@ void Shared::Global::highlightInFileManager(const QString& path) QString output = proc.readLine().simplified(); QString folder; - if (info.isDir()) + if (info.isDir()) { folder = info.canonicalFilePath(); - else + } 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 @@ -355,32 +356,27 @@ void Shared::Global::highlightInFileManager(const QString& path) } QIcon Shared::Global::createThemePreview(const QString& path) { -#ifdef WITH_KCONFIG if (supported("colorSchemeTools")) { QIcon* icon = createPreview(path); QIcon localIcon = *icon; deletePreview(icon); return localIcon; + } else { + return QIcon(); } -#endif - - return QIcon(); } QString Shared::Global::getColorSchemeName(const QString& path) { -#ifdef WITH_KCONFIG if (supported("colorSchemeTools")) { QString res; colorSchemeName(path, res); return res; + } else { + return ""; } -#endif - - return ""; } void Shared::Global::setTheme(const QString& path) { -#ifdef WITH_KCONFIG if (supported("colorSchemeTools")) { if (path.toLower() == "system") { QApplication::setPalette(getInstance()->defaultSystemPalette); @@ -390,26 +386,23 @@ void Shared::Global::setTheme(const QString& path) { QApplication::setPalette(pallete); } } -#else - SHARED_UNUSED(path); - qDebug("setTheme() was called, but this version of squawk was compiled without KConfig support, ignoring"); -#endif } void Shared::Global::setStyle(const QString& style) { - if (style.toLower() == "system") + if (style.toLower() == "system") { QApplication::setStyle(getInstance()->defaultSystemStyle); - else + } else { QApplication::setStyle(style); + } } #define FROM_INT_INPL(Enum) \ template<> \ Enum Shared::Global::fromInt(int src) \ { \ - if (src < static_cast(Enum##Lowest) || src > static_cast(Enum##Highest)) \ + if (src < static_cast(Enum##Lowest) || src > static_cast(Enum##Highest)) { \ throw EnumOutOfRange(#Enum); \ - \ + } \ return static_cast(src); \ } \ template<> \ diff --git a/shared/global.h b/shared/global.h index 627903f..6d23c2f 100644 --- a/shared/global.h +++ b/shared/global.h @@ -135,7 +135,7 @@ namespace Shared { private: static Global* instance; - std::map optionalFeatures; + std::map pluginSupport; std::map fileCache; #ifdef WITH_KIO diff --git a/shared/messageinfo.cpp b/shared/messageinfo.cpp index a26f23f..7502a6e 100644 --- a/shared/messageinfo.cpp +++ b/shared/messageinfo.cpp @@ -43,19 +43,3 @@ Shared::MessageInfo & Shared::MessageInfo::operator=(const Shared::MessageInfo& return *this; } - -QDataStream& operator >> (QDataStream& in, Shared::MessageInfo& info) { - in >> info.account; - in >> info.jid; - in >> info.messageId; - - return in; -} - -QDataStream& operator <<( QDataStream& out, const Shared::MessageInfo& info) { - out << info.account; - out << info.jid; - out << info.messageId; - - return out; -} diff --git a/shared/messageinfo.h b/shared/messageinfo.h index f06371b..3cf75bc 100644 --- a/shared/messageinfo.h +++ b/shared/messageinfo.h @@ -19,7 +19,6 @@ #pragma once #include -#include namespace Shared { struct MessageInfo { @@ -35,6 +34,3 @@ struct MessageInfo { }; } - -QDataStream& operator << (QDataStream& out, const Shared::MessageInfo& info); -QDataStream& operator >> (QDataStream& in, Shared::MessageInfo& info); diff --git a/ui/utils/flowlayout.cpp b/ui/utils/flowlayout.cpp index 34f978a..ad7715e 100644 --- a/ui/utils/flowlayout.cpp +++ b/ui/utils/flowlayout.cpp @@ -33,78 +33,96 @@ FlowLayout::FlowLayout(int margin, int hSpacing, int vSpacing): setContentsMargins(margin, margin, margin, margin); } -FlowLayout::~FlowLayout() { +FlowLayout::~FlowLayout() +{ QLayoutItem *item; - while ((item = takeAt(0))) + while ((item = takeAt(0))) { delete item; + } } -void FlowLayout::addItem(QLayoutItem *item) { +void FlowLayout::addItem(QLayoutItem *item) +{ itemList.append(item); } -int FlowLayout::horizontalSpacing() const { - if (m_hSpace >= 0) +int FlowLayout::horizontalSpacing() const +{ + if (m_hSpace >= 0) { return m_hSpace; - else + } else { return smartSpacing(QStyle::PM_LayoutHorizontalSpacing); + } } -int FlowLayout::verticalSpacing() const { - if (m_vSpace >= 0) +int FlowLayout::verticalSpacing() const +{ + if (m_vSpace >= 0) { return m_vSpace; - else + } else { return smartSpacing(QStyle::PM_LayoutVerticalSpacing); + } } -int FlowLayout::count() const { +int FlowLayout::count() const +{ return itemList.size(); } -QLayoutItem *FlowLayout::itemAt(int index) const { +QLayoutItem *FlowLayout::itemAt(int index) const +{ return itemList.value(index); } -QLayoutItem *FlowLayout::takeAt(int index) { - if (index >= 0 && index < itemList.size()) +QLayoutItem *FlowLayout::takeAt(int index) +{ + if (index >= 0 && index < itemList.size()) { return itemList.takeAt(index); - + } return nullptr; } -Qt::Orientations FlowLayout::expandingDirections() const { +Qt::Orientations FlowLayout::expandingDirections() const +{ return Qt::Orientations(); } -bool FlowLayout::hasHeightForWidth() const { +bool FlowLayout::hasHeightForWidth() const +{ return true; } -int FlowLayout::heightForWidth(int width) const { +int FlowLayout::heightForWidth(int width) const +{ int height = doLayout(QRect(0, 0, width, 0), true); return height; } -void FlowLayout::setGeometry(const QRect &rect) { +void FlowLayout::setGeometry(const QRect &rect) +{ QLayout::setGeometry(rect); doLayout(rect, false); } -QSize FlowLayout::sizeHint() const { +QSize FlowLayout::sizeHint() const +{ return minimumSize(); } -QSize FlowLayout::minimumSize() const { +QSize FlowLayout::minimumSize() const +{ QSize size; - for (const QLayoutItem *item : std::as_const(itemList)) + for (const QLayoutItem *item : qAsConst(itemList)) { size = size.expandedTo(item->minimumSize()); + } const QMargins margins = contentsMargins(); size += QSize(margins.left() + margins.right(), margins.top() + margins.bottom()); return size; } -int FlowLayout::doLayout(const QRect &rect, bool testOnly) const { +int FlowLayout::doLayout(const QRect &rect, bool testOnly) const +{ int left, top, right, bottom; getContentsMargins(&left, &top, &right, &bottom); QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom); @@ -112,16 +130,16 @@ int FlowLayout::doLayout(const QRect &rect, bool testOnly) const { int y = effectiveRect.y(); int lineHeight = 0; - for (QLayoutItem *item : std::as_const(itemList)) { + for (QLayoutItem *item : qAsConst(itemList)) { const QWidget *wid = item->widget(); int spaceX = horizontalSpacing(); - if (spaceX == -1) + if (spaceX == -1) { spaceX = wid->style()->layoutSpacing(QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal); - + } int spaceY = verticalSpacing(); - if (spaceY == -1) + if (spaceY == -1) { spaceY = wid->style()->layoutSpacing(QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical); - + } int nextX = x + item->sizeHint().width() + spaceX; if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) { x = effectiveRect.x(); @@ -130,8 +148,9 @@ int FlowLayout::doLayout(const QRect &rect, bool testOnly) const { lineHeight = 0; } - if (!testOnly) + if (!testOnly) { item->setGeometry(QRect(QPoint(x, y), item->sizeHint())); + } x = nextX; lineHeight = qMax(lineHeight, item->sizeHint().height()); @@ -139,7 +158,8 @@ int FlowLayout::doLayout(const QRect &rect, bool testOnly) const { return y + lineHeight - rect.y() + bottom; } -int FlowLayout::smartSpacing(QStyle::PixelMetric pm) const { +int FlowLayout::smartSpacing(QStyle::PixelMetric pm) const +{ QObject *parent = this->parent(); if (!parent) { return -1; diff --git a/ui/utils/progress.cpp b/ui/utils/progress.cpp index 676376b..73e4d02 100644 --- a/ui/utils/progress.cpp +++ b/ui/utils/progress.cpp @@ -49,7 +49,7 @@ Progress::Progress(quint16 p_size, QWidget* parent): QGridLayout* layout = new QGridLayout(); setLayout(layout); - layout->setContentsMargins(0, 0, 0, 0); + layout->setMargin(0); layout->setVerticalSpacing(0); layout->setHorizontalSpacing(0); diff --git a/ui/widgets/accounts/account.cpp b/ui/widgets/accounts/account.cpp index 1e2c4c7..164af6c 100644 --- a/ui/widgets/accounts/account.cpp +++ b/ui/widgets/accounts/account.cpp @@ -26,7 +26,6 @@ Account::Account(): m_ui->setupUi(this); connect(m_ui->passwordType, qOverload(&QComboBox::currentIndexChanged), this, &Account::onComboboxChange); - QStandardItemModel *model = static_cast(m_ui->passwordType->model()); for (int i = static_cast(Shared::AccountPasswordLowest); i < static_cast(Shared::AccountPasswordHighest) + 1; ++i) { Shared::AccountPassword ap = static_cast(i); @@ -35,14 +34,18 @@ Account::Account(): m_ui->passwordType->setCurrentIndex(static_cast(Shared::AccountPassword::plain)); if (!Shared::Global::supported("KWallet")) { + QStandardItemModel *model = static_cast(m_ui->passwordType->model()); QStandardItem *item = model->item(static_cast(Shared::AccountPassword::kwallet)); item->setFlags(item->flags() & ~Qt::ItemIsEnabled); } } -Account::~Account() {} +Account::~Account() +{ +} -QMap Account::value() const { +QMap Account::value() const +{ QMap map; map["login"] = m_ui->login->text(); map["password"] = m_ui->password->text(); @@ -55,11 +58,13 @@ QMap Account::value() const { return map; } -void Account::lockId() { +void Account::lockId() +{ m_ui->name->setReadOnly(true);; } -void Account::setData(const QMap& data) { +void Account::setData(const QMap& data) +{ m_ui->login->setText(data.value("login").toString()); m_ui->password->setText(data.value("password").toString()); m_ui->server->setText(data.value("server").toString()); @@ -68,7 +73,8 @@ void Account::setData(const QMap& data) { m_ui->passwordType->setCurrentIndex(data.value("passwordType").toInt()); } -void Account::onComboboxChange(int index) { +void Account::onComboboxChange(int index) +{ QString description = Shared::Global::getDescription(Shared::Global::fromInt(index)); m_ui->comment->setText(description); } diff --git a/ui/widgets/conversation.cpp b/ui/widgets/conversation.cpp index cedcf21..7214a40 100644 --- a/ui/widgets/conversation.cpp +++ b/ui/widgets/conversation.cpp @@ -500,7 +500,7 @@ void Conversation::onFeedContext(const QPoint& pos) { } QString path = Shared::resolvePath(item->getAttachPath()); - if (!path.isEmpty()) { + if (path.size() > 0) { showMenu = true; QAction* open = contextMenu->addAction(Shared::icon("document-preview"), tr("Open")); connect(open, &QAction::triggered, [path]() { @@ -513,7 +513,7 @@ void Conversation::onFeedContext(const QPoint& pos) { }); } - bool hasAttach = !item->getAttachPath().isEmpty() || !item->getOutOfBandUrl().isEmpty(); + bool hasAttach = item->getAttachPath() > 0 || item->getOutOfBandUrl() > 0; //the only mandatory condition - is for the message to be outgoing, the rest is just a good intention on the server if (item->getOutgoing() && !hasAttach && index.row() < 100 && item->getTime().daysTo(QDateTime::currentDateTimeUtc()) < 20) { showMenu = true; diff --git a/ui/widgets/messageline/feedview.cpp b/ui/widgets/messageline/feedview.cpp index 29ec9c6..41e4484 100644 --- a/ui/widgets/messageline/feedview.cpp +++ b/ui/widgets/messageline/feedview.cpp @@ -141,15 +141,7 @@ void FeedView::updateGeometries() { const QStyle* st = style(); QSize layoutBounds = maximumViewportSize(); - - - QStyleOptionViewItem option; -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - initViewItemOption(&option); -#else - option = viewOptions(); -#endif - + QStyleOptionViewItem option = viewOptions(); option.rect.setHeight(maxMessageHeight); option.rect.setWidth(layoutBounds.width()); int frameAroundContents = 0; @@ -190,11 +182,7 @@ void FeedView::updateGeometries() { previousOffset += elementMargin; } lastDate = currentDate; -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - QSize messageSize = itemDelegateForIndex(index)->sizeHint(option, index); -#else QSize messageSize = itemDelegate(index)->sizeHint(option, index); -#endif uint32_t offsetX(0); if (specialDelegate) { if (index.data(Models::MessageFeed::SentByMe).toBool()) @@ -244,11 +232,7 @@ bool FeedView::tryToCalculateGeometriesWithNoScrollbars(const QStyleOptionViewIt previousOffset += elementMargin; } lastDate = currentDate; -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - QSize messageSize = itemDelegateForIndex(index)->sizeHint(option, index); -#else - QSize messageSize = itemDelegate(index)->sizeHint(option, index); -#endif + QSize messageSize = itemDelegate(index)->sizeHint(option, index); if (previousOffset + messageSize.height() + elementMargin > totalHeight) return false; @@ -304,14 +288,8 @@ void FeedView::paintEvent(QPaintEvent* event) { } } - QStyleOptionViewItem option; -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - initViewItemOption(&option); -#else - option = viewOptions(); -#endif - QPainter painter(vp); + QStyleOptionViewItem option = viewOptions(); option.features = QStyleOptionViewItem::WrapText; QPoint cursor = vp->mapFromGlobal(QCursor::pos()); @@ -341,12 +319,7 @@ void FeedView::paintEvent(QPaintEvent* event) { stripe.setWidth(viewportRect.width()); bool mouseOver = stripe.contains(cursor) && viewportRect.contains(cursor); option.state.setFlag(QStyle::State_MouseOver, mouseOver); - -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - itemDelegateForIndex(index)->paint(&painter, option, index); -#else - itemDelegate(index)->paint(&painter, option, index); -#endif + itemDelegate(index)->paint(&painter, option, index); if (!lastDate.isNull() && currentDate.daysTo(lastDate) > 0) drawDateDevider(option.rect.bottom(), lastDate, painter); @@ -406,12 +379,8 @@ void FeedView::setAnchorHovered(Shared::Hover type) { void FeedView::mouseMoveEvent(QMouseEvent* event) { if (!isVisible()) return; -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - dragEndPoint = event->position().toPoint(); -#else - dragEndPoint = event->localPos().toPoint(); -#endif + dragEndPoint = event->localPos().toPoint(); if (mousePressed) { QPoint distance = dragStartPoint - dragEndPoint; if (distance.manhattanLength() > 5) @@ -454,11 +423,7 @@ void FeedView::mousePressEvent(QMouseEvent* event) { mousePressed = event->button() == Qt::LeftButton; if (mousePressed) { -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - dragStartPoint = event->position().toPoint(); -#else - dragStartPoint = event->localPos().toPoint(); -#endif + dragStartPoint = event->localPos().toPoint(); if (specialDelegate && specialModel) { MessageDelegate* del = static_cast(itemDelegate()); QString lastSelectedId = del->clearSelection(); @@ -476,11 +441,7 @@ void FeedView::mouseDoubleClickEvent(QMouseEvent* event) { QAbstractItemView::mouseDoubleClickEvent(event); mousePressed = event->button() == Qt::LeftButton; if (mousePressed) { -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - dragStartPoint = event->position().toPoint(); -#else - dragStartPoint = event->localPos().toPoint(); -#endif + dragStartPoint = event->localPos().toPoint(); if (specialDelegate && specialModel) { MessageDelegate* del = static_cast(itemDelegate()); QString lastSelectedId = del->clearSelection(); @@ -508,11 +469,7 @@ void FeedView::mouseReleaseEvent(QMouseEvent* event) { if (mousePressed) { if (!dragging && specialDelegate) { -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - QPoint point = event->position().toPoint(); -#else QPoint point = event->localPos().toPoint(); -#endif QModelIndex index = indexAt(point); if (index.isValid()) { QRect rect = visualRect(index); diff --git a/ui/widgets/messageline/feedview.h b/ui/widgets/messageline/feedview.h index 19645c0..a39afc8 100644 --- a/ui/widgets/messageline/feedview.h +++ b/ui/widgets/messageline/feedview.h @@ -16,7 +16,8 @@ * along with this program. If not, see . */ -#pragma once +#ifndef FEEDVIEW_H +#define FEEDVIEW_H #include #include @@ -29,7 +30,11 @@ #include #include -class FeedView : public QAbstractItemView { +/** + * @todo write docs + */ +class FeedView : public QAbstractItemView +{ Q_OBJECT public: FeedView(QWidget* parent = nullptr); @@ -106,3 +111,5 @@ private: static const std::set geometryChangingRoles; }; + +#endif //FEEDVIEW_H diff --git a/ui/widgets/messageline/messagedelegate.cpp b/ui/widgets/messageline/messagedelegate.cpp index b82a992..b89b438 100644 --- a/ui/widgets/messageline/messagedelegate.cpp +++ b/ui/widgets/messageline/messagedelegate.cpp @@ -659,7 +659,7 @@ QLabel * MessageDelegate::getStatusIcon(const Models::FeedItem& data) const { QIcon q(Shared::icon(Shared::messageStateThemeIcons[static_cast(data.state)])); QString tt = Shared::Global::getName(data.state); if (data.state == Shared::Message::State::error) { - if (data.error.size() > 0) + if (data.error > 0) tt += ": " + data.error; } if (result->toolTip() != tt) { //If i just assign pixmap every time unconditionally diff --git a/ui/widgets/settings/settingslist.cpp b/ui/widgets/settings/settingslist.cpp index ae071ff..ee2e3ed 100644 --- a/ui/widgets/settings/settingslist.cpp +++ b/ui/widgets/settings/settingslist.cpp @@ -21,39 +21,36 @@ SettingsList::SettingsList(QWidget* parent): QListWidget(parent), lastWidth(0) -{} +{ -SettingsList::~SettingsList() {} - -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) -void SettingsList::initViewItemOption(QStyleOptionViewItem* option) const { - QListWidget::initViewItemOption(option); - if (!iconSize().isValid()) - option->decorationSize.setWidth(lastWidth); - - option->rect.setWidth(lastWidth); } -#else -QStyleOptionViewItem SettingsList::viewOptions() const { - QStyleOptionViewItem option = QListWidget::viewOptions(); - if (!iconSize().isValid()) - option.decorationSize.setWidth(lastWidth); +SettingsList::~SettingsList() +{ +} + +QStyleOptionViewItem SettingsList::viewOptions() const +{ + QStyleOptionViewItem option = QListWidget::viewOptions(); + if (!iconSize().isValid()) { + option.decorationSize.setWidth(lastWidth); + } option.rect.setWidth(lastWidth); return option; } -#endif -void SettingsList::resizeEvent(QResizeEvent* event) { +void SettingsList::resizeEvent(QResizeEvent* event) +{ lastWidth = event->size().width(); QListWidget::resizeEvent(event); } -QRect SettingsList::visualRect(const QModelIndex& index) const { +QRect SettingsList::visualRect(const QModelIndex& index) const +{ QRect res = QListWidget::visualRect(index); - if (index.isValid()) + if (index.isValid()) { res.setWidth(lastWidth); - + } return res; } diff --git a/ui/widgets/settings/settingslist.h b/ui/widgets/settings/settingslist.h index 14ebf55..64c9d57 100644 --- a/ui/widgets/settings/settingslist.h +++ b/ui/widgets/settings/settingslist.h @@ -16,28 +16,29 @@ * along with this program. If not, see . */ -#pragma once +#ifndef UI_SETTINGSLIST_H +#define UI_SETTINGSLIST_H #include #include -#include -class SettingsList : public QListWidget { +/** + * @todo write docs + */ +class SettingsList : public QListWidget +{ Q_OBJECT public: SettingsList(QWidget* parent = nullptr); ~SettingsList(); protected: -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - void initViewItemOption(QStyleOptionViewItem* option) const override; -#else QStyleOptionViewItem viewOptions() const override; -#endif - void resizeEvent(QResizeEvent * event) override; QRect visualRect(const QModelIndex & index) const override; private: int lastWidth; }; + +#endif // UI_SETTINGSLIST_H