diff --git a/CMakeLists.txt b/CMakeLists.txt index b537fe0..a62c800 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,6 @@ 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) @@ -35,7 +34,6 @@ 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_SIMPLE_CRYPT "Builds with SimpleCrypt to obfuscate password" ON) # Dependencies ## Qt @@ -69,9 +67,9 @@ endif () ## KIO if (WITH_KIO) - find_package(KF5KIO CONFIG) + find_package(KF${QT_VERSION_MAJOR}KIO CONFIG) - if (NOT KF5KIO_FOUND) + if (NOT KF${QT_VERSION_MAJOR}KIO_FOUND) set(WITH_KIO OFF) message("KIO package wasn't found, KIO support modules wouldn't be built") else () @@ -82,9 +80,9 @@ endif () ## KWallet if (WITH_KWALLET) - find_package(KF5Wallet CONFIG) + find_package(KF${QT_VERSION_MAJOR}Wallet CONFIG) - if (NOT KF5Wallet_FOUND) + if (NOT KF${QT_VERSION_MAJOR}Wallet_FOUND) set(WITH_KWALLET OFF) message("KWallet package wasn't found, KWallet support module wouldn't be built") else () @@ -95,13 +93,13 @@ endif () ## KConfig if (WITH_KCONFIG) - find_package(KF5Config CONFIG) - if (NOT KF5Config_FOUND) + find_package(KF${QT_VERSION_MAJOR}Config CONFIG) + if (NOT KF${QT_VERSION_MAJOR}Config_FOUND) set(WITH_KCONFIG OFF) message("KConfig package wasn't found, KConfig support modules wouldn't be built") else() - find_package(KF5ConfigWidgets CONFIG) - if (NOT KF5ConfigWidgets_FOUND) + find_package(KF${QT_VERSION_MAJOR}ConfigWidgets CONFIG) + if (NOT KF${QT_VERSION_MAJOR}ConfigWidgets_FOUND) set(WITH_KCONFIG OFF) message("KConfigWidgets package wasn't found, KConfigWidgets support modules wouldn't be built") else() @@ -115,12 +113,12 @@ endif() ## QXmpp if (SYSTEM_QXMPP) if (WITH_OMEMO) - find_package(QXmpp CONFIG COMPONENTS Omemo) + find_package(QXmppQt${QT_VERSION_MAJOR} CONFIG COMPONENTS Omemo) else () - find_package(QXmpp CONFIG) + find_package(QXmppQt${QT_VERSION_MAJOR} CONFIG) endif () - if (NOT QXmpp_FOUND) + if (NOT QXmppQt${QT_VERSION_MAJOR}_FOUND) set(SYSTEM_QXMPP OFF) message("QXmpp package wasn't found, trying to build with bundled QXmpp") else () @@ -152,8 +150,8 @@ endif () ## LMDBAL if (SYSTEM_LMDBAL) - find_package(lmdbal) - if (NOT lmdbal_FOUND) + find_package(lmdbalqt${QT_VERSION_MAJOR}) + if (NOT lmdbalqt${QT_VERSION_MAJOR}_FOUND) set(SYSTEM_LMDBAL OFF) message("LMDBAL package wasn't found, trying to build with bundled LMDBAL") else () @@ -163,9 +161,11 @@ else() message("Building with bundled LMDBAL") set(BUILD_STATIC ON) add_subdirectory(external/lmdbal) - add_library(LMDBAL::LMDBAL ALIAS LMDBAL) + add_library(LMDBALQT${QT_VERSION_MAJOR}::LMDBALQT${QT_VERSION_MAJOR} ALIAS LMDBAL) endif() +find_package(OpenSSL REQUIRED) + ## Linking target_link_libraries(squawk PRIVATE @@ -175,7 +175,8 @@ target_link_libraries(squawk Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Xml - LMDBAL::LMDBAL + LMDBALQT${QT_VERSION_MAJOR}::LMDBALQT${QT_VERSION_MAJOR} + OpenSSL::Crypto QXmpp::QXmpp ) @@ -183,12 +184,6 @@ if (WITH_OMEMO) target_link_libraries(squawk PRIVATE QXmpp::Omemo) endif () -if (WITH_SIMPLE_CRYPT) - target_compile_definitions(squawk PRIVATE WITH_SIMPLE_CRYPT) - add_subdirectory(external/simpleCrypt) - target_link_libraries(squawk PRIVATE simpleCrypt) -endif () - ## Link thread libraries on Linux if(UNIX AND NOT APPLE) set(THREADS_PREFER_PTHREAD_FLAG ON) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index a02bfe6..8baa5ad 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -23,10 +23,7 @@ set(HEADER_FILES squawk.h ) -target_sources(squawk PRIVATE - ${SOURCE_FILES} - ${HEADER_FILES} -) +target_sources(squawk PRIVATE ${SOURCE_FILES}) target_include_directories(squawk PRIVATE ${LMDB_INCLUDE_DIRS}) @@ -34,3 +31,4 @@ 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 8082aeb..6143fa6 100644 --- a/core/account.cpp +++ b/core/account.cpp @@ -81,6 +81,7 @@ Core::Account::Account( config.setDomain(p_server); config.setPassword(p_password); config.setAutoAcceptSubscriptions(true); + config.setIgnoreSslErrors(true); //config.setAutoReconnectionEnabled(false); delay = new DelayManager::Manager(getBareJid()); QObject::connect(delay, &DelayManager::Manager::gotInfo, this, &Account::infoReady); diff --git a/core/components/CMakeLists.txt b/core/components/CMakeLists.txt index 77d290b..751a01f 100644 --- a/core/components/CMakeLists.txt +++ b/core/components/CMakeLists.txt @@ -12,7 +12,4 @@ set(HEADER_FILES archive.h ) -target_sources(squawk PRIVATE - ${SOURCE_FILES} - ${HEADER_FILES} -) +target_sources(squawk PRIVATE ${SOURCE_FILES}) diff --git a/core/components/networkaccess.cpp b/core/components/networkaccess.cpp index 0771dfa..59e2448 100644 --- a/core/components/networkaccess.cpp +++ b/core/components/networkaccess.cpp @@ -550,10 +550,8 @@ void Core::NetworkAccess::moveFilesDirectory(const QString& newPath) { QDir dir(currentPath); bool success = true; qDebug() << "moving" << currentPath << "to" << newPath; - for (QFileInfo fileInfo : dir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System)) { - QString fileName = fileInfo.fileName(); + for (QString fileName : dir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System)) 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 ae6c695..b9ae3b6 100644 --- a/core/handlers/messagehandler.cpp +++ b/core/handlers/messagehandler.cpp @@ -492,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(path, id); + uploadingSlotsQueue.emplace_back(file, id); if (uploadingSlotsQueue.size() == 1) acc->um->requestUploadSlot(file); } else { @@ -505,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, slot.putUrl(), slot.getUrl(), slot.putHeaders()); + acc->network->uploadFile({acc->name, palJid, mId}, pair.first.path(), slot.putUrl(), slot.getUrl(), slot.putHeaders()); uploadingSlotsQueue.pop_front(); if (uploadingSlotsQueue.size() > 0) @@ -522,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 15f99bf..917b98d 100644 --- a/core/handlers/messagehandler.h +++ b/core/handlers/messagehandler.h @@ -19,6 +19,7 @@ #pragma once #include +#include #include #include @@ -81,7 +82,7 @@ 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 2afda3f..2a38931 100644 --- a/core/passwordStorageEngines/CMakeLists.txt +++ b/core/passwordStorageEngines/CMakeLists.txt @@ -1,9 +1,6 @@ if (WITH_KWALLET) - target_sources(squawk PRIVATE - kwallet.cpp - kwallet.h - ) + target_sources(squawk PRIVATE kwallet.cpp) add_subdirectory(wrappers) - target_include_directories(squawk PRIVATE $) + target_include_directories(squawk PRIVATE $) endif () diff --git a/core/passwordStorageEngines/kwallet.h b/core/passwordStorageEngines/kwallet.h index 28475d2..1f047e6 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 432079f..6280cc0 100644 --- a/core/passwordStorageEngines/wrappers/CMakeLists.txt +++ b/core/passwordStorageEngines/wrappers/CMakeLists.txt @@ -1,4 +1,5 @@ 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) diff --git a/core/passwordStorageEngines/wrappers/kwallet.cpp b/core/passwordStorageEngines/wrappers/kwallet.cpp index d899985..5c7bc99 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 1d1abe5..1851eb3 100644 --- a/core/squawk.cpp +++ b/core/squawk.cpp @@ -22,9 +22,7 @@ #include #include -#ifdef WITH_SIMPLE_CRYPT -#include "external/simpleCrypt/simplecrypt.h" -#endif +#include "utils/jammer.h" Core::Squawk::Squawk(QObject* parent): QObject(parent), @@ -87,18 +85,14 @@ void Core::Squawk::stop() { password = acc->getPassword(); break; case Shared::AccountPassword::jammed: -#ifdef WITH_SIMPLE_CRYPT2 - password = SimpleCrypt(passwordHash).encryptToString(acc->getPassword()); -#else - qDebug() << "The password for account" << acc->getName() << "is set to be jammed, but Squawk was compiled without SimpleCrypt support"; - qDebug("Can not encode password, setting this account to always ask password mode"); - ap = Shared::AccountPassword::alwaysAsk; -#endif + password = Jammer::encrypt(acc->getPassword(), passwordHash); break; default: break; } + qDebug() << "Saving password for" << acc->getName() << password; + settings.setValue("name", acc->getName()); settings.setValue("server", acc->getServer()); settings.setValue("login", acc->getLogin()); @@ -708,16 +702,8 @@ void Core::Squawk::readSettings() { QString name = settings.value("name").toString(); QString password = settings.value("password", "").toString(); - if (passwordType == Shared::AccountPassword::jammed) { -#ifdef WITH_SIMPLE_CRYPT - SimpleCrypt crypto(passwordHash); - password = crypto.decryptToString(password); -#else - qDebug() << "The password for account" << name << "is jammed, but Squawk was compiled without SimpleCrypt support"; - qDebug("Can not decode password, setting this account to always ask password mode"); - passwordType = Shared::AccountPassword::alwaysAsk; -#endif - } + if (passwordType == Shared::AccountPassword::jammed) + password = Jammer::decrypt(password, passwordHash); addAccount( settings.value("login").toString(), diff --git a/core/utils/CMakeLists.txt b/core/utils/CMakeLists.txt new file mode 100644 index 0000000..e030130 --- /dev/null +++ b/core/utils/CMakeLists.txt @@ -0,0 +1,9 @@ +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 new file mode 100644 index 0000000..1714c6b --- /dev/null +++ b/core/utils/jammer.cpp @@ -0,0 +1,94 @@ +/* + * 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 new file mode 100644 index 0000000..456c14b --- /dev/null +++ b/core/utils/jammer.h @@ -0,0 +1,44 @@ +/* + * 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/simpleCrypt/CMakeLists.txt b/external/simpleCrypt/CMakeLists.txt deleted file mode 100644 index 5f274ba..0000000 --- a/external/simpleCrypt/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -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 deleted file mode 100644 index 093403e..0000000 --- a/external/simpleCrypt/simplecrypt.cpp +++ /dev/null @@ -1,248 +0,0 @@ -/* - 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 deleted file mode 100644 index 0052618..0000000 --- a/external/simpleCrypt/simplecrypt.h +++ /dev/null @@ -1,226 +0,0 @@ -/* - 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/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 565651e..9eb9070 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 KF5::KIOWidgets) + target_link_libraries(openFileManagerWindowJob PRIVATE KF${QT_VERSION_MAJOR}::KIOWidgets) install(TARGETS openFileManagerWindowJob LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/squawk) endif () if (WITH_KCONFIG) add_library(colorSchemeTools SHARED colorschemetools.cpp) - target_link_libraries(colorSchemeTools PRIVATE KF5::ConfigCore) - target_link_libraries(colorSchemeTools PRIVATE KF5::ConfigWidgets) + target_link_libraries(colorSchemeTools PRIVATE KF${QT_VERSION_MAJOR}::ConfigCore) + target_link_libraries(colorSchemeTools PRIVATE KF${QT_VERSION_MAJOR}::ConfigWidgets) install(TARGETS colorSchemeTools LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/squawk) endif() diff --git a/plugins/colorschemetools.cpp b/plugins/colorschemetools.cpp index ea2c23e..76eba9b 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/shared/CMakeLists.txt b/shared/CMakeLists.txt index 2ef3970..45fcfd0 100644 --- a/shared/CMakeLists.txt +++ b/shared/CMakeLists.txt @@ -39,7 +39,4 @@ 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 5188b1c..05bed45 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 . -#ifndef SHARED_CLIENTID_H -#define SHARED_CLIENTID_H +#pragma once #include #include +#include namespace Shared { @@ -54,5 +54,3 @@ 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 288e9fa..ca66c6d 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 . -#ifndef SHARED_CLIENTINFO_H -#define SHARED_CLIENTINFO_H +#pragma once #include +#include #include #include @@ -54,5 +54,3 @@ private: QDataStream& operator << (QDataStream& stream, const Shared::ClientInfo& info); QDataStream& operator >> (QDataStream& stream, Shared::ClientInfo& info); - -#endif // SHARED_CLIENTINFO_H diff --git a/shared/enums.h b/shared/enums.h index 43d1583..6f5e9db 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 362bf81..f0e3230 100644 --- a/shared/global.cpp +++ b/shared/global.cpp @@ -23,12 +23,6 @@ #include "enums.h" #include "ui/models/roster.h" -#ifdef WITH_SIMPLE_CRYPT -#define SIMPLE_CRYPT_ENABLED true -#else -#define SIMPLE_CRYPT_ENABLED false -#endif - #ifdef WITH_OMEMO constexpr bool OMEMO_SUPPORT = true; #else @@ -158,8 +152,7 @@ Shared::Global::Global(): optionalFeatures({ {"KWallet", false}, {"openFileManagerWindowJob", false}, - {"colorSchemeTools", false}, - {"simpleCryptJammedPassword", SIMPLE_CRYPT_ENABLED} + {"colorSchemeTools", false} }), fileCache() { @@ -324,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); diff --git a/shared/messageinfo.cpp b/shared/messageinfo.cpp index 7502a6e..a26f23f 100644 --- a/shared/messageinfo.cpp +++ b/shared/messageinfo.cpp @@ -43,3 +43,19 @@ 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 3cf75bc..f06371b 100644 --- a/shared/messageinfo.h +++ b/shared/messageinfo.h @@ -19,6 +19,7 @@ #pragma once #include +#include namespace Shared { struct MessageInfo { @@ -34,3 +35,6 @@ struct MessageInfo { }; } + +QDataStream& operator << (QDataStream& out, const Shared::MessageInfo& info); +QDataStream& operator >> (QDataStream& in, Shared::MessageInfo& info); diff --git a/ui/utils/progress.cpp b/ui/utils/progress.cpp index 73e4d02..676376b 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->setMargin(0); + layout->setContentsMargins(0, 0, 0, 0); layout->setVerticalSpacing(0); layout->setHorizontalSpacing(0); diff --git a/ui/widgets/accounts/account.cpp b/ui/widgets/accounts/account.cpp index 2d70603..1e2c4c7 100644 --- a/ui/widgets/accounts/account.cpp +++ b/ui/widgets/accounts/account.cpp @@ -38,11 +38,6 @@ Account::Account(): QStandardItem *item = model->item(static_cast(Shared::AccountPassword::kwallet)); item->setFlags(item->flags() & ~Qt::ItemIsEnabled); } - - if (!Shared::Global::supported("simpleCryptJammedPassword")) { - QStandardItem *item = model->item(static_cast(Shared::AccountPassword::jammed)); - item->setFlags(item->flags() & ~Qt::ItemIsEnabled); - } } Account::~Account() {} diff --git a/ui/widgets/conversation.cpp b/ui/widgets/conversation.cpp index 7214a40..cedcf21 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.size() > 0) { + if (!path.isEmpty()) { 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() > 0 || item->getOutOfBandUrl() > 0; + bool hasAttach = !item->getAttachPath().isEmpty() || !item->getOutOfBandUrl().isEmpty(); //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 41e4484..3c56d84 100644 --- a/ui/widgets/messageline/feedview.cpp +++ b/ui/widgets/messageline/feedview.cpp @@ -141,7 +141,15 @@ void FeedView::updateGeometries() { const QStyle* st = style(); QSize layoutBounds = maximumViewportSize(); - QStyleOptionViewItem option = viewOptions(); + + + QStyleOptionViewItem option; +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + initViewItemOption(&option); +#else + option = viewOptions(); +#endif + option.rect.setHeight(maxMessageHeight); option.rect.setWidth(layoutBounds.width()); int frameAroundContents = 0; @@ -182,7 +190,7 @@ void FeedView::updateGeometries() { previousOffset += elementMargin; } lastDate = currentDate; - QSize messageSize = itemDelegate(index)->sizeHint(option, index); + QSize messageSize = itemDelegateForIndex(index)->sizeHint(option, index); uint32_t offsetX(0); if (specialDelegate) { if (index.data(Models::MessageFeed::SentByMe).toBool()) @@ -232,7 +240,7 @@ bool FeedView::tryToCalculateGeometriesWithNoScrollbars(const QStyleOptionViewIt previousOffset += elementMargin; } lastDate = currentDate; - QSize messageSize = itemDelegate(index)->sizeHint(option, index); + QSize messageSize = itemDelegateForIndex(index)->sizeHint(option, index); if (previousOffset + messageSize.height() + elementMargin > totalHeight) return false; @@ -288,8 +296,14 @@ 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()); @@ -319,7 +333,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); - itemDelegate(index)->paint(&painter, option, index); + itemDelegateForIndex(index)->paint(&painter, option, index); if (!lastDate.isNull() && currentDate.daysTo(lastDate) > 0) drawDateDevider(option.rect.bottom(), lastDate, painter); @@ -380,7 +394,7 @@ void FeedView::mouseMoveEvent(QMouseEvent* event) { if (!isVisible()) return; - dragEndPoint = event->localPos().toPoint(); + dragEndPoint = event->position().toPoint(); if (mousePressed) { QPoint distance = dragStartPoint - dragEndPoint; if (distance.manhattanLength() > 5) @@ -423,7 +437,7 @@ void FeedView::mousePressEvent(QMouseEvent* event) { mousePressed = event->button() == Qt::LeftButton; if (mousePressed) { - dragStartPoint = event->localPos().toPoint(); + dragStartPoint = event->position().toPoint(); if (specialDelegate && specialModel) { MessageDelegate* del = static_cast(itemDelegate()); QString lastSelectedId = del->clearSelection(); @@ -441,7 +455,7 @@ void FeedView::mouseDoubleClickEvent(QMouseEvent* event) { QAbstractItemView::mouseDoubleClickEvent(event); mousePressed = event->button() == Qt::LeftButton; if (mousePressed) { - dragStartPoint = event->localPos().toPoint(); + dragStartPoint = event->position().toPoint(); if (specialDelegate && specialModel) { MessageDelegate* del = static_cast(itemDelegate()); QString lastSelectedId = del->clearSelection(); @@ -469,7 +483,7 @@ void FeedView::mouseReleaseEvent(QMouseEvent* event) { if (mousePressed) { if (!dragging && specialDelegate) { - QPoint point = event->localPos().toPoint(); + QPoint point = event->position().toPoint(); 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 a39afc8..19645c0 100644 --- a/ui/widgets/messageline/feedview.h +++ b/ui/widgets/messageline/feedview.h @@ -16,8 +16,7 @@ * along with this program. If not, see . */ -#ifndef FEEDVIEW_H -#define FEEDVIEW_H +#pragma once #include #include @@ -30,11 +29,7 @@ #include #include -/** - * @todo write docs - */ -class FeedView : public QAbstractItemView -{ +class FeedView : public QAbstractItemView { Q_OBJECT public: FeedView(QWidget* parent = nullptr); @@ -111,5 +106,3 @@ private: static const std::set geometryChangingRoles; }; - -#endif //FEEDVIEW_H diff --git a/ui/widgets/messageline/messagedelegate.cpp b/ui/widgets/messageline/messagedelegate.cpp index b89b438..b82a992 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 > 0) + if (data.error.size() > 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 ee2e3ed..ae071ff 100644 --- a/ui/widgets/settings/settingslist.cpp +++ b/ui/widgets/settings/settingslist.cpp @@ -21,36 +21,39 @@ 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); } - -SettingsList::~SettingsList() -{ -} - -QStyleOptionViewItem SettingsList::viewOptions() const -{ +#else +QStyleOptionViewItem SettingsList::viewOptions() const { QStyleOptionViewItem option = QListWidget::viewOptions(); - if (!iconSize().isValid()) { + 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 64c9d57..14ebf55 100644 --- a/ui/widgets/settings/settingslist.h +++ b/ui/widgets/settings/settingslist.h @@ -16,29 +16,28 @@ * along with this program. If not, see . */ -#ifndef UI_SETTINGSLIST_H -#define UI_SETTINGSLIST_H +#pragma once #include #include +#include -/** - * @todo write docs - */ -class SettingsList : public QListWidget -{ +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