1
0
forked from blue/squawk

Compare commits

..

13 Commits

Author SHA1 Message Date
321f0b03c8
Fix build for qt 5, removed some debug messages 2024-12-14 18:08:50 +02:00
d4cec645b5
qt6 build 2024-12-14 01:53:04 +02:00
a04693e39d
fix: build without KConfig is possible once more 2024-11-19 18:45:11 +02:00
3cce057545
fix: omitting from attribute not to wreck the stream
fix: build without kwallet
2024-11-18 22:43:46 +02:00
9a44ae1fa5
SimpleCrypt password jamming is now optional 2024-11-17 20:25:33 +02:00
85ff6c25ba
find boos cmake new policy
magick instead of convert rendering images
2024-10-27 20:02:34 +02:00
3cc7db8eff
A workaround to store plugins in a subdirectory 2024-10-27 19:33:03 +02:00
Benson Muite
ff9a591d6d
Private libraries directory 2024-10-27 19:33:03 +02:00
8e3f10caff Merge pull request 'Add appdata file' (#94) from bmckwm/squawk:appdata into master
Reviewed-on: blue/squawk#94
Reviewed-by: Blue <blue@macaw.me>
2024-10-13 07:37:05 +00:00
8bfe88929f Merge pull request 'Fix license text error' (#90) from bmckwm/squawk:license into master
Reviewed-on: blue/squawk#90
Reviewed-by: Blue <blue@macaw.me>
2024-10-13 07:35:29 +00:00
9927bdc38b Merge pull request 'Update image link' (#87) from bmckwm/squawk:image-link-update into master
Reviewed-on: blue/squawk#87
Reviewed-by: Blue <blue@macaw.me>
2024-10-13 07:34:34 +00:00
Benson Muite
8083859541 Fix license text error 2024-10-07 13:45:15 +03:00
Benson Muite
2c61b82924 Add appdata file 2024-10-06 19:26:44 +03:00
47 changed files with 448 additions and 696 deletions

View File

@ -1,5 +1,13 @@
# Changelog # 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
- got rid of deprecated SimpleCrypt library
## Squawk 0.2.3 (February 04, 2024) ## Squawk 0.2.3 (February 04, 2024)
### Bug fixes ### Bug fixes
- "Add contact" and "Join conference" menu are enabled once again (pavavno)! - "Add contact" and "Join conference" menu are enabled once again (pavavno)!

View File

@ -1,12 +1,12 @@
cmake_minimum_required(VERSION 3.5) cmake_minimum_required(VERSION 3.16)
project(squawk VERSION 0.2.3 LANGUAGES CXX) project(squawk VERSION 0.2.4 LANGUAGES CXX)
cmake_policy(SET CMP0076 NEW) cmake_policy(SET CMP0076 NEW)
cmake_policy(SET CMP0077 NEW) cmake_policy(SET CMP0077 NEW)
cmake_policy(SET CMP0079 NEW) cmake_policy(SET CMP0079 NEW)
cmake_policy(SET CMP0167 NEW)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
set(QT_VERSION_MAJOR 5)
set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON) set(CMAKE_AUTORCC ON)
@ -33,7 +33,7 @@ option(SYSTEM_LMDBAL "Use system lmdbal lib" ON)
option(WITH_KWALLET "Build KWallet support module" ON) option(WITH_KWALLET "Build KWallet support module" ON)
option(WITH_KIO "Build KIO support module" ON) option(WITH_KIO "Build KIO support module" ON)
option(WITH_KCONFIG "Build KConfig 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 sourt the problems out option(WITH_OMEMO "Build OMEMO support module" OFF) #it should be off by default untill I sort the problems out
# Dependencies # Dependencies
## Qt ## Qt
@ -67,9 +67,9 @@ endif ()
## KIO ## KIO
if (WITH_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) set(WITH_KIO OFF)
message("KIO package wasn't found, KIO support modules wouldn't be built") message("KIO package wasn't found, KIO support modules wouldn't be built")
else () else ()
@ -80,9 +80,9 @@ endif ()
## KWallet ## KWallet
if (WITH_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) set(WITH_KWALLET OFF)
message("KWallet package wasn't found, KWallet support module wouldn't be built") message("KWallet package wasn't found, KWallet support module wouldn't be built")
else () else ()
@ -93,13 +93,13 @@ endif ()
## KConfig ## KConfig
if (WITH_KCONFIG) if (WITH_KCONFIG)
find_package(KF5Config CONFIG) find_package(KF${QT_VERSION_MAJOR}Config CONFIG)
if (NOT KF5Config_FOUND) if (NOT KF${QT_VERSION_MAJOR}Config_FOUND)
set(WITH_KCONFIG OFF) set(WITH_KCONFIG OFF)
message("KConfig package wasn't found, KConfig support modules wouldn't be built") message("KConfig package wasn't found, KConfig support modules wouldn't be built")
else() else()
find_package(KF5ConfigWidgets CONFIG) find_package(KF${QT_VERSION_MAJOR}ConfigWidgets CONFIG)
if (NOT KF5ConfigWidgets_FOUND) if (NOT KF${QT_VERSION_MAJOR}ConfigWidgets_FOUND)
set(WITH_KCONFIG OFF) set(WITH_KCONFIG OFF)
message("KConfigWidgets package wasn't found, KConfigWidgets support modules wouldn't be built") message("KConfigWidgets package wasn't found, KConfigWidgets support modules wouldn't be built")
else() else()
@ -113,12 +113,12 @@ endif()
## QXmpp ## QXmpp
if (SYSTEM_QXMPP) if (SYSTEM_QXMPP)
if (WITH_OMEMO) if (WITH_OMEMO)
find_package(QXmpp CONFIG COMPONENTS Omemo) find_package(QXmppQt${QT_VERSION_MAJOR} CONFIG COMPONENTS Omemo)
else () else ()
find_package(QXmpp CONFIG) find_package(QXmppQt${QT_VERSION_MAJOR} CONFIG)
endif () endif ()
if (NOT QXmpp_FOUND) if (NOT QXmppQt${QT_VERSION_MAJOR}_FOUND)
set(SYSTEM_QXMPP OFF) set(SYSTEM_QXMPP OFF)
message("QXmpp package wasn't found, trying to build with bundled QXmpp") message("QXmpp package wasn't found, trying to build with bundled QXmpp")
else () else ()
@ -150,8 +150,8 @@ endif ()
## LMDBAL ## LMDBAL
if (SYSTEM_LMDBAL) if (SYSTEM_LMDBAL)
find_package(lmdbal) find_package(lmdbalqt${QT_VERSION_MAJOR})
if (NOT lmdbal_FOUND) if (NOT lmdbalqt${QT_VERSION_MAJOR}_FOUND)
set(SYSTEM_LMDBAL OFF) set(SYSTEM_LMDBAL OFF)
message("LMDBAL package wasn't found, trying to build with bundled LMDBAL") message("LMDBAL package wasn't found, trying to build with bundled LMDBAL")
else () else ()
@ -161,9 +161,11 @@ else()
message("Building with bundled LMDBAL") message("Building with bundled LMDBAL")
set(BUILD_STATIC ON) set(BUILD_STATIC ON)
add_subdirectory(external/lmdbal) add_subdirectory(external/lmdbal)
add_library(LMDBAL::LMDBAL ALIAS LMDBAL) add_library(LMDBALQT${QT_VERSION_MAJOR}::LMDBALQT${QT_VERSION_MAJOR} ALIAS LMDBAL)
endif() endif()
find_package(OpenSSL REQUIRED)
## Linking ## Linking
target_link_libraries(squawk target_link_libraries(squawk
PRIVATE PRIVATE
@ -173,9 +175,9 @@ target_link_libraries(squawk
Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::Network
Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Gui
Qt${QT_VERSION_MAJOR}::Xml Qt${QT_VERSION_MAJOR}::Xml
LMDBAL::LMDBAL LMDBALQT${QT_VERSION_MAJOR}::LMDBALQT${QT_VERSION_MAJOR}
OpenSSL::Crypto
QXmpp::QXmpp QXmpp::QXmpp
simpleCrypt
) )
if (WITH_OMEMO) if (WITH_OMEMO)
@ -211,9 +213,13 @@ if(CMAKE_COMPILER_IS_GNUCXX)
target_compile_options(squawk PRIVATE ${COMPILE_OPTIONS}) target_compile_options(squawk PRIVATE ${COMPILE_OPTIONS})
endif(CMAKE_COMPILER_IS_GNUCXX) 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(main)
add_subdirectory(core) add_subdirectory(core)
add_subdirectory(external/simpleCrypt)
add_subdirectory(packaging) add_subdirectory(packaging)
add_subdirectory(plugins) add_subdirectory(plugins)
add_subdirectory(resources) add_subdirectory(resources)

View File

@ -8,8 +8,8 @@
### Prerequisites ### Prerequisites
- QT 5.12 *(lower versions might work but it wasn't tested)* - QT 5 or 6
- CMake 3.4 or higher - CMake 3.10 or higher
- qxmpp 1.1.0 or higher - qxmpp 1.1.0 or higher
- LMDBAL (my own [library](https://git.macaw.me/blue/lmdbal) for lmdb) - LMDBAL (my own [library](https://git.macaw.me/blue/lmdbal) for lmdb)
- KDE Frameworks: kwallet (optional) - KDE Frameworks: kwallet (optional)
@ -108,6 +108,7 @@ 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_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_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`) - `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. By default it picks your system default Qt
## License ## License

View File

@ -23,10 +23,7 @@ set(HEADER_FILES
squawk.h squawk.h
) )
target_sources(squawk PRIVATE target_sources(squawk PRIVATE ${SOURCE_FILES})
${SOURCE_FILES}
${HEADER_FILES}
)
target_include_directories(squawk PRIVATE ${LMDB_INCLUDE_DIRS}) target_include_directories(squawk PRIVATE ${LMDB_INCLUDE_DIRS})
@ -34,3 +31,4 @@ add_subdirectory(handlers)
add_subdirectory(passwordStorageEngines) add_subdirectory(passwordStorageEngines)
add_subdirectory(components) add_subdirectory(components)
add_subdirectory(delayManager) add_subdirectory(delayManager)
add_subdirectory(utils)

View File

@ -81,7 +81,8 @@ Core::Account::Account(
config.setDomain(p_server); config.setDomain(p_server);
config.setPassword(p_password); config.setPassword(p_password);
config.setAutoAcceptSubscriptions(true); config.setAutoAcceptSubscriptions(true);
//config.setAutoReconnectionEnabled(false); // config.setIgnoreSslErrors(true);
// config.setAutoReconnectionEnabled(false);
delay = new DelayManager::Manager(getBareJid()); delay = new DelayManager::Manager(getBareJid());
QObject::connect(delay, &DelayManager::Manager::gotInfo, this, &Account::infoReady); QObject::connect(delay, &DelayManager::Manager::gotInfo, this, &Account::infoReady);
QObject::connect(delay, &DelayManager::Manager::gotOwnInfo, this, &Account::infoReady); QObject::connect(delay, &DelayManager::Manager::gotOwnInfo, this, &Account::infoReady);

View File

@ -12,7 +12,4 @@ set(HEADER_FILES
archive.h archive.h
) )
target_sources(squawk PRIVATE target_sources(squawk PRIVATE ${SOURCE_FILES})
${SOURCE_FILES}
${HEADER_FILES}
)

View File

@ -550,10 +550,8 @@ void Core::NetworkAccess::moveFilesDirectory(const QString& newPath) {
QDir dir(currentPath); QDir dir(currentPath);
bool success = true; bool success = true;
qDebug() << "moving" << currentPath << "to" << newPath; qDebug() << "moving" << currentPath << "to" << newPath;
for (QFileInfo fileInfo : dir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System)) { for (QString fileName : 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; success = dir.rename(fileName, newPath + QDir::separator() + fileName) && success;
}
if (!success) if (!success)
qDebug() << "couldn't move downloads directory, most probably downloads will be broken"; qDebug() << "couldn't move downloads directory, most probably downloads will be broken";

View File

@ -431,7 +431,7 @@ QMap<QString, QVariant> Core::MessageHandler::getChanges(Shared::Message& data,
} }
QXmppMessage Core::MessageHandler::createPacket(const Shared::Message& data, const QDateTime& time, const QString& originalId) const { QXmppMessage Core::MessageHandler::createPacket(const Shared::Message& data, const QDateTime& time, const QString& originalId) const {
QXmppMessage msg(acc->getFullJid(), data.getTo(), data.getBody(), data.getThread()); QXmppMessage msg(QString(), data.getTo(), data.getBody(), data.getThread());
QString id(data.getId()); QString id(data.getId());
if (originalId.size() > 0) if (originalId.size() > 0)
@ -492,7 +492,7 @@ void Core::MessageHandler::prepareUpload(const Shared::Message& data, bool newMe
QFileInfo file(path); QFileInfo file(path);
if (file.exists() && file.isReadable()) { if (file.exists() && file.isReadable()) {
pendingStateMessages.insert(std::make_pair(id, jid)); pendingStateMessages.insert(std::make_pair(id, jid));
uploadingSlotsQueue.emplace_back(path, id); uploadingSlotsQueue.emplace_back(file, id);
if (uploadingSlotsQueue.size() == 1) if (uploadingSlotsQueue.size() == 1)
acc->um->requestUploadSlot(file); acc->um->requestUploadSlot(file);
} else { } else {
@ -505,10 +505,10 @@ void Core::MessageHandler::onUploadSlotReceived(const QXmppHttpUploadSlotIq& slo
if (uploadingSlotsQueue.size() == 0) { if (uploadingSlotsQueue.size() == 0) {
qDebug() << "HTTP Upload manager of account" << acc->name << "reports about success requesting upload slot, but none was requested"; qDebug() << "HTTP Upload manager of account" << acc->name << "reports about success requesting upload slot, but none was requested";
} else { } else {
const std::pair<QString, QString>& pair = uploadingSlotsQueue.front(); const std::pair<QFileInfo, QString>& pair = uploadingSlotsQueue.front();
const QString& mId = pair.second; const QString& mId = pair.second;
QString palJid = pendingStateMessages.at(mId); 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(); uploadingSlotsQueue.pop_front();
if (uploadingSlotsQueue.size() > 0) 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() << "HTTP Upload manager of account" << acc->name << "reports about an error requesting upload slot, but none was requested";
qDebug() << err; qDebug() << err;
} else { } else {
const std::pair<QString, QString>& pair = uploadingSlotsQueue.front(); const std::pair<QFileInfo, QString>& pair = uploadingSlotsQueue.front();
qDebug() << "Error requesting upload slot for file" << pair.first << "in account" << acc->name << ":" << err; qDebug() << "Error requesting upload slot for file" << pair.first << "in account" << acc->name << ":" << err;
handleUploadError(pendingStateMessages.at(pair.second), pair.second, err); handleUploadError(pendingStateMessages.at(pair.second), pair.second, err);

View File

@ -19,6 +19,7 @@
#pragma once #pragma once
#include <QObject> #include <QObject>
#include <QFileInfo>
#include <deque> #include <deque>
#include <map> #include <map>
@ -81,7 +82,7 @@ private:
Account* acc; Account* acc;
std::map<QString, QString> pendingStateMessages; //key is message id, value is JID std::map<QString, QString> pendingStateMessages; //key is message id, value is JID
std::map<QString, QString> pendingCorrectionMessages; //key is new mesage, value is originalOne std::map<QString, QString> pendingCorrectionMessages; //key is new mesage, value is originalOne
std::deque<std::pair<QString, QString>> uploadingSlotsQueue; std::deque<std::pair<QFileInfo, QString>> uploadingSlotsQueue;
}; };
} }

View File

@ -1,9 +1,6 @@
if (WITH_KWALLET) if (WITH_KWALLET)
target_sources(squawk PRIVATE target_sources(squawk PRIVATE kwallet.cpp)
kwallet.cpp
kwallet.h
)
add_subdirectory(wrappers) add_subdirectory(wrappers)
target_include_directories(squawk PRIVATE $<TARGET_PROPERTY:KF5::Wallet,INTERFACE_INCLUDE_DIRECTORIES>) target_include_directories(squawk PRIVATE $<TARGET_PROPERTY:KF${QT_VERSION_MAJOR}::Wallet,INTERFACE_INCLUDE_DIRECTORIES>)
endif () endif ()

View File

@ -28,7 +28,8 @@ Core::PSE::KWallet::CreateFolder Core::PSE::KWallet::createFolder = 0;
Core::PSE::KWallet::SetFolder Core::PSE::KWallet::setFolder = 0; Core::PSE::KWallet::SetFolder Core::PSE::KWallet::setFolder = 0;
Core::PSE::KWallet::SupportState Core::PSE::KWallet::sState = Core::PSE::KWallet::initial; Core::PSE::KWallet::SupportState Core::PSE::KWallet::sState = Core::PSE::KWallet::initial;
QLibrary Core::PSE::KWallet::lib("kwalletWrapper");
QLibrary Core::PSE::KWallet::lib(QString("%1/kwalletWrapper").arg(PLUGIN_PATH));
Core::PSE::KWallet::KWallet(): Core::PSE::KWallet::KWallet():
QObject(), QObject(),

View File

@ -27,7 +27,7 @@
#include <map> #include <map>
#include <set> #include <set>
#include <KF5/KWallet/KWallet> #include <KWallet>
namespace Core { namespace Core {
namespace PSE { namespace PSE {

View File

@ -1,4 +1,5 @@
add_library(kwalletWrapper SHARED kwallet.cpp) add_library(kwalletWrapper SHARED kwallet.cpp)
target_link_libraries(kwalletWrapper PRIVATE KF5::Wallet)
install(TARGETS kwalletWrapper LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) target_link_libraries(kwalletWrapper PRIVATE KF${QT_VERSION_MAJOR}::Wallet)
install(TARGETS kwalletWrapper LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/squawk)

View File

@ -16,7 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <KF5/KWallet/KWallet> #include <KWallet>
extern "C" KWallet::Wallet* openWallet(const QString &name, WId w, KWallet::Wallet::OpenType ot = KWallet::Wallet::Synchronous) { extern "C" KWallet::Wallet* openWallet(const QString &name, WId w, KWallet::Wallet::OpenType ot = KWallet::Wallet::Synchronous) {
return KWallet::Wallet::openWallet(name, w, ot); return KWallet::Wallet::openWallet(name, w, ot);

View File

@ -22,6 +22,8 @@
#include <QDir> #include <QDir>
#include <QStandardPaths> #include <QStandardPaths>
#include "utils/jammer.h"
Core::Squawk::Squawk(QObject* parent): Core::Squawk::Squawk(QObject* parent):
QObject(parent), QObject(parent),
accounts(), accounts(),
@ -29,10 +31,10 @@ Core::Squawk::Squawk(QObject* parent):
state(Shared::Availability::offline), state(Shared::Availability::offline),
network(), network(),
isInitialized(false), isInitialized(false),
clientCache(),
#ifdef WITH_KWALLET #ifdef WITH_KWALLET
kwallet() kwallet(),
#endif #endif
clientCache()
{ {
connect(&network, &NetworkAccess::loadFileProgress, this, &Squawk::fileProgress); connect(&network, &NetworkAccess::loadFileProgress, this, &Squawk::fileProgress);
connect(&network, &NetworkAccess::loadFileError, this, &Squawk::fileError); connect(&network, &NetworkAccess::loadFileError, this, &Squawk::fileError);
@ -71,7 +73,6 @@ void Core::Squawk::stop() {
QSettings settings; QSettings settings;
settings.beginGroup("core"); settings.beginGroup("core");
settings.beginWriteArray("accounts"); settings.beginWriteArray("accounts");
SimpleCrypt crypto(passwordHash);
for (std::deque<Account*>::size_type i = 0; i < accounts.size(); ++i) { for (std::deque<Account*>::size_type i = 0; i < accounts.size(); ++i) {
settings.setArrayIndex(i); settings.setArrayIndex(i);
Account* acc = accounts[i]; Account* acc = accounts[i];
@ -84,7 +85,7 @@ void Core::Squawk::stop() {
password = acc->getPassword(); password = acc->getPassword();
break; break;
case Shared::AccountPassword::jammed: case Shared::AccountPassword::jammed:
password = crypto.encryptToString(acc->getPassword()); password = Jammer::encrypt(acc->getPassword(), passwordHash);
break; break;
default: default:
break; break;
@ -697,17 +698,16 @@ void Core::Squawk::readSettings() {
settings.value("passwordType", static_cast<int>(Shared::AccountPassword::plain)).toInt() settings.value("passwordType", static_cast<int>(Shared::AccountPassword::plain)).toInt()
); );
QString name = settings.value("name").toString();
QString password = settings.value("password", "").toString(); QString password = settings.value("password", "").toString();
if (passwordType == Shared::AccountPassword::jammed) { if (passwordType == Shared::AccountPassword::jammed)
SimpleCrypt crypto(passwordHash); password = Jammer::decrypt(password, passwordHash);
password = crypto.decryptToString(password);
}
addAccount( addAccount(
settings.value("login").toString(), settings.value("login").toString(),
settings.value("server").toString(), settings.value("server").toString(),
password, password,
settings.value("name").toString(), name,
settings.value("resource").toString(), settings.value("resource").toString(),
settings.value("active").toBool(), settings.value("active").toBool(),
passwordType passwordType

View File

@ -33,7 +33,6 @@
#include "shared/global.h" #include "shared/global.h"
#include "shared/info.h" #include "shared/info.h"
#include "shared/clientinfo.h" #include "shared/clientinfo.h"
#include "external/simpleCrypt/simplecrypt.h"
#include <core/components/clientcache.h> #include <core/components/clientcache.h>
#include <core/components/networkaccess.h> #include <core/components/networkaccess.h>
@ -42,10 +41,8 @@
#include "passwordStorageEngines/kwallet.h" #include "passwordStorageEngines/kwallet.h"
#endif #endif
namespace Core namespace Core {
{ class Squawk : public QObject {
class Squawk : public QObject
{
Q_OBJECT Q_OBJECT
public: public:
@ -140,11 +137,12 @@ private:
Shared::Availability state; Shared::Availability state;
NetworkAccess network; NetworkAccess network;
bool isInitialized; bool isInitialized;
ClientCache clientCache;
#ifdef WITH_KWALLET #ifdef WITH_KWALLET
PSE::KWallet kwallet; PSE::KWallet kwallet;
#endif #endif
ClientCache clientCache;
private slots: private slots:
void addAccount( void addAccount(

View File

@ -0,0 +1,9 @@
set(SOURCE_FILES
jammer.cpp
)
set(HEADER_FILES
jammer.h
)
target_sources(squawk PRIVATE ${SOURCE_FILES})

94
core/utils/jammer.cpp Normal file
View File

@ -0,0 +1,94 @@
/*
* Squawk messenger.
* Copyright (C) 2019 Yury Gubich <blue@macaw.me>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "jammer.h"
#include <memory>
#include <openssl/evp.h>
#include <openssl/err.h>
struct CipherCtxDeleter {
void operator()(EVP_CIPHER_CTX* ctx) const {
EVP_CIPHER_CTX_free(ctx);
}
};
typedef std::unique_ptr<EVP_CIPHER_CTX, CipherCtxDeleter> 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<const char *>(&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<unsigned char *>(data.data());}
const unsigned char* Core::Jammer::toUChar(const QByteArray& data) {
return reinterpret_cast<const unsigned char *>(data.constData());}

44
core/utils/jammer.h Normal file
View File

@ -0,0 +1,44 @@
/*
* Squawk messenger.
* Copyright (C) 2019 Yury Gubich <blue@macaw.me>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stdexcept>
#include <QByteArray>
#include <QString>
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();
};
}

View File

@ -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)

View File

@ -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 #######; 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 <QByteArray>
#include <QtDebug>
#include <QtGlobal>
#include <QDateTime>
#include <QCryptographicHash>
#include <QDataStream>
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<char>(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;
}

View File

@ -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 #######; 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 <QString>
#include <QVector>
#include <QFlags>
#include <QRandomGenerator>
/**
@ 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<char> m_keyParts;
CompressionMode m_compressionMode;
IntegrityProtectionMode m_protectionMode;
Error m_lastError;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(SimpleCrypt::CryptoFlags)
#endif // SimpleCrypt_H

View File

@ -58,6 +58,7 @@ Root::~Root() {
delete gui; delete gui;
if (core != nullptr) if (core != nullptr)
delete core; delete core;
delete coreThread; delete coreThread;
} }
delete global; delete global;
@ -72,13 +73,13 @@ void Root::initializeTranslation() {
bool found = false; bool found = false;
for (QString share : shares) { for (QString share : shares) {
found = currentTranslator.load(QLocale(), QLatin1String("squawk"), ".", share + "/l10n"); found = currentTranslator.load(QLocale(), QLatin1String("squawk"), ".", share + "/l10n");
if (found) { if (found)
break; break;
}
} }
if (!found) {
if (!found)
currentTranslator.load(QLocale(), QLatin1String("squawk"), ".", QCoreApplication::applicationDirPath()); currentTranslator.load(QLocale(), QLatin1String("squawk"), ".", QCoreApplication::applicationDirPath());
}
installTranslator(&currentTranslator); installTranslator(&currentTranslator);
} }
@ -94,18 +95,16 @@ bool Root::initializeSettings() {
QVariant vs = settings.value("style"); QVariant vs = settings.value("style");
if (vs.isValid()) { if (vs.isValid()) {
QString style = vs.toString().toLower(); QString style = vs.toString().toLower();
if (style != "system") { if (style != "system")
Shared::Global::setStyle(style); Shared::Global::setStyle(style);
}
} }
if (Shared::Global::supported("colorSchemeTools")) { if (Shared::Global::supported("colorSchemeTools")) {
QVariant vt = settings.value("theme"); QVariant vt = settings.value("theme");
if (vt.isValid()) { if (vt.isValid()) {
QString theme = vt.toString(); QString theme = vt.toString();
if (theme.toLower() != "system") { if (theme.toLower() != "system")
Shared::Global::setTheme(theme); Shared::Global::setTheme(theme);
}
} }
} }

View File

@ -1,19 +1,19 @@
# Maintainer: Yury Gubich <blue@macaw.me> # Maintainer: Yury Gubich <blue@macaw.me>
pkgname=squawk pkgname=squawk
pkgver=0.2.3 pkgver=0.2.4
pkgrel=1 pkgrel=1
pkgdesc="An XMPP desktop messenger, written on pure c++ (qt)" pkgdesc="An XMPP desktop messenger, written on pure c++ (qt)"
arch=('i686' 'x86_64') arch=('i686' 'x86_64')
url="https://git.macaw.me/blue/squawk" url="https://git.macaw.me/blue/squawk"
license=('GPL3') license=('GPL3')
depends=('hicolor-icon-theme' 'desktop-file-utils' 'lmdbal' 'qxmpp-qt5') depends=('hicolor-icon-theme' 'desktop-file-utils' 'lmdbal-qt6' 'qxmpp-qt6')
makedepends=('cmake>=3.3' 'imagemagick' 'qt5-tools' 'boost') makedepends=('cmake>=3.3' 'imagemagick' 'qt6-tools' 'boost')
optdepends=('kwallet5: secure password storage (requires rebuild)' optdepends=('kwallet6: secure password storage (requires rebuild)'
'kconfig5: system themes support (requires rebuild)' 'kconfig6: system themes support (requires rebuild)'
'kconfigwidgets5: system themes support (requires rebuild)' 'kconfigwidgets6: system themes support (requires rebuild)'
'kio5: better show in folder action (requires rebuild)') 'kio6: better show in folder action (requires rebuild)')
source=("$pkgname-$pkgver.tar.gz::https://git.macaw.me/blue/$pkgname/archive/$pkgver.tar.gz") source=("$pkgname-$pkgver-$pkgrel.tar.gz::https://git.macaw.me/blue/$pkgname/archive/$pkgver.tar.gz")
sha256sums=('SKIP') sha256sums=('SKIP')
build() { build() {
cd "$srcdir/squawk" cd "$srcdir/squawk"

View File

@ -1,3 +1,7 @@
configure_file(squawk.desktop squawk.desktop COPYONLY) configure_file(squawk.desktop squawk.desktop COPYONLY)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/squawk.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications) 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)

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<component xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:its="http://www.w3.org/2005/11/its" xmlns="https://specifications.freedesktop.org/metainfo/1.0" type="desktop-application">
<id>macaw.me.squawk</id>
<metadata_license>CC0-1.0</metadata_license>
<project_license>GPL-3.0+</project_license>
<name>Squawk</name>
<summary>Desktop Qt based XMPP messenger</summary>
<description>
<p>
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 systems style, while
also minimizing resource consumption.
</p>
<p>
Squawk is still at a very early stage and might not suit
everyone but you are welcome to try it out.
</p>
</description>
<launchable type="desktop-id">macaw.me.squawk.desktop</launchable>
<screenshots>
<screenshot type="default">
<image>https://macaw.me/projects/squawk/0.2.2.png</image>
<caption>View XMPP contacts and conversations</caption>
</screenshot>
</screenshots>
<url type="homepage">https://macaw.me/projects/squawk/</url>
<provides>
<binary>squawk</binary>
</provides>
<update_contact>blue@macaw.me</update_contact>
</component>

View File

@ -1,7 +1,7 @@
[Desktop Entry] [Desktop Entry]
Type=Application Type=Application
Version=1.0 Version=0.2.4
Name=Squawk Name=Squawk
GenericName=Instant Messenger GenericName=Instant Messenger
GenericName[ru]=Мгновенные сообщения GenericName[ru]=Мгновенные сообщения

View File

@ -1,14 +1,14 @@
if (WITH_KIO) if (WITH_KIO)
add_library(openFileManagerWindowJob SHARED openfilemanagerwindowjob.cpp) 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}) install(TARGETS openFileManagerWindowJob LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/squawk)
endif () endif ()
if (WITH_KCONFIG) if (WITH_KCONFIG)
add_library(colorSchemeTools SHARED colorschemetools.cpp) add_library(colorSchemeTools SHARED colorschemetools.cpp)
target_link_libraries(colorSchemeTools PRIVATE KF5::ConfigCore) target_link_libraries(colorSchemeTools PRIVATE KF${QT_VERSION_MAJOR}::ConfigCore)
target_link_libraries(colorSchemeTools PRIVATE KF5::ConfigWidgets) target_link_libraries(colorSchemeTools PRIVATE KF${QT_VERSION_MAJOR}::ConfigWidgets)
install(TARGETS colorSchemeTools LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(TARGETS colorSchemeTools LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/squawk)
endif() endif()

View File

@ -20,9 +20,9 @@
#include <QPainter> #include <QPainter>
#include <QFileInfo> #include <QFileInfo>
#include <KConfigCore/KSharedConfig> #include <KSharedConfig>
#include <KConfigCore/KConfigGroup> #include <KConfigGroup>
#include <KConfigWidgets/KColorScheme> #include <KColorScheme>
QPixmap createPixmap(int size, const QBrush& window, const QBrush& button, const QBrush& view, const QBrush& selection); QPixmap createPixmap(int size, const QBrush& window, const QBrush& button, const QBrush& view, const QBrush& selection);

View File

@ -3,11 +3,8 @@ target_sources(squawk PRIVATE resources.qrc)
configure_file(images/logo.svg squawk.svg COPYONLY) configure_file(images/logo.svg squawk.svg COPYONLY)
configure_file(squawk.rc squawk.rc COPYONLY) configure_file(squawk.rc squawk.rc COPYONLY)
if(WIN32) set(CONVERT_BIN magick)
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 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 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}) execute_process(COMMAND ${CONVERT_BIN} -background none -size 128x128 squawk.svg squawk128.png WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
@ -18,20 +15,20 @@ if (WIN32)
set(SQUAWK_WIN_RC "${CMAKE_CURRENT_BINARY_DIR}/squawk.rc") set(SQUAWK_WIN_RC "${CMAKE_CURRENT_BINARY_DIR}/squawk.rc")
set(SQUAWK_WIN_RC "${SQUAWK_WIN_RC}" PARENT_SCOPE) set(SQUAWK_WIN_RC "${SQUAWK_WIN_RC}" PARENT_SCOPE)
target_sources(squawk PRIVATE ${SQUAWK_WIN_RC}) target_sources(squawk PRIVATE ${SQUAWK_WIN_RC})
endif(WIN32) endif (WIN32)
if (APPLE) if (APPLE)
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/icns.iconset") file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/icns.iconset")
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_BIN} -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_BIN} -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_BIN} -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_BIN} -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_BIN} -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_BIN} -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_BIN} -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_BIN} -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_BIN} -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 ${CONVERT_BIN} -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}) 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 squawk.icns)
set(MACOSX_BUNDLE_ICON_FILE ${MACOSX_BUNDLE_ICON_FILE} PARENT_SCOPE) set(MACOSX_BUNDLE_ICON_FILE ${MACOSX_BUNDLE_ICON_FILE} PARENT_SCOPE)
@ -47,8 +44,8 @@ if (APPLE)
MACOSX_BUNDLE_ICON_FILE "${MACOSX_BUNDLE_ICON_FILE}" # TODO MACOSX_BUNDLE_ICON_FILE "${MACOSX_BUNDLE_ICON_FILE}" # TODO
MACOSX_BUNDLE_BUNDLE_NAME "Squawk" MACOSX_BUNDLE_BUNDLE_NAME "Squawk"
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/cmake/MacOSXBundleInfo.plist.in) MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/cmake/MacOSXBundleInfo.plist.in)
endif(APPLE) endif (APPLE)
endif() endif ()
endif (APPLE) endif (APPLE)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/squawk.svg DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/squawk.svg DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps)

View File

@ -39,7 +39,4 @@ set(HEADER_FILES
defines.h defines.h
) )
target_sources(squawk PRIVATE target_sources(squawk PRIVATE ${SOURCE_FILES} ${HEADER_FILES})
${SOURCE_FILES}
${HEADER_FILES}
)

View File

@ -14,11 +14,11 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef SHARED_CLIENTID_H #pragma once
#define SHARED_CLIENTID_H
#include <QString> #include <QString>
#include <QDataStream> #include <QDataStream>
#include <QMetaType>
namespace Shared { namespace Shared {
@ -54,5 +54,3 @@ Q_DECLARE_METATYPE(Shared::ClientId)
QDataStream& operator << (QDataStream& stream, const Shared::ClientId& info); QDataStream& operator << (QDataStream& stream, const Shared::ClientId& info);
QDataStream& operator >> (QDataStream& stream, Shared::ClientId& info); QDataStream& operator >> (QDataStream& stream, Shared::ClientId& info);
#endif // SHARED_CLIENTID_H

View File

@ -14,10 +14,10 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef SHARED_CLIENTINFO_H #pragma once
#define SHARED_CLIENTINFO_H
#include <set> #include <set>
#include <map>
#include <QDataStream> #include <QDataStream>
#include <QString> #include <QString>
@ -54,5 +54,3 @@ private:
QDataStream& operator << (QDataStream& stream, const Shared::ClientInfo& info); QDataStream& operator << (QDataStream& stream, const Shared::ClientInfo& info);
QDataStream& operator >> (QDataStream& stream, Shared::ClientInfo& info); QDataStream& operator >> (QDataStream& stream, Shared::ClientInfo& info);
#endif // SHARED_CLIENTINFO_H

View File

@ -16,9 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef SHARED_DEFINES_H #pragma once
#define SHARED_DEFINES_H
#define SHARED_UNUSED(x) (void)(x) #define SHARED_UNUSED(x) (void)(x)
#endif

View File

@ -101,8 +101,8 @@ enum class Avatar {
valid valid
}; };
Q_ENUM_NS(Avatar) Q_ENUM_NS(Avatar)
static const Avatar AvatarHighest = Avatar::valid; static const Avatar AvatarHighest = Avatar::valid;
static const Avatar AvatarLowest = Avatar::empty; static const Avatar AvatarLowest = Avatar::empty;
static const std::deque<QString> messageStateThemeIcons = {"state-offline", "state-sync", "state-ok", "state-error"}; static const std::deque<QString> messageStateThemeIcons = {"state-offline", "state-sync", "state-ok", "state-error"};

View File

@ -19,8 +19,10 @@
#include "global.h" #include "global.h"
#include <QFontDatabase> #include <QFontDatabase>
#include "defines.h"
#include "enums.h" #include "enums.h"
#include "ui/models/roster.h" #include "ui/models/roster.h"
#ifdef WITH_OMEMO #ifdef WITH_OMEMO
constexpr bool OMEMO_SUPPORT = true; constexpr bool OMEMO_SUPPORT = true;
#else #else
@ -36,11 +38,10 @@ QFont getFont (QFontDatabase::SystemFont type, bool bold = false, bool italic =
if (factor != 1.0) { if (factor != 1.0) {
float ps = font.pointSizeF(); float ps = font.pointSizeF();
if (ps != -1) { if (ps != -1)
font.setPointSizeF(ps * factor); font.setPointSizeF(ps * factor);
} else { else
font.setPointSize(font.pointSize() * factor); font.setPointSize(font.pointSize() * factor);
}
} }
return font; return font;
@ -50,12 +51,12 @@ Shared::Global* Shared::Global::instance = 0;
const std::set<QString> Shared::Global::supportedImagesExts = {"png", "jpg", "webp", "jpeg", "gif", "svg"}; const std::set<QString> Shared::Global::supportedImagesExts = {"png", "jpg", "webp", "jpeg", "gif", "svg"};
#ifdef WITH_KIO #ifdef WITH_KIO
QLibrary Shared::Global::openFileManagerWindowJob("openFileManagerWindowJob"); QLibrary Shared::Global::openFileManagerWindowJob(QString("%1/openFileManagerWindowJob").arg(PLUGIN_PATH));
Shared::Global::HighlightInFileManager Shared::Global::hfm = 0; Shared::Global::HighlightInFileManager Shared::Global::hfm = 0;
#endif #endif
#ifdef WITH_KCONFIG #ifdef WITH_KCONFIG
QLibrary Shared::Global::colorSchemeTools("colorSchemeTools"); QLibrary Shared::Global::colorSchemeTools(QString("%1/colorSchemeTools").arg(PLUGIN_PATH));
Shared::Global::CreatePreview Shared::Global::createPreview = 0; Shared::Global::CreatePreview Shared::Global::createPreview = 0;
Shared::Global::DeletePreview Shared::Global::deletePreview = 0; Shared::Global::DeletePreview Shared::Global::deletePreview = 0;
Shared::Global::ColorSchemeName Shared::Global::colorSchemeName = 0; Shared::Global::ColorSchemeName Shared::Global::colorSchemeName = 0;
@ -148,7 +149,7 @@ Shared::Global::Global():
smallFontMetrics(smallFont), smallFontMetrics(smallFont),
headerFontMetrics(headerFont), headerFontMetrics(headerFont),
titleFontMetrics(titleFont), titleFontMetrics(titleFont),
pluginSupport({ optionalFeatures({
{"KWallet", false}, {"KWallet", false},
{"openFileManagerWindowJob", false}, {"openFileManagerWindowJob", false},
{"colorSchemeTools", false} {"colorSchemeTools", false}
@ -197,8 +198,7 @@ Shared::Global::Global():
static const QSize defaultIconFileInfoHeight(50, 50); 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<QString, FileInfo>::const_iterator itr = instance->fileCache.find(path); std::map<QString, FileInfo>::const_iterator itr = instance->fileCache.find(path);
if (itr == instance->fileCache.end()) { if (itr == instance->fileCache.end()) {
QMimeDatabase db; QMimeDatabase db;
@ -275,17 +275,17 @@ QString Shared::Global::getName(EncryptionProtocol ep) {
} }
void Shared::Global::setSupported(const QString& pluginName, bool support) { void Shared::Global::setSupported(const QString& pluginName, bool support) {
std::map<QString, bool>::iterator itr = instance->pluginSupport.find(pluginName); std::map<QString, bool>::iterator itr = instance->optionalFeatures.find(pluginName);
if (itr != instance->pluginSupport.end()) { if (itr != instance->optionalFeatures.end()) {
itr->second = support; itr->second = support;
} }
} }
bool Shared::Global::supported(const QString& pluginName) { bool Shared::Global::supported(const QString& pluginName) {
std::map<QString, bool>::iterator itr = instance->pluginSupport.find(pluginName); std::map<QString, bool>::iterator itr = instance->optionalFeatures.find(pluginName);
if (itr != instance->pluginSupport.end()) { if (itr != instance->optionalFeatures.end())
return itr->second; return itr->second;
}
return false; 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"; qDebug() << "requested to highlight in file manager url" << path << "but it's not supported: squawk wasn't compiled to support it, trying fallback";
#endif #endif
QFileInfo info = path; QFileInfo info(path);
if (info.exists()) { if (info.exists()) {
QProcess proc; QProcess proc;
proc.start("xdg-mime", query); proc.start("xdg-mime", query);
@ -325,11 +325,10 @@ void Shared::Global::highlightInFileManager(const QString& path)
QString output = proc.readLine().simplified(); QString output = proc.readLine().simplified();
QString folder; QString folder;
if (info.isDir()) { if (info.isDir())
folder = info.canonicalFilePath(); folder = info.canonicalFilePath();
} else { else
folder = info.canonicalPath(); folder = info.canonicalPath();
}
if (output.contains(dolphinReg)) { if (output.contains(dolphinReg)) {
//there is a bug on current (21.04.0) dolphin, it works correct only if you already have dolphin launched //there is a bug on current (21.04.0) dolphin, it works correct only if you already have dolphin launched
@ -356,27 +355,32 @@ void Shared::Global::highlightInFileManager(const QString& path)
} }
QIcon Shared::Global::createThemePreview(const QString& path) { QIcon Shared::Global::createThemePreview(const QString& path) {
#ifdef WITH_KCONFIG
if (supported("colorSchemeTools")) { if (supported("colorSchemeTools")) {
QIcon* icon = createPreview(path); QIcon* icon = createPreview(path);
QIcon localIcon = *icon; QIcon localIcon = *icon;
deletePreview(icon); deletePreview(icon);
return localIcon; return localIcon;
} else {
return QIcon();
} }
#endif
return QIcon();
} }
QString Shared::Global::getColorSchemeName(const QString& path) { QString Shared::Global::getColorSchemeName(const QString& path) {
#ifdef WITH_KCONFIG
if (supported("colorSchemeTools")) { if (supported("colorSchemeTools")) {
QString res; QString res;
colorSchemeName(path, res); colorSchemeName(path, res);
return res; return res;
} else {
return "";
} }
#endif
return "";
} }
void Shared::Global::setTheme(const QString& path) { void Shared::Global::setTheme(const QString& path) {
#ifdef WITH_KCONFIG
if (supported("colorSchemeTools")) { if (supported("colorSchemeTools")) {
if (path.toLower() == "system") { if (path.toLower() == "system") {
QApplication::setPalette(getInstance()->defaultSystemPalette); QApplication::setPalette(getInstance()->defaultSystemPalette);
@ -386,23 +390,26 @@ void Shared::Global::setTheme(const QString& path) {
QApplication::setPalette(pallete); 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) { void Shared::Global::setStyle(const QString& style) {
if (style.toLower() == "system") { if (style.toLower() == "system")
QApplication::setStyle(getInstance()->defaultSystemStyle); QApplication::setStyle(getInstance()->defaultSystemStyle);
} else { else
QApplication::setStyle(style); QApplication::setStyle(style);
}
} }
#define FROM_INT_INPL(Enum) \ #define FROM_INT_INPL(Enum) \
template<> \ template<> \
Enum Shared::Global::fromInt(int src) \ Enum Shared::Global::fromInt(int src) \
{ \ { \
if (src < static_cast<int>(Enum##Lowest) || src > static_cast<int>(Enum##Highest)) { \ if (src < static_cast<int>(Enum##Lowest) || src > static_cast<int>(Enum##Highest)) \
throw EnumOutOfRange(#Enum); \ throw EnumOutOfRange(#Enum); \
} \ \
return static_cast<Enum>(src); \ return static_cast<Enum>(src); \
} \ } \
template<> \ template<> \

View File

@ -135,7 +135,7 @@ namespace Shared {
private: private:
static Global* instance; static Global* instance;
std::map<QString, bool> pluginSupport; std::map<QString, bool> optionalFeatures;
std::map<QString, FileInfo> fileCache; std::map<QString, FileInfo> fileCache;
#ifdef WITH_KIO #ifdef WITH_KIO

View File

@ -43,3 +43,19 @@ Shared::MessageInfo & Shared::MessageInfo::operator=(const Shared::MessageInfo&
return *this; 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;
}

View File

@ -19,6 +19,7 @@
#pragma once #pragma once
#include <QString> #include <QString>
#include <QDataStream>
namespace Shared { namespace Shared {
struct MessageInfo { struct MessageInfo {
@ -34,3 +35,6 @@ struct MessageInfo {
}; };
} }
QDataStream& operator << (QDataStream& out, const Shared::MessageInfo& info);
QDataStream& operator >> (QDataStream& in, Shared::MessageInfo& info);

View File

@ -49,7 +49,7 @@ Progress::Progress(quint16 p_size, QWidget* parent):
QGridLayout* layout = new QGridLayout(); QGridLayout* layout = new QGridLayout();
setLayout(layout); setLayout(layout);
layout->setMargin(0); layout->setContentsMargins(0, 0, 0, 0);
layout->setVerticalSpacing(0); layout->setVerticalSpacing(0);
layout->setHorizontalSpacing(0); layout->setHorizontalSpacing(0);

View File

@ -26,6 +26,7 @@ Account::Account():
m_ui->setupUi(this); m_ui->setupUi(this);
connect(m_ui->passwordType, qOverload<int>(&QComboBox::currentIndexChanged), this, &Account::onComboboxChange); connect(m_ui->passwordType, qOverload<int>(&QComboBox::currentIndexChanged), this, &Account::onComboboxChange);
QStandardItemModel *model = static_cast<QStandardItemModel*>(m_ui->passwordType->model());
for (int i = static_cast<int>(Shared::AccountPasswordLowest); i < static_cast<int>(Shared::AccountPasswordHighest) + 1; ++i) { for (int i = static_cast<int>(Shared::AccountPasswordLowest); i < static_cast<int>(Shared::AccountPasswordHighest) + 1; ++i) {
Shared::AccountPassword ap = static_cast<Shared::AccountPassword>(i); Shared::AccountPassword ap = static_cast<Shared::AccountPassword>(i);
@ -34,18 +35,14 @@ Account::Account():
m_ui->passwordType->setCurrentIndex(static_cast<int>(Shared::AccountPassword::plain)); m_ui->passwordType->setCurrentIndex(static_cast<int>(Shared::AccountPassword::plain));
if (!Shared::Global::supported("KWallet")) { if (!Shared::Global::supported("KWallet")) {
QStandardItemModel *model = static_cast<QStandardItemModel*>(m_ui->passwordType->model());
QStandardItem *item = model->item(static_cast<int>(Shared::AccountPassword::kwallet)); QStandardItem *item = model->item(static_cast<int>(Shared::AccountPassword::kwallet));
item->setFlags(item->flags() & ~Qt::ItemIsEnabled); item->setFlags(item->flags() & ~Qt::ItemIsEnabled);
} }
} }
Account::~Account() Account::~Account() {}
{
}
QMap<QString, QVariant> Account::value() const QMap<QString, QVariant> Account::value() const {
{
QMap<QString, QVariant> map; QMap<QString, QVariant> map;
map["login"] = m_ui->login->text(); map["login"] = m_ui->login->text();
map["password"] = m_ui->password->text(); map["password"] = m_ui->password->text();
@ -58,13 +55,11 @@ QMap<QString, QVariant> Account::value() const
return map; return map;
} }
void Account::lockId() void Account::lockId() {
{
m_ui->name->setReadOnly(true);; m_ui->name->setReadOnly(true);;
} }
void Account::setData(const QMap<QString, QVariant>& data) void Account::setData(const QMap<QString, QVariant>& data) {
{
m_ui->login->setText(data.value("login").toString()); m_ui->login->setText(data.value("login").toString());
m_ui->password->setText(data.value("password").toString()); m_ui->password->setText(data.value("password").toString());
m_ui->server->setText(data.value("server").toString()); m_ui->server->setText(data.value("server").toString());
@ -73,8 +68,7 @@ void Account::setData(const QMap<QString, QVariant>& data)
m_ui->passwordType->setCurrentIndex(data.value("passwordType").toInt()); 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<Shared::AccountPassword>(index)); QString description = Shared::Global::getDescription(Shared::Global::fromInt<Shared::AccountPassword>(index));
m_ui->comment->setText(description); m_ui->comment->setText(description);
} }

View File

@ -500,7 +500,7 @@ void Conversation::onFeedContext(const QPoint& pos) {
} }
QString path = Shared::resolvePath(item->getAttachPath()); QString path = Shared::resolvePath(item->getAttachPath());
if (path.size() > 0) { if (!path.isEmpty()) {
showMenu = true; showMenu = true;
QAction* open = contextMenu->addAction(Shared::icon("document-preview"), tr("Open")); QAction* open = contextMenu->addAction(Shared::icon("document-preview"), tr("Open"));
connect(open, &QAction::triggered, [path]() { 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 //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) { if (item->getOutgoing() && !hasAttach && index.row() < 100 && item->getTime().daysTo(QDateTime::currentDateTimeUtc()) < 20) {
showMenu = true; showMenu = true;

View File

@ -141,7 +141,15 @@ void FeedView::updateGeometries() {
const QStyle* st = style(); const QStyle* st = style();
QSize layoutBounds = maximumViewportSize(); 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.setHeight(maxMessageHeight);
option.rect.setWidth(layoutBounds.width()); option.rect.setWidth(layoutBounds.width());
int frameAroundContents = 0; int frameAroundContents = 0;
@ -182,7 +190,11 @@ void FeedView::updateGeometries() {
previousOffset += elementMargin; previousOffset += elementMargin;
} }
lastDate = currentDate; 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); QSize messageSize = itemDelegate(index)->sizeHint(option, index);
#endif
uint32_t offsetX(0); uint32_t offsetX(0);
if (specialDelegate) { if (specialDelegate) {
if (index.data(Models::MessageFeed::SentByMe).toBool()) if (index.data(Models::MessageFeed::SentByMe).toBool())
@ -232,7 +244,11 @@ bool FeedView::tryToCalculateGeometriesWithNoScrollbars(const QStyleOptionViewIt
previousOffset += elementMargin; previousOffset += elementMargin;
} }
lastDate = currentDate; lastDate = currentDate;
QSize messageSize = itemDelegate(index)->sizeHint(option, index); #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
if (previousOffset + messageSize.height() + elementMargin > totalHeight) if (previousOffset + messageSize.height() + elementMargin > totalHeight)
return false; return false;
@ -288,8 +304,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); QPainter painter(vp);
QStyleOptionViewItem option = viewOptions();
option.features = QStyleOptionViewItem::WrapText; option.features = QStyleOptionViewItem::WrapText;
QPoint cursor = vp->mapFromGlobal(QCursor::pos()); QPoint cursor = vp->mapFromGlobal(QCursor::pos());
@ -319,7 +341,12 @@ void FeedView::paintEvent(QPaintEvent* event) {
stripe.setWidth(viewportRect.width()); stripe.setWidth(viewportRect.width());
bool mouseOver = stripe.contains(cursor) && viewportRect.contains(cursor); bool mouseOver = stripe.contains(cursor) && viewportRect.contains(cursor);
option.state.setFlag(QStyle::State_MouseOver, mouseOver); option.state.setFlag(QStyle::State_MouseOver, mouseOver);
itemDelegate(index)->paint(&painter, option, index);
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
itemDelegateForIndex(index)->paint(&painter, option, index);
#else
itemDelegate(index)->paint(&painter, option, index);
#endif
if (!lastDate.isNull() && currentDate.daysTo(lastDate) > 0) if (!lastDate.isNull() && currentDate.daysTo(lastDate) > 0)
drawDateDevider(option.rect.bottom(), lastDate, painter); drawDateDevider(option.rect.bottom(), lastDate, painter);
@ -379,8 +406,12 @@ void FeedView::setAnchorHovered(Shared::Hover type) {
void FeedView::mouseMoveEvent(QMouseEvent* event) { void FeedView::mouseMoveEvent(QMouseEvent* event) {
if (!isVisible()) if (!isVisible())
return; 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) { if (mousePressed) {
QPoint distance = dragStartPoint - dragEndPoint; QPoint distance = dragStartPoint - dragEndPoint;
if (distance.manhattanLength() > 5) if (distance.manhattanLength() > 5)
@ -423,7 +454,11 @@ void FeedView::mousePressEvent(QMouseEvent* event) {
mousePressed = event->button() == Qt::LeftButton; mousePressed = event->button() == Qt::LeftButton;
if (mousePressed) { if (mousePressed) {
dragStartPoint = event->localPos().toPoint(); #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
dragStartPoint = event->position().toPoint();
#else
dragStartPoint = event->localPos().toPoint();
#endif
if (specialDelegate && specialModel) { if (specialDelegate && specialModel) {
MessageDelegate* del = static_cast<MessageDelegate*>(itemDelegate()); MessageDelegate* del = static_cast<MessageDelegate*>(itemDelegate());
QString lastSelectedId = del->clearSelection(); QString lastSelectedId = del->clearSelection();
@ -441,7 +476,11 @@ void FeedView::mouseDoubleClickEvent(QMouseEvent* event) {
QAbstractItemView::mouseDoubleClickEvent(event); QAbstractItemView::mouseDoubleClickEvent(event);
mousePressed = event->button() == Qt::LeftButton; mousePressed = event->button() == Qt::LeftButton;
if (mousePressed) { if (mousePressed) {
dragStartPoint = event->localPos().toPoint(); #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
dragStartPoint = event->position().toPoint();
#else
dragStartPoint = event->localPos().toPoint();
#endif
if (specialDelegate && specialModel) { if (specialDelegate && specialModel) {
MessageDelegate* del = static_cast<MessageDelegate*>(itemDelegate()); MessageDelegate* del = static_cast<MessageDelegate*>(itemDelegate());
QString lastSelectedId = del->clearSelection(); QString lastSelectedId = del->clearSelection();
@ -469,7 +508,11 @@ void FeedView::mouseReleaseEvent(QMouseEvent* event) {
if (mousePressed) { if (mousePressed) {
if (!dragging && specialDelegate) { if (!dragging && specialDelegate) {
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
QPoint point = event->position().toPoint();
#else
QPoint point = event->localPos().toPoint(); QPoint point = event->localPos().toPoint();
#endif
QModelIndex index = indexAt(point); QModelIndex index = indexAt(point);
if (index.isValid()) { if (index.isValid()) {
QRect rect = visualRect(index); QRect rect = visualRect(index);

View File

@ -16,8 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef FEEDVIEW_H #pragma once
#define FEEDVIEW_H
#include <QAbstractItemView> #include <QAbstractItemView>
#include <QDesktopServices> #include <QDesktopServices>
@ -30,11 +29,7 @@
#include <ui/utils/progress.h> #include <ui/utils/progress.h>
#include <shared/utils.h> #include <shared/utils.h>
/** class FeedView : public QAbstractItemView {
* @todo write docs
*/
class FeedView : public QAbstractItemView
{
Q_OBJECT Q_OBJECT
public: public:
FeedView(QWidget* parent = nullptr); FeedView(QWidget* parent = nullptr);
@ -111,5 +106,3 @@ private:
static const std::set<int> geometryChangingRoles; static const std::set<int> geometryChangingRoles;
}; };
#endif //FEEDVIEW_H

View File

@ -659,7 +659,7 @@ QLabel * MessageDelegate::getStatusIcon(const Models::FeedItem& data) const {
QIcon q(Shared::icon(Shared::messageStateThemeIcons[static_cast<uint8_t>(data.state)])); QIcon q(Shared::icon(Shared::messageStateThemeIcons[static_cast<uint8_t>(data.state)]));
QString tt = Shared::Global::getName(data.state); QString tt = Shared::Global::getName(data.state);
if (data.state == Shared::Message::State::error) { if (data.state == Shared::Message::State::error) {
if (data.error > 0) if (data.error.size() > 0)
tt += ": " + data.error; tt += ": " + data.error;
} }
if (result->toolTip() != tt) { //If i just assign pixmap every time unconditionally if (result->toolTip() != tt) { //If i just assign pixmap every time unconditionally

View File

@ -21,36 +21,39 @@
SettingsList::SettingsList(QWidget* parent): SettingsList::SettingsList(QWidget* parent):
QListWidget(parent), QListWidget(parent),
lastWidth(0) 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
SettingsList::~SettingsList() QStyleOptionViewItem SettingsList::viewOptions() const {
{
}
QStyleOptionViewItem SettingsList::viewOptions() const
{
QStyleOptionViewItem option = QListWidget::viewOptions(); QStyleOptionViewItem option = QListWidget::viewOptions();
if (!iconSize().isValid()) { if (!iconSize().isValid())
option.decorationSize.setWidth(lastWidth); option.decorationSize.setWidth(lastWidth);
}
option.rect.setWidth(lastWidth); option.rect.setWidth(lastWidth);
return option; return option;
} }
#endif
void SettingsList::resizeEvent(QResizeEvent* event) void SettingsList::resizeEvent(QResizeEvent* event) {
{
lastWidth = event->size().width(); lastWidth = event->size().width();
QListWidget::resizeEvent(event); QListWidget::resizeEvent(event);
} }
QRect SettingsList::visualRect(const QModelIndex& index) const QRect SettingsList::visualRect(const QModelIndex& index) const {
{
QRect res = QListWidget::visualRect(index); QRect res = QListWidget::visualRect(index);
if (index.isValid()) { if (index.isValid())
res.setWidth(lastWidth); res.setWidth(lastWidth);
}
return res; return res;
} }

View File

@ -16,29 +16,28 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef UI_SETTINGSLIST_H #pragma once
#define UI_SETTINGSLIST_H
#include <QListWidget> #include <QListWidget>
#include <QResizeEvent> #include <QResizeEvent>
#include <QStyleOptionViewItem>
/** class SettingsList : public QListWidget {
* @todo write docs
*/
class SettingsList : public QListWidget
{
Q_OBJECT Q_OBJECT
public: public:
SettingsList(QWidget* parent = nullptr); SettingsList(QWidget* parent = nullptr);
~SettingsList(); ~SettingsList();
protected: protected:
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
void initViewItemOption(QStyleOptionViewItem* option) const override;
#else
QStyleOptionViewItem viewOptions() const override; QStyleOptionViewItem viewOptions() const override;
#endif
void resizeEvent(QResizeEvent * event) override; void resizeEvent(QResizeEvent * event) override;
QRect visualRect(const QModelIndex & index) const override; QRect visualRect(const QModelIndex & index) const override;
private: private:
int lastWidth; int lastWidth;
}; };
#endif // UI_SETTINGSLIST_H