Compare commits
58 Commits
master
...
encryption
Author | SHA1 | Date | |
---|---|---|---|
829777935f | |||
0be2648849 | |||
93c5be412e | |||
8f5325b291 | |||
75554c7451 | |||
00af582287 | |||
19835af3cf | |||
e31ef78e71 | |||
be466fbad1 | |||
0a530bfa93 | |||
637eb702a8 | |||
a7d1a28f29 | |||
297e08ba41 | |||
9d688e8596 | |||
23ec80ccba | |||
5fbb03fc46 | |||
81cf0f8d34 | |||
69d797fe51 | |||
4f295fee3c | |||
fffef9876a | |||
283e9ebc4d | |||
21b40a9ccb | |||
76a9c5da0c | |||
8ec0af3205 | |||
4b68da458f | |||
927bdf0dab | |||
5ba97ecc25 | |||
9fff409630 | |||
99fd001292 | |||
2d8f32c257 | |||
77dd28b600 | |||
6f32e99593 | |||
ec362cef55 | |||
e4a2728ef8 | |||
bf11d8a74e | |||
edf1ee60cd | |||
4af16b75bf | |||
bb304ce774 | |||
3c6b611a41 | |||
73d83f55af | |||
b72a837754 | |||
d4bf7e599a | |||
15fb4bbd62 | |||
2aed8a1209 | |||
78ef3664f7 | |||
5aa0f4bca9 | |||
b45a73b723 | |||
758a9d95f3 | |||
dfe72ca36c | |||
db3bc358a7 | |||
0b61b6e928 | |||
820dc845ea | |||
87973b3b67 | |||
b6ba022bff | |||
7b2b7ee5d5 | |||
c50cd1140e | |||
037dabbe06 | |||
2ae75a4b91 |
6
.gitmodules
vendored
@ -1,3 +1,9 @@
|
|||||||
[submodule "external/qxmpp"]
|
[submodule "external/qxmpp"]
|
||||||
path = external/qxmpp
|
path = external/qxmpp
|
||||||
url = https://github.com/qxmpp-project/qxmpp.git
|
url = https://github.com/qxmpp-project/qxmpp.git
|
||||||
|
[submodule "external/storage"]
|
||||||
|
path = external/storage
|
||||||
|
url = https://git.macaw.me/blue/storage
|
||||||
|
[submodule "external/lmdbal"]
|
||||||
|
path = external/lmdbal
|
||||||
|
url = gitea@git.macaw.me:blue/lmdbal.git
|
||||||
|
3640
.uncrustify.cfg
Normal file
@ -9,9 +9,13 @@
|
|||||||
- deactivated accounts now don't appear in combobox of "Add contact" and "Join conference" dialogues
|
- deactivated accounts now don't appear in combobox of "Add contact" and "Join conference" dialogues
|
||||||
- all of the expandable roster items now get saved between launches
|
- all of the expandable roster items now get saved between launches
|
||||||
- settings file on the disk is not rewritten every roster element expansion or collapse
|
- settings file on the disk is not rewritten every roster element expansion or collapse
|
||||||
|
- removed unnecessary own vcard request at sturtup (used to do it to discover my own avatar)
|
||||||
|
- vcard window now is Info system and it can display more information
|
||||||
|
|
||||||
### New features
|
### New features
|
||||||
- Now you can enable tray icon from settings!
|
- now you can enable tray icon from settings!
|
||||||
|
- there is a job queue now, this allowes to spread a bit the spam on the server at connection time
|
||||||
|
- squawk now querries clients of it's peers, you can see what programs other people use
|
||||||
|
|
||||||
## Squawk 0.2.2 (May 05, 2022)
|
## Squawk 0.2.2 (May 05, 2022)
|
||||||
### Bug fixes
|
### Bug fixes
|
||||||
|
137
CMakeLists.txt
@ -1,10 +1,12 @@
|
|||||||
cmake_minimum_required(VERSION 3.4)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
project(squawk VERSION 0.2.3 LANGUAGES CXX)
|
project(squawk VERSION 0.2.3 LANGUAGES CXX)
|
||||||
|
|
||||||
cmake_policy(SET CMP0076 NEW)
|
cmake_policy(SET CMP0076 NEW)
|
||||||
|
cmake_policy(SET CMP0077 NEW)
|
||||||
cmake_policy(SET CMP0079 NEW)
|
cmake_policy(SET CMP0079 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)
|
||||||
@ -27,42 +29,40 @@ add_executable(squawk ${WIN32_FLAG} ${MACOSX_BUNDLE_FLAG})
|
|||||||
target_include_directories(squawk PRIVATE ${CMAKE_SOURCE_DIR})
|
target_include_directories(squawk PRIVATE ${CMAKE_SOURCE_DIR})
|
||||||
|
|
||||||
option(SYSTEM_QXMPP "Use system qxmpp lib" ON)
|
option(SYSTEM_QXMPP "Use system qxmpp lib" ON)
|
||||||
|
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" ON)
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
## Qt
|
## Qt
|
||||||
set(QT_VERSION_MAJOR 5)
|
if (NOT DEFINED QT_VERSION_MAJOR)
|
||||||
find_package(Qt5 COMPONENTS Widgets DBus Gui Xml Network Core REQUIRED)
|
find_package(QT NAMES Qt6 Qt5 CONFIG REQUIRED COMPONENTS Widgets DBus Gui Xml Network Core)
|
||||||
|
else ()
|
||||||
|
find_package(Qt${QT_VERSION_MAJOR} CONFIG REQUIRED COMPONENTS Widgets DBus Gui Xml Network Core)
|
||||||
|
endif()
|
||||||
|
|
||||||
find_package(Boost COMPONENTS)
|
find_package(Boost COMPONENTS)
|
||||||
|
|
||||||
target_include_directories(squawk PRIVATE ${Boost_INCLUDE_DIRS})
|
target_include_directories(squawk PRIVATE ${Boost_INCLUDE_DIRS})
|
||||||
target_include_directories(squawk PRIVATE ${Qt5_INCLUDE_DIRS})
|
|
||||||
target_include_directories(squawk PRIVATE ${Qt5Widgets_INCLUDE_DIRS})
|
|
||||||
target_include_directories(squawk PRIVATE ${Qt5DBus_INCLUDE_DIRS})
|
|
||||||
target_include_directories(squawk PRIVATE ${Qt5Gui_INCLUDE_DIRS})
|
|
||||||
target_include_directories(squawk PRIVATE ${Qt5Xml_INCLUDE_DIRS})
|
|
||||||
target_include_directories(squawk PRIVATE ${Qt5Network_INCLUDE_DIRS})
|
|
||||||
target_include_directories(squawk PRIVATE ${Qt5Core_INCLUDE_DIRS})
|
|
||||||
|
|
||||||
## QXmpp
|
## OMEMO
|
||||||
if (SYSTEM_QXMPP)
|
if (WITH_OMEMO)
|
||||||
find_package(QXmpp CONFIG)
|
find_package(PkgConfig)
|
||||||
|
if (PKG_CONFIG_FOUND)
|
||||||
if (NOT QXmpp_FOUND)
|
pkg_check_modules(OMEMO libomemo-c)
|
||||||
set(SYSTEM_QXMPP OFF)
|
if (OMEMO_FOUND)
|
||||||
message("QXmpp package wasn't found, trying to build with bundled QXmpp")
|
target_compile_definitions(squawk PRIVATE WITH_OMEMO)
|
||||||
|
message("Building with support of OMEMO")
|
||||||
else ()
|
else ()
|
||||||
message("Building with system QXmpp")
|
message("libomemo-c package wasn't found, trying to build without OMEMO support")
|
||||||
|
set(WITH_OMEMO OFF)
|
||||||
|
endif ()
|
||||||
|
else ()
|
||||||
|
message("PKG_CONFIG module wasn't found, can not check libomemo-c support, trying to build without OMEMO support")
|
||||||
|
set(WITH_OMEMO OFF)
|
||||||
endif ()
|
endif ()
|
||||||
endif ()
|
|
||||||
|
|
||||||
if (NOT SYSTEM_QXMPP)
|
|
||||||
target_link_libraries(squawk PRIVATE qxmpp)
|
|
||||||
add_subdirectory(external/qxmpp)
|
|
||||||
else ()
|
|
||||||
target_link_libraries(squawk PRIVATE QXmpp::QXmpp)
|
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
## KIO
|
## KIO
|
||||||
@ -91,6 +91,7 @@ if (WITH_KWALLET)
|
|||||||
endif ()
|
endif ()
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
## KConfig
|
||||||
if (WITH_KCONFIG)
|
if (WITH_KCONFIG)
|
||||||
find_package(KF5Config CONFIG)
|
find_package(KF5Config CONFIG)
|
||||||
if (NOT KF5Config_FOUND)
|
if (NOT KF5Config_FOUND)
|
||||||
@ -109,24 +110,86 @@ if (WITH_KCONFIG)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
## Signal (TODO)
|
## QXmpp
|
||||||
# find_package(Signal REQUIRED)
|
if (SYSTEM_QXMPP)
|
||||||
|
if (WITH_OMEMO)
|
||||||
|
find_package(QXmpp CONFIG COMPONENTS Omemo)
|
||||||
|
else ()
|
||||||
|
find_package(QXmpp CONFIG)
|
||||||
|
endif ()
|
||||||
|
|
||||||
## LMDB
|
if (NOT QXmpp_FOUND)
|
||||||
find_package(LMDB REQUIRED)
|
set(SYSTEM_QXMPP OFF)
|
||||||
|
message("QXmpp package wasn't found, trying to build with bundled QXmpp")
|
||||||
|
else ()
|
||||||
|
message("Building with system QXmpp")
|
||||||
|
endif ()
|
||||||
|
endif () #it's endif() + if() and not else() because I want it to have a fallback behaviour
|
||||||
|
if (NOT SYSTEM_QXMPP) #we can fail finding system QXmpp and this way we'll check bundled before failing completely
|
||||||
|
message("Building with bundled QXmpp")
|
||||||
|
|
||||||
# Linking
|
target_include_directories(squawk PRIVATE ${CMAKE_SOURCE_DIR}/external/qxmpp/src/base)
|
||||||
target_link_libraries(squawk PRIVATE Qt5::Core Qt5::Widgets Qt5::DBus Qt5::Network Qt5::Gui Qt5::Xml)
|
target_include_directories(squawk PRIVATE ${CMAKE_SOURCE_DIR}/external/qxmpp/src/client)
|
||||||
target_link_libraries(squawk PRIVATE lmdb)
|
target_include_directories(squawk PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/external/qxmpp/src)
|
||||||
target_link_libraries(squawk PRIVATE simpleCrypt)
|
|
||||||
# Link thread libraries on Linux
|
if (WITH_OMEMO)
|
||||||
|
target_include_directories(squawk PRIVATE ${CMAKE_SOURCE_DIR}/external/qxmpp/src/omemo)
|
||||||
|
target_include_directories(squawk PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/external/qxmpp/src/omemo)
|
||||||
|
set(BUILD_OMEMO ON)
|
||||||
|
set(BUILD_TESTS OFF)
|
||||||
|
else ()
|
||||||
|
set(BUILD_OMEMO OFF)
|
||||||
|
endif ()
|
||||||
|
add_subdirectory(external/qxmpp)
|
||||||
|
add_library(QXmpp::QXmpp ALIAS QXmppQt${QT_VERSION_MAJOR})
|
||||||
|
if (WITH_OMEMO)
|
||||||
|
target_include_directories(QXmppOmemoQt${QT_VERSION_MAJOR} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/external/qxmpp/src)
|
||||||
|
add_library(QXmpp::Omemo ALIAS QXmppOmemoQt${QT_VERSION_MAJOR})
|
||||||
|
endif ()
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
## LMDBAL
|
||||||
|
if (SYSTEM_LMDBAL)
|
||||||
|
find_package(lmdbal)
|
||||||
|
if (NOT lmdbal_FOUND)
|
||||||
|
set(SYSTEM_LMDBAL OFF)
|
||||||
|
message("LMDBAL package wasn't found, trying to build with bundled LMDBAL")
|
||||||
|
else ()
|
||||||
|
message("Building with system LMDBAL")
|
||||||
|
endif ()
|
||||||
|
else()
|
||||||
|
message("Building with bundled LMDBAL")
|
||||||
|
set(BUILD_STATIC ON)
|
||||||
|
add_subdirectory(external/lmdbal)
|
||||||
|
add_library(LMDBAL::LMDBAL ALIAS LMDBAL)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
## Linking
|
||||||
|
target_link_libraries(squawk
|
||||||
|
PRIVATE
|
||||||
|
Qt${QT_VERSION_MAJOR}::Core
|
||||||
|
Qt${QT_VERSION_MAJOR}::Widgets
|
||||||
|
Qt${QT_VERSION_MAJOR}::DBus
|
||||||
|
Qt${QT_VERSION_MAJOR}::Network
|
||||||
|
Qt${QT_VERSION_MAJOR}::Gui
|
||||||
|
Qt${QT_VERSION_MAJOR}::Xml
|
||||||
|
LMDBAL::LMDBAL
|
||||||
|
QXmpp::QXmpp
|
||||||
|
simpleCrypt
|
||||||
|
)
|
||||||
|
|
||||||
|
if (WITH_OMEMO)
|
||||||
|
target_link_libraries(squawk PRIVATE QXmpp::Omemo)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
## Link thread libraries on Linux
|
||||||
if(UNIX AND NOT APPLE)
|
if(UNIX AND NOT APPLE)
|
||||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
target_link_libraries(squawk PRIVATE Threads::Threads)
|
target_link_libraries(squawk PRIVATE Threads::Threads)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Build type
|
## Build type
|
||||||
if (NOT CMAKE_BUILD_TYPE)
|
if (NOT CMAKE_BUILD_TYPE)
|
||||||
set(CMAKE_BUILD_TYPE Debug)
|
set(CMAKE_BUILD_TYPE Debug)
|
||||||
endif ()
|
endif ()
|
||||||
@ -158,7 +221,7 @@ add_subdirectory(shared)
|
|||||||
add_subdirectory(translations)
|
add_subdirectory(translations)
|
||||||
add_subdirectory(ui)
|
add_subdirectory(ui)
|
||||||
|
|
||||||
# Install the executable
|
## Install the executable
|
||||||
install(TARGETS squawk DESTINATION ${CMAKE_INSTALL_BINDIR})
|
install(TARGETS squawk DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||||
install(FILES README.md DESTINATION ${CMAKE_INSTALL_DATADIR}/macaw.me/squawk)
|
install(FILES README.md DESTINATION ${CMAKE_INSTALL_DATADIR}/macaw.me/squawk)
|
||||||
install(FILES LICENSE.md DESTINATION ${CMAKE_INSTALL_DATADIR}/macaw.me/squawk)
|
install(FILES LICENSE.md DESTINATION ${CMAKE_INSTALL_DATADIR}/macaw.me/squawk)
|
||||||
@ -166,7 +229,7 @@ install(FILES LICENSE.md DESTINATION ${CMAKE_INSTALL_DATADIR}/macaw.me/squawk)
|
|||||||
if (CMAKE_BUILD_TYPE STREQUAL "Release")
|
if (CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
add_custom_command(TARGET squawk POST_BUILD COMMENT "Running macdeployqt..."
|
add_custom_command(TARGET squawk POST_BUILD COMMENT "Running macdeployqt..."
|
||||||
COMMAND "${Qt5Widgets_DIR}/../../../bin/macdeployqt" "${CMAKE_CURRENT_BINARY_DIR}/squawk.app"
|
COMMAND "${Qt${QT_VERSION_MAJOR}Widgets_DIR}/../../../bin/macdeployqt" "${CMAKE_CURRENT_BINARY_DIR}/squawk.app"
|
||||||
)
|
)
|
||||||
endif(APPLE)
|
endif(APPLE)
|
||||||
endif()
|
endif()
|
||||||
|
@ -9,9 +9,9 @@
|
|||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
- QT 5.12 *(lower versions might work but it wasn't tested)*
|
- QT 5.12 *(lower versions might work but it wasn't tested)*
|
||||||
- lmdb
|
|
||||||
- CMake 3.4 or higher
|
- CMake 3.4 or higher
|
||||||
- qxmpp 1.1.0 or higher
|
- qxmpp 1.1.0 or higher
|
||||||
|
- LMDBAL (my own [library](https://git.macaw.me/blue/lmdbal) around lmdb)
|
||||||
- KDE Frameworks: kwallet (optional)
|
- KDE Frameworks: kwallet (optional)
|
||||||
- KDE Frameworks: KIO (optional)
|
- KDE Frameworks: KIO (optional)
|
||||||
- KDE Frameworks: KConfig (optional)
|
- KDE Frameworks: KConfig (optional)
|
||||||
@ -92,9 +92,11 @@ You can always refer to `appveyor.yml` to see how AppVeyor build squawk.
|
|||||||
Here is the list of keys you can pass to configuration phase of `cmake ..`.
|
Here is the list of keys you can pass to configuration phase of `cmake ..`.
|
||||||
- `CMAKE_BUILD_TYPE` - `Debug` just builds showing all warnings, `Release` builds with no warnings and applies optimizations (default is `Debug`)
|
- `CMAKE_BUILD_TYPE` - `Debug` just builds showing all warnings, `Release` builds with no warnings and applies optimizations (default is `Debug`)
|
||||||
- `SYSTEM_QXMPP` - `True` tries to link against `qxmpp` installed in the system, `False` builds bundled `qxmpp` library (default is `True`)
|
- `SYSTEM_QXMPP` - `True` tries to link against `qxmpp` installed in the system, `False` builds bundled `qxmpp` library (default is `True`)
|
||||||
|
- `SYSTEM_LMDBAL` - `True` tries to link against `LMDABL` installed in the system, `False` builds bundled `LMDBAL` library (default is `True`)
|
||||||
- `WITH_KWALLET` - `True` builds the `KWallet` capability module if `KWallet` is installed and if not goes to `False`. `False` disables `KWallet` support (default is `True`)
|
- `WITH_KWALLET` - `True` builds the `KWallet` capability module if `KWallet` is installed and if not goes to `False`. `False` disables `KWallet` support (default is `True`)
|
||||||
- `WITH_KIO` - `True` builds the `KIO` capability module if `KIO` is installed and if not goes to `False`. `False` disables `KIO` support (default is `True`)
|
- `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 `True`)
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
#This file is taken from here https://gitlab.ralph.or.at/causal-rt/causal-cpp/, it was GPLv3 license
|
|
||||||
#Thank you so much, mr. Ralph Alexander Bariz, I hope you don't mind me using your code
|
|
||||||
|
|
||||||
# Try to find LMDB headers and library.
|
|
||||||
#
|
|
||||||
# Usage of this module as follows:
|
|
||||||
#
|
|
||||||
# find_package(LMDB)
|
|
||||||
#
|
|
||||||
# Variables used by this module, they can change the default behaviour and need
|
|
||||||
# to be set before calling find_package:
|
|
||||||
#
|
|
||||||
# LMDB_ROOT_DIR Set this variable to the root installation of
|
|
||||||
# LMDB if the module has problems finding the
|
|
||||||
# proper installation path.
|
|
||||||
#
|
|
||||||
# Variables defined by this module:
|
|
||||||
#
|
|
||||||
# LMDB_FOUND System has LMDB library/headers.
|
|
||||||
# LMDB_LIBRARIES The LMDB library.
|
|
||||||
# LMDB_INCLUDE_DIRS The location of LMDB headers.
|
|
||||||
|
|
||||||
find_path(LMDB_ROOT_DIR
|
|
||||||
NAMES include/lmdb.h
|
|
||||||
)
|
|
||||||
|
|
||||||
find_library(LMDB_LIBRARIES
|
|
||||||
NAMES liblmdb.a liblmdb.so liblmdb.so.a liblmdb.dll.a # We want lmdb to be static, if possible
|
|
||||||
HINTS ${LMDB_ROOT_DIR}/lib
|
|
||||||
)
|
|
||||||
|
|
||||||
add_library(lmdb UNKNOWN IMPORTED)
|
|
||||||
set_target_properties(lmdb PROPERTIES
|
|
||||||
IMPORTED_LOCATION ${LMDB_LIBRARIES}
|
|
||||||
)
|
|
||||||
|
|
||||||
find_path(LMDB_INCLUDE_DIRS
|
|
||||||
NAMES lmdb.h
|
|
||||||
HINTS ${LMDB_ROOT_DIR}/include
|
|
||||||
)
|
|
||||||
|
|
||||||
include(FindPackageHandleStandardArgs)
|
|
||||||
find_package_handle_standard_args(LMDB DEFAULT_MSG
|
|
||||||
LMDB_LIBRARIES
|
|
||||||
LMDB_INCLUDE_DIRS
|
|
||||||
)
|
|
||||||
|
|
||||||
mark_as_advanced(
|
|
||||||
LMDB_ROOT_DIR
|
|
||||||
LMDB_LIBRARIES
|
|
||||||
LMDB_INCLUDE_DIRS
|
|
||||||
)
|
|
@ -1,15 +0,0 @@
|
|||||||
find_path(Signal_INCLUDE_DIR NAMES signal/signal_protocol.h)
|
|
||||||
find_library(Signal_LIBRARY signal-protocol-c)
|
|
||||||
mark_as_advanced(Signal_INCLUDE_DIR Signal_LIBRARY)
|
|
||||||
|
|
||||||
include(FindPackageHandleStandardArgs)
|
|
||||||
find_package_handle_standard_args(Signal REQUIRED_VARS Signal_LIBRARY Signal_INCLUDE_DIR)
|
|
||||||
|
|
||||||
if (Signal_FOUND AND NOT TARGET Signal::Signal)
|
|
||||||
add_library(Signal::Signal UNKNOWN IMPORTED)
|
|
||||||
set_target_properties(Signal::Signal PROPERTIES
|
|
||||||
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
|
|
||||||
IMPORTED_LOCATION "${Signal_LIBRARY}"
|
|
||||||
INTERFACE_INCLUDE_DIRECTORIES "${Signal_INCLUDE_DIR}"
|
|
||||||
)
|
|
||||||
endif ()
|
|
@ -3,27 +3,34 @@ if(WIN32)
|
|||||||
set(SIGNALCATCHER_SOURCE signalcatcher_win32.cpp)
|
set(SIGNALCATCHER_SOURCE signalcatcher_win32.cpp)
|
||||||
endif(WIN32)
|
endif(WIN32)
|
||||||
|
|
||||||
target_sources(squawk PRIVATE
|
set(SOURCE_FILES
|
||||||
account.cpp
|
account.cpp
|
||||||
account.h
|
|
||||||
adapterfunctions.cpp
|
adapterfunctions.cpp
|
||||||
adapterfunctions.h
|
|
||||||
conference.cpp
|
conference.cpp
|
||||||
conference.h
|
|
||||||
contact.cpp
|
contact.cpp
|
||||||
contact.h
|
|
||||||
networkaccess.cpp
|
|
||||||
networkaccess.h
|
|
||||||
rosteritem.cpp
|
rosteritem.cpp
|
||||||
rosteritem.h
|
|
||||||
${SIGNALCATCHER_SOURCE}
|
${SIGNALCATCHER_SOURCE}
|
||||||
signalcatcher.h
|
|
||||||
squawk.cpp
|
squawk.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(HEADER_FILES
|
||||||
|
account.h
|
||||||
|
adapterfunctions.h
|
||||||
|
conference.h
|
||||||
|
contact.h
|
||||||
|
rosteritem.h
|
||||||
|
signalcatcher.h
|
||||||
squawk.h
|
squawk.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
target_sources(squawk PRIVATE
|
||||||
|
${SOURCE_FILES}
|
||||||
|
${HEADER_FILES}
|
||||||
|
)
|
||||||
|
|
||||||
target_include_directories(squawk PRIVATE ${LMDB_INCLUDE_DIRS})
|
target_include_directories(squawk PRIVATE ${LMDB_INCLUDE_DIRS})
|
||||||
|
|
||||||
add_subdirectory(handlers)
|
add_subdirectory(handlers)
|
||||||
add_subdirectory(storage)
|
|
||||||
add_subdirectory(passwordStorageEngines)
|
add_subdirectory(passwordStorageEngines)
|
||||||
|
add_subdirectory(components)
|
||||||
|
add_subdirectory(delayManager)
|
||||||
|
415
core/account.cpp
@ -18,11 +18,20 @@
|
|||||||
|
|
||||||
#include "account.h"
|
#include "account.h"
|
||||||
#include <QXmppMessage.h>
|
#include <QXmppMessage.h>
|
||||||
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
|
||||||
using namespace Core;
|
#include "shared/defines.h"
|
||||||
|
|
||||||
Account::Account(const QString& p_login, const QString& p_server, const QString& p_password, const QString& p_name, bool p_active, NetworkAccess* p_net, QObject* parent):
|
Core::Account::Account(
|
||||||
|
const QString& p_login,
|
||||||
|
const QString& p_server,
|
||||||
|
const QString& p_password,
|
||||||
|
const QString& p_name,
|
||||||
|
bool p_active,
|
||||||
|
NetworkAccess* p_net,
|
||||||
|
QObject* parent
|
||||||
|
):
|
||||||
QObject(parent),
|
QObject(parent),
|
||||||
name(p_name),
|
name(p_name),
|
||||||
archiveQueries(),
|
archiveQueries(),
|
||||||
@ -30,7 +39,25 @@ Account::Account(const QString& p_login, const QString& p_server, const QString&
|
|||||||
config(),
|
config(),
|
||||||
presence(),
|
presence(),
|
||||||
state(Shared::ConnectionState::disconnected),
|
state(Shared::ConnectionState::disconnected),
|
||||||
|
|
||||||
|
mh(new MessageHandler(this)),
|
||||||
|
rh(new RosterHandler(this)),
|
||||||
|
vh(new VCardHandler(this)),
|
||||||
|
dh(new DiscoveryHandler(this)),
|
||||||
|
#if (QXMPP_VERSION) >= QT_VERSION_CHECK(1, 5, 0)
|
||||||
|
th(new TrustHandler(this)),
|
||||||
|
#endif
|
||||||
|
#ifdef WITH_OMEMO
|
||||||
|
oh(new OmemoHandler(this)),
|
||||||
|
om(new QXmppOmemoManager(oh)),
|
||||||
|
#endif
|
||||||
|
#if (QXMPP_VERSION) >= QT_VERSION_CHECK(1, 5, 0)
|
||||||
|
tm(new QXmppTrustManager(th)),
|
||||||
|
cm(new QXmppCarbonManagerV2()),
|
||||||
|
psm(new QXmppPubSubManager()),
|
||||||
|
#else
|
||||||
cm(new QXmppCarbonManager()),
|
cm(new QXmppCarbonManager()),
|
||||||
|
#endif
|
||||||
am(new QXmppMamManager()),
|
am(new QXmppMamManager()),
|
||||||
mm(new QXmppMucManager()),
|
mm(new QXmppMucManager()),
|
||||||
bm(new QXmppBookmarkManager()),
|
bm(new QXmppBookmarkManager()),
|
||||||
@ -42,20 +69,29 @@ Account::Account(const QString& p_login, const QString& p_server, const QString&
|
|||||||
reconnectScheduled(false),
|
reconnectScheduled(false),
|
||||||
reconnectTimer(new QTimer),
|
reconnectTimer(new QTimer),
|
||||||
network(p_net),
|
network(p_net),
|
||||||
|
delay(nullptr),
|
||||||
passwordType(Shared::AccountPassword::plain),
|
passwordType(Shared::AccountPassword::plain),
|
||||||
lastError(Error::none),
|
lastError(Error::none),
|
||||||
pepSupport(false),
|
pepSupport(Shared::Support::unknown),
|
||||||
active(p_active),
|
active(p_active),
|
||||||
notReadyPassword(false),
|
notReadyPassword(false),
|
||||||
mh(new MessageHandler(this)),
|
loadingOmemo(false)
|
||||||
rh(new RosterHandler(this)),
|
|
||||||
vh(new VCardHandler(this))
|
|
||||||
{
|
{
|
||||||
config.setUser(p_login);
|
config.setUser(p_login);
|
||||||
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.setAutoReconnectionEnabled(false);
|
||||||
|
delay = new DelayManager::Manager(getBareJid());
|
||||||
|
QObject::connect(delay, &DelayManager::Manager::gotInfo, this, &Account::infoReady);
|
||||||
|
QObject::connect(delay, &DelayManager::Manager::gotOwnInfo, this, &Account::infoReady);
|
||||||
|
|
||||||
|
QObject::connect(delay, &DelayManager::Manager::requestOwnVCard, vm, &QXmppVCardManager::requestClientVCard);
|
||||||
|
QObject::connect(delay, &DelayManager::Manager::requestVCard, vm, &QXmppVCardManager::requestVCard);
|
||||||
|
|
||||||
|
rh->initialize();
|
||||||
|
vh->initialize();
|
||||||
|
dh->initialize();
|
||||||
|
|
||||||
QObject::connect(&client, &QXmppClient::stateChanged, this, &Account::onClientStateChange);
|
QObject::connect(&client, &QXmppClient::stateChanged, this, &Account::onClientStateChange);
|
||||||
QObject::connect(&client, &QXmppClient::presenceReceived, this, &Account::onPresenceReceived);
|
QObject::connect(&client, &QXmppClient::presenceReceived, this, &Account::onPresenceReceived);
|
||||||
@ -64,8 +100,10 @@ Account::Account(const QString& p_login, const QString& p_server, const QString&
|
|||||||
|
|
||||||
client.addExtension(cm);
|
client.addExtension(cm);
|
||||||
|
|
||||||
|
#if (QXMPP_VERSION) < QT_VERSION_CHECK(1, 5, 0)
|
||||||
QObject::connect(cm, &QXmppCarbonManager::messageReceived, mh, &MessageHandler::onCarbonMessageReceived);
|
QObject::connect(cm, &QXmppCarbonManager::messageReceived, mh, &MessageHandler::onCarbonMessageReceived);
|
||||||
QObject::connect(cm, &QXmppCarbonManager::messageSent, mh, &MessageHandler::onCarbonMessageSent);
|
QObject::connect(cm, &QXmppCarbonManager::messageSent, mh, &MessageHandler::onCarbonMessageSent);
|
||||||
|
#endif
|
||||||
|
|
||||||
client.addExtension(am);
|
client.addExtension(am);
|
||||||
|
|
||||||
@ -79,9 +117,6 @@ Account::Account(const QString& p_login, const QString& p_server, const QString&
|
|||||||
QObject::connect(um, &QXmppUploadRequestManager::slotReceived, mh, &MessageHandler::onUploadSlotReceived);
|
QObject::connect(um, &QXmppUploadRequestManager::slotReceived, mh, &MessageHandler::onUploadSlotReceived);
|
||||||
QObject::connect(um, &QXmppUploadRequestManager::requestFailed, mh, &MessageHandler::onUploadSlotRequestFailed);
|
QObject::connect(um, &QXmppUploadRequestManager::requestFailed, mh, &MessageHandler::onUploadSlotRequestFailed);
|
||||||
|
|
||||||
QObject::connect(dm, &QXmppDiscoveryManager::itemsReceived, this, &Account::onDiscoveryItemsReceived);
|
|
||||||
QObject::connect(dm, &QXmppDiscoveryManager::infoReceived, this, &Account::onDiscoveryInfoReceived);
|
|
||||||
|
|
||||||
QObject::connect(network, &NetworkAccess::uploadFileComplete, mh, &MessageHandler::onUploadFileComplete);
|
QObject::connect(network, &NetworkAccess::uploadFileComplete, mh, &MessageHandler::onUploadFileComplete);
|
||||||
QObject::connect(network, &NetworkAccess::downloadFileComplete, mh, &MessageHandler::onDownloadFileComplete);
|
QObject::connect(network, &NetworkAccess::downloadFileComplete, mh, &MessageHandler::onDownloadFileComplete);
|
||||||
QObject::connect(network, &NetworkAccess::loadFileError, mh, &MessageHandler::onLoadFileError);
|
QObject::connect(network, &NetworkAccess::loadFileError, mh, &MessageHandler::onLoadFileError);
|
||||||
@ -89,6 +124,34 @@ Account::Account(const QString& p_login, const QString& p_server, const QString&
|
|||||||
client.addExtension(rcpm);
|
client.addExtension(rcpm);
|
||||||
QObject::connect(rcpm, &QXmppMessageReceiptManager::messageDelivered, mh, &MessageHandler::onReceiptReceived);
|
QObject::connect(rcpm, &QXmppMessageReceiptManager::messageDelivered, mh, &MessageHandler::onReceiptReceived);
|
||||||
|
|
||||||
|
client.addExtension(psm);
|
||||||
|
|
||||||
|
#ifdef WITH_OMEMO
|
||||||
|
QObject::connect(delay, &DelayManager::Manager::requestBundles, oh, &OmemoHandler::requestBundles);
|
||||||
|
QObject::connect(delay, &DelayManager::Manager::requestOwnBundles, oh, &OmemoHandler::requestOwnBundles);
|
||||||
|
|
||||||
|
QObject::connect(om, &QXmppOmemoManager::deviceAdded, oh, &OmemoHandler::onOmemoDeviceAdded);
|
||||||
|
|
||||||
|
client.addExtension(tm);
|
||||||
|
client.addExtension(om);
|
||||||
|
om->setSecurityPolicy(QXmpp::Toakafa);
|
||||||
|
|
||||||
|
if (oh->hasOwnDevice()) {
|
||||||
|
QXmppTask<bool> future = om->load();
|
||||||
|
loadingOmemo = true;
|
||||||
|
future.then(this, [this] (bool result) {
|
||||||
|
loadingOmemo = false;
|
||||||
|
if (state == Shared::ConnectionState::scheduled)
|
||||||
|
client.connectToServer(config, presence);
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
qDebug() << "successfully loaded OMEMO data for account" << getName();
|
||||||
|
else
|
||||||
|
qDebug() << "couldn't load OMEMO data for account" << getName();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
reconnectTimer->setSingleShot(true);
|
reconnectTimer->setSingleShot(true);
|
||||||
QObject::connect(reconnectTimer, &QTimer::timeout, this, &Account::onReconnectTimer);
|
QObject::connect(reconnectTimer, &QTimer::timeout, this, &Account::onReconnectTimer);
|
||||||
|
|
||||||
@ -97,14 +160,14 @@ Account::Account(const QString& p_login, const QString& p_server, const QString&
|
|||||||
logger->setLoggingType(QXmppLogger::SignalLogging);
|
logger->setLoggingType(QXmppLogger::SignalLogging);
|
||||||
client.setLogger(logger);
|
client.setLogger(logger);
|
||||||
|
|
||||||
QObject::connect(logger, &QXmppLogger::message, this, [](QXmppLogger::MessageType type, const QString& text){
|
QObject::connect(logger, &QXmppLogger::message, this, [](QXmppLogger::MessageType type, const QString& text) {
|
||||||
|
SHARED_UNUSED(type);
|
||||||
qDebug() << text;
|
qDebug() << text;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Account::~Account()
|
Core::Account::~Account() {
|
||||||
{
|
|
||||||
if (reconnectScheduled) {
|
if (reconnectScheduled) {
|
||||||
reconnectScheduled = false;
|
reconnectScheduled = false;
|
||||||
reconnectTimer->stop();
|
reconnectTimer->stop();
|
||||||
@ -114,27 +177,40 @@ Account::~Account()
|
|||||||
QObject::disconnect(network, &NetworkAccess::downloadFileComplete, mh, &MessageHandler::onDownloadFileComplete);
|
QObject::disconnect(network, &NetworkAccess::downloadFileComplete, mh, &MessageHandler::onDownloadFileComplete);
|
||||||
QObject::disconnect(network, &NetworkAccess::loadFileError, mh, &MessageHandler::onLoadFileError);
|
QObject::disconnect(network, &NetworkAccess::loadFileError, mh, &MessageHandler::onLoadFileError);
|
||||||
|
|
||||||
delete vh;
|
rh->clear(); //conferenses inside of roster handler hold QXmppMuc objects.
|
||||||
delete mh;
|
//If we destroy QXmppMucManager, then when we will be destroying RosterHandler
|
||||||
delete rh;
|
//it will try to destory Core::Conference objects
|
||||||
|
//and inside of those QXmppMuc objects will already be destroyed.
|
||||||
|
//So, clear will start the destruction from Core::Conference and this way it's not gonna crash
|
||||||
|
|
||||||
|
delete delay;
|
||||||
delete reconnectTimer;
|
delete reconnectTimer;
|
||||||
delete rcpm;
|
delete rcpm;
|
||||||
delete dm;
|
|
||||||
delete um;
|
delete um;
|
||||||
delete bm;
|
delete bm;
|
||||||
delete mm;
|
delete mm;
|
||||||
delete am;
|
delete am;
|
||||||
delete cm;
|
delete cm;
|
||||||
|
#if (QXMPP_VERSION) >= QT_VERSION_CHECK(1, 5, 0)
|
||||||
|
delete psm;
|
||||||
|
#endif
|
||||||
|
#ifdef WITH_OMEMO
|
||||||
|
delete om;
|
||||||
|
delete tm;
|
||||||
|
delete oh;
|
||||||
|
delete th;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
delete dh;
|
||||||
|
delete vh;
|
||||||
|
delete rh;
|
||||||
|
delete mh;
|
||||||
}
|
}
|
||||||
|
|
||||||
Shared::ConnectionState Core::Account::getState() const
|
Shared::ConnectionState Core::Account::getState() const {
|
||||||
{
|
return state;}
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::Account::connect()
|
void Core::Account::connect() {
|
||||||
{
|
|
||||||
if (reconnectScheduled) {
|
if (reconnectScheduled) {
|
||||||
reconnectScheduled = false;
|
reconnectScheduled = false;
|
||||||
reconnectTimer->stop();
|
reconnectTimer->stop();
|
||||||
@ -142,37 +218,44 @@ void Core::Account::connect()
|
|||||||
if (state == Shared::ConnectionState::disconnected) {
|
if (state == Shared::ConnectionState::disconnected) {
|
||||||
if (notReadyPassword) {
|
if (notReadyPassword) {
|
||||||
emit needPassword();
|
emit needPassword();
|
||||||
|
} else {
|
||||||
|
if (loadingOmemo) {
|
||||||
|
state = Shared::ConnectionState::scheduled;
|
||||||
|
emit connectionStateChanged(state);
|
||||||
} else {
|
} else {
|
||||||
client.connectToServer(config, presence);
|
client.connectToServer(config, presence);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
qDebug("An attempt to connect an account which is already connected, skipping");
|
qDebug("An attempt to connect an account which is already connected, skipping");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Account::onReconnectTimer()
|
void Core::Account::onReconnectTimer() {
|
||||||
{
|
|
||||||
if (reconnectScheduled) {
|
if (reconnectScheduled) {
|
||||||
reconnectScheduled = false;
|
reconnectScheduled = false;
|
||||||
connect();
|
connect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Account::disconnect()
|
void Core::Account::disconnect() {
|
||||||
{
|
|
||||||
if (reconnectScheduled) {
|
if (reconnectScheduled) {
|
||||||
reconnectScheduled = false;
|
reconnectScheduled = false;
|
||||||
reconnectTimer->stop();
|
reconnectTimer->stop();
|
||||||
}
|
}
|
||||||
if (state != Shared::ConnectionState::disconnected) {
|
if (state != Shared::ConnectionState::disconnected) {
|
||||||
//rh->clearConferences();
|
//rh->clearConferences();
|
||||||
|
if (state != Shared::ConnectionState::scheduled) {
|
||||||
client.disconnectFromServer();
|
client.disconnectFromServer();
|
||||||
|
} else {
|
||||||
|
state = Shared::ConnectionState::disconnected;
|
||||||
|
emit connectionStateChanged(state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Account::onClientStateChange(QXmppClient::State st)
|
void Core::Account::onClientStateChange(QXmppClient::State st) {
|
||||||
{
|
|
||||||
switch (st) {
|
switch (st) {
|
||||||
case QXmppClient::ConnectedState: {
|
case QXmppClient::ConnectedState: {
|
||||||
if (state != Shared::ConnectionState::connected) {
|
if (state != Shared::ConnectionState::connected) {
|
||||||
@ -180,9 +263,27 @@ void Core::Account::onClientStateChange(QXmppClient::State st)
|
|||||||
Shared::ConnectionState os = state;
|
Shared::ConnectionState os = state;
|
||||||
state = Shared::ConnectionState::connected;
|
state = Shared::ConnectionState::connected;
|
||||||
if (os == Shared::ConnectionState::connecting) {
|
if (os == Shared::ConnectionState::connecting) {
|
||||||
qDebug() << "running service discovery for account" << name;
|
#ifdef WITH_OMEMO
|
||||||
dm->requestItems(getServer());
|
if (!oh->hasOwnDevice()) {
|
||||||
dm->requestInfo(getServer());
|
qDebug() << "setting up OMEMO data for account" << getName();
|
||||||
|
om->changeDeviceLabel(QGuiApplication::applicationDisplayName() + " - " + QSysInfo::productType());
|
||||||
|
QXmppTask<bool> future = om->setUp();
|
||||||
|
future.then(this, [this] (bool result) {
|
||||||
|
if (result)
|
||||||
|
qDebug() << "successfully set up OMEMO data for account" << getName();
|
||||||
|
else
|
||||||
|
qDebug() << "couldn't set up OMEMO data for account" << getName();
|
||||||
|
|
||||||
|
if (state == Shared::ConnectionState::connected)
|
||||||
|
runDiscoveryService();
|
||||||
|
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
runDiscoveryService();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
runDiscoveryService();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
lastError = Error::none;
|
lastError = Error::none;
|
||||||
emit connectionStateChanged(state);
|
emit connectionStateChanged(state);
|
||||||
@ -214,8 +315,7 @@ void Core::Account::onClientStateChange(QXmppClient::State st)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Account::reconnect()
|
void Core::Account::reconnect() {
|
||||||
{
|
|
||||||
if (!reconnectScheduled) { //TODO define behavior if It was connection or disconnecting
|
if (!reconnectScheduled) { //TODO define behavior if It was connection or disconnecting
|
||||||
if (state == Shared::ConnectionState::connected) {
|
if (state == Shared::ConnectionState::connected) {
|
||||||
reconnectScheduled = true;
|
reconnectScheduled = true;
|
||||||
@ -227,8 +327,7 @@ void Core::Account::reconnect()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Shared::Availability Core::Account::getAvailability() const
|
Shared::Availability Core::Account::getAvailability() const {
|
||||||
{
|
|
||||||
if (state == Shared::ConnectionState::connected) {
|
if (state == Shared::ConnectionState::connected) {
|
||||||
QXmppPresence::AvailableStatusType pres = presence.availableStatusType();
|
QXmppPresence::AvailableStatusType pres = presence.availableStatusType();
|
||||||
return static_cast<Shared::Availability>(pres); //they are compatible;
|
return static_cast<Shared::Availability>(pres); //they are compatible;
|
||||||
@ -237,36 +336,41 @@ Shared::Availability Core::Account::getAvailability() const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Account::setAvailability(Shared::Availability avail)
|
void Core::Account::setAvailability(Shared::Availability avail) {
|
||||||
{
|
|
||||||
if (avail == Shared::Availability::offline) {
|
if (avail == Shared::Availability::offline) {
|
||||||
disconnect(); //TODO not sure how to do here - changing state may cause connection or disconnection
|
disconnect(); //TODO not sure how to do here - changing state may cause connection or disconnection
|
||||||
} else {
|
} else {
|
||||||
QXmppPresence::AvailableStatusType pres = static_cast<QXmppPresence::AvailableStatusType>(avail);
|
QXmppPresence::AvailableStatusType pres = static_cast<QXmppPresence::AvailableStatusType>(avail);
|
||||||
|
|
||||||
presence.setAvailableStatusType(pres);
|
presence.setAvailableStatusType(pres);
|
||||||
if (state != Shared::ConnectionState::disconnected) {
|
if (state != Shared::ConnectionState::disconnected)
|
||||||
client.setClientPresence(presence);
|
client.setClientPresence(presence);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Account::onPresenceReceived(const QXmppPresence& p_presence)
|
void Core::Account::runDiscoveryService() {
|
||||||
{
|
qDebug() << "running service discovery for account" << name;
|
||||||
|
dm->requestItems(getServer());
|
||||||
|
dm->requestInfo(getServer());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::Account::onPresenceReceived(const QXmppPresence& p_presence) {
|
||||||
QString id = p_presence.from();
|
QString id = p_presence.from();
|
||||||
QStringList comps = id.split("/");
|
QStringList comps = id.split("/");
|
||||||
QString jid = comps.front().toLower();
|
QString jid = comps.front().toLower();
|
||||||
QString resource = comps.back();
|
QString resource = comps.back();
|
||||||
|
|
||||||
if (jid == getBareJid()) {
|
if (jid == getBareJid()) {
|
||||||
if (resource == getResource()) {
|
if (resource == getResource())
|
||||||
emit availabilityChanged(static_cast<Shared::Availability>(p_presence.availableStatusType()));
|
emit availabilityChanged(static_cast<Shared::Availability>(p_presence.availableStatusType()));
|
||||||
} else {
|
|
||||||
vh->handleOtherPresenceOfMyAccountChange(p_presence);
|
vh->handlePresenceOfMyAccountChange(p_presence);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
RosterItem* item = rh->getRosterItem(jid);
|
RosterItem* item = rh->getRosterItem(jid);
|
||||||
if (item != 0) {
|
if (item != nullptr) {
|
||||||
|
if (item->isMuc()) //MUC presence is handled by inner muc events
|
||||||
|
return;
|
||||||
|
else
|
||||||
item->handlePresence(p_presence);
|
item->handlePresence(p_presence);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -275,37 +379,46 @@ void Core::Account::onPresenceReceived(const QXmppPresence& p_presence)
|
|||||||
case QXmppPresence::Error:
|
case QXmppPresence::Error:
|
||||||
qDebug() << "An error reported by presence from" << id << p_presence.error().text();
|
qDebug() << "An error reported by presence from" << id << p_presence.error().text();
|
||||||
break;
|
break;
|
||||||
case QXmppPresence::Available:{
|
case QXmppPresence::Available: {
|
||||||
QDateTime lastInteraction = p_presence.lastUserInteraction();
|
QDateTime lastInteraction = p_presence.lastUserInteraction();
|
||||||
if (!lastInteraction.isValid()) {
|
if (!lastInteraction.isValid())
|
||||||
lastInteraction = QDateTime::currentDateTimeUtc();
|
lastInteraction = QDateTime::currentDateTimeUtc();
|
||||||
}
|
|
||||||
emit addPresence(jid, resource, {
|
emit addPresence(jid, resource, {
|
||||||
{"lastActivity", lastInteraction},
|
{"lastActivity", lastInteraction},
|
||||||
{"availability", p_presence.availableStatusType()}, //TODO check and handle invisible
|
{"availability", p_presence.availableStatusType()}, //TODO check and handle invisible
|
||||||
{"status", p_presence.statusText()}
|
{"status", p_presence.statusText()},
|
||||||
});
|
{"client", QVariant::fromValue(
|
||||||
|
Shared::ClientId(
|
||||||
|
p_presence.capabilityNode(),
|
||||||
|
p_presence.capabilityVer().toBase64(),
|
||||||
|
p_presence.capabilityHash())
|
||||||
|
)
|
||||||
}
|
}
|
||||||
break;
|
});
|
||||||
|
} break;
|
||||||
case QXmppPresence::Unavailable:
|
case QXmppPresence::Unavailable:
|
||||||
emit removePresence(jid, resource);
|
emit removePresence(jid, resource);
|
||||||
break;
|
break;
|
||||||
case QXmppPresence::Subscribe:
|
case QXmppPresence::Subscribe:
|
||||||
qDebug("xmpp presence \"subscribe\" received, do not yet know what to do, skipping");
|
qDebug("xmpp presence \"subscribe\" received, do not yet know what to do, skipping");
|
||||||
|
break;
|
||||||
case QXmppPresence::Subscribed:
|
case QXmppPresence::Subscribed:
|
||||||
qDebug("xmpp presence \"subscribed\" received, do not yet know what to do, skipping");
|
qDebug("xmpp presence \"subscribed\" received, do not yet know what to do, skipping");
|
||||||
|
break;
|
||||||
case QXmppPresence::Unsubscribe:
|
case QXmppPresence::Unsubscribe:
|
||||||
qDebug("xmpp presence \"unsubscribe\" received, do not yet know what to do, skipping");
|
qDebug("xmpp presence \"unsubscribe\" received, do not yet know what to do, skipping");
|
||||||
|
break;
|
||||||
case QXmppPresence::Unsubscribed:
|
case QXmppPresence::Unsubscribed:
|
||||||
qDebug("xmpp presence \"unsubscribed\" received, do not yet know what to do, skipping");
|
qDebug("xmpp presence \"unsubscribed\" received, do not yet know what to do, skipping");
|
||||||
|
break;
|
||||||
case QXmppPresence::Probe:
|
case QXmppPresence::Probe:
|
||||||
qDebug("xmpp presence \"probe\" received, do not yet know what to do, skipping");
|
qDebug("xmpp presence \"probe\" received, do not yet know what to do, skipping");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Account::onMamMessageReceived(const QString& queryId, const QXmppMessage& msg)
|
void Core::Account::onMamMessageReceived(const QString& queryId, const QXmppMessage& msg) {
|
||||||
{
|
|
||||||
if (msg.id().size() > 0 && (msg.body().size() > 0 || msg.outOfBandUrl().size() > 0)) {
|
if (msg.id().size() > 0 && (msg.body().size() > 0 || msg.outOfBandUrl().size() > 0)) {
|
||||||
std::map<QString, QString>::const_iterator itr = archiveQueries.find(queryId);
|
std::map<QString, QString>::const_iterator itr = archiveQueries.find(queryId);
|
||||||
if (itr != archiveQueries.end()) {
|
if (itr != archiveQueries.end()) {
|
||||||
@ -317,21 +430,19 @@ void Core::Account::onMamMessageReceived(const QString& queryId, const QXmppMess
|
|||||||
sMsg.setState(Shared::Message::State::sent);
|
sMsg.setState(Shared::Message::State::sent);
|
||||||
|
|
||||||
QString oId = msg.replaceId();
|
QString oId = msg.replaceId();
|
||||||
if (oId.size() > 0) {
|
if (oId.size() > 0)
|
||||||
item->correctMessageInArchive(oId, sMsg);
|
item->correctMessageInArchive(oId, sMsg);
|
||||||
} else {
|
else
|
||||||
item->addMessageToArchive(sMsg);
|
item->addMessageToArchive(sMsg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Account::requestArchive(const QString& jid, int count, const QString& before)
|
void Core::Account::requestArchive(const QString& jid, int count, const QString& before) {
|
||||||
{
|
|
||||||
qDebug() << "An archive request for " << jid << ", before " << before;
|
qDebug() << "An archive request for " << jid << ", before " << before;
|
||||||
RosterItem* contact = rh->getRosterItem(jid);
|
RosterItem* item = rh->getRosterItem(jid);
|
||||||
|
|
||||||
if (contact == 0) {
|
if (item == nullptr) {
|
||||||
qDebug() << "An attempt to request archive for" << jid << "in account" << name << ", but the contact with such id wasn't found, skipping";
|
qDebug() << "An attempt to request archive for" << jid << "in account" << name << ", but the contact with such id wasn't found, skipping";
|
||||||
emit responseArchive(jid, std::list<Shared::Message>(), true);
|
emit responseArchive(jid, std::list<Shared::Message>(), true);
|
||||||
return;
|
return;
|
||||||
@ -339,14 +450,21 @@ void Core::Account::requestArchive(const QString& jid, int count, const QString&
|
|||||||
|
|
||||||
if (state != Shared::ConnectionState::connected) {
|
if (state != Shared::ConnectionState::connected) {
|
||||||
qDebug() << "An attempt to request archive for" << jid << "in account" << name << ", but the account is not online, skipping";
|
qDebug() << "An attempt to request archive for" << jid << "in account" << name << ", but the account is not online, skipping";
|
||||||
emit responseArchive(contact->jid, std::list<Shared::Message>(), false);
|
emit responseArchive(jid, std::list<Shared::Message>(), false);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
contact->requestHistory(count, before);
|
#ifdef WITH_OMEMO
|
||||||
|
if (!item->isMuc()) {
|
||||||
|
Contact* contact = static_cast<Contact*>(item);
|
||||||
|
if (contact->omemoBundles == Shared::Possible::unknown)
|
||||||
|
oh->requestBundles(jid);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
item->requestHistory(count, before);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Account::onContactNeedHistory(const QString& before, const QString& after, const QDateTime& at)
|
void Core::Account::onContactNeedHistory(const QString& before, const QString& after, const QDateTime& at) {
|
||||||
{
|
|
||||||
RosterItem* contact = static_cast<RosterItem*>(sender());
|
RosterItem* contact = static_cast<RosterItem*>(sender());
|
||||||
|
|
||||||
QString to;
|
QString to;
|
||||||
@ -390,8 +508,7 @@ void Core::Account::onContactNeedHistory(const QString& before, const QString& a
|
|||||||
archiveQueries.insert(std::make_pair(q, contact->jid));
|
archiveQueries.insert(std::make_pair(q, contact->jid));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Account::onMamResultsReceived(const QString& queryId, const QXmppResultSetReply& resultSetReply, bool complete)
|
void Core::Account::onMamResultsReceived(const QString& queryId, const QXmppResultSetReply& resultSetReply, bool complete) {
|
||||||
{
|
|
||||||
std::map<QString, QString>::const_iterator itr = archiveQueries.find(queryId);
|
std::map<QString, QString>::const_iterator itr = archiveQueries.find(queryId);
|
||||||
if (itr != archiveQueries.end()) {
|
if (itr != archiveQueries.end()) {
|
||||||
QString jid = itr->second;
|
QString jid = itr->second;
|
||||||
@ -399,21 +516,20 @@ void Core::Account::onMamResultsReceived(const QString& queryId, const QXmppResu
|
|||||||
|
|
||||||
RosterItem* ri = rh->getRosterItem(jid);
|
RosterItem* ri = rh->getRosterItem(jid);
|
||||||
|
|
||||||
if (ri != 0) {
|
if (ri != nullptr) {
|
||||||
qDebug() << "Flushing messages for" << jid << ", complete:" << complete;
|
qDebug() << "Flushing messages for" << jid << ", complete:" << complete;
|
||||||
ri->flushMessagesToArchive(complete, resultSetReply.first(), resultSetReply.last());
|
ri->flushMessagesToArchive(complete, resultSetReply.first(), resultSetReply.last());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Account::onMamLog(QXmppLogger::MessageType type, const QString& msg)
|
void Core::Account::onMamLog(QXmppLogger::MessageType type, const QString& msg) {
|
||||||
{
|
SHARED_UNUSED(type);
|
||||||
qDebug() << "MAM MESSAGE LOG::";
|
qDebug() << "MAM MESSAGE LOG::";
|
||||||
qDebug() << msg;
|
qDebug() << msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Account::onClientError(QXmppClient::Error err)
|
void Core::Account::onClientError(QXmppClient::Error err) {
|
||||||
{
|
|
||||||
qDebug() << "Error";
|
qDebug() << "Error";
|
||||||
QString errorText;
|
QString errorText;
|
||||||
QString errorType;
|
QString errorType;
|
||||||
@ -523,22 +639,18 @@ void Core::Account::onClientError(QXmppClient::Error err)
|
|||||||
emit error(errorText);
|
emit error(errorText);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Account::subscribeToContact(const QString& jid, const QString& reason)
|
void Core::Account::subscribeToContact(const QString& jid, const QString& reason) {
|
||||||
{
|
if (state == Shared::ConnectionState::connected)
|
||||||
if (state == Shared::ConnectionState::connected) {
|
|
||||||
rm->subscribe(jid, reason);
|
rm->subscribe(jid, reason);
|
||||||
} else {
|
else
|
||||||
qDebug() << "An attempt to subscribe account " << name << " to contact " << jid << " but the account is not in the connected state, skipping";
|
qDebug() << "An attempt to subscribe account " << name << " to contact " << jid << " but the account is not in the connected state, skipping";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Account::unsubscribeFromContact(const QString& jid, const QString& reason)
|
void Core::Account::unsubscribeFromContact(const QString& jid, const QString& reason) {
|
||||||
{
|
if (state == Shared::ConnectionState::connected)
|
||||||
if (state == Shared::ConnectionState::connected) {
|
|
||||||
rm->unsubscribe(jid, reason);
|
rm->unsubscribe(jid, reason);
|
||||||
} else {
|
else
|
||||||
qDebug() << "An attempt to unsubscribe account " << name << " from contact " << jid << " but the account is not in the connected state, skipping";
|
qDebug() << "An attempt to unsubscribe account " << name << " from contact " << jid << " but the account is not in the connected state, skipping";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Account::removeContactRequest(const QString& jid) {
|
void Core::Account::removeContactRequest(const QString& jid) {
|
||||||
@ -547,8 +659,7 @@ void Core::Account::removeContactRequest(const QString& jid) {
|
|||||||
void Core::Account::addContactRequest(const QString& jid, const QString& name, const QSet<QString>& groups) {
|
void Core::Account::addContactRequest(const QString& jid, const QString& name, const QSet<QString>& groups) {
|
||||||
rh->addContactRequest(jid, name, groups);}
|
rh->addContactRequest(jid, name, groups);}
|
||||||
|
|
||||||
void Core::Account::setRoomAutoJoin(const QString& jid, bool joined)
|
void Core::Account::setRoomAutoJoin(const QString& jid, bool joined) {
|
||||||
{
|
|
||||||
Conference* conf = rh->getConference(jid);
|
Conference* conf = rh->getConference(jid);
|
||||||
if (conf == 0) {
|
if (conf == 0) {
|
||||||
qDebug() << "An attempt to set auto join to the non existing room" << jid << "of the account" << getName() << ", skipping";
|
qDebug() << "An attempt to set auto join to the non existing room" << jid << "of the account" << getName() << ", skipping";
|
||||||
@ -558,8 +669,7 @@ void Core::Account::setRoomAutoJoin(const QString& jid, bool joined)
|
|||||||
conf->setAutoJoin(joined);
|
conf->setAutoJoin(joined);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Account::setRoomJoined(const QString& jid, bool joined)
|
void Core::Account::setRoomJoined(const QString& jid, bool joined) {
|
||||||
{
|
|
||||||
Conference* conf = rh->getConference(jid);
|
Conference* conf = rh->getConference(jid);
|
||||||
if (conf == 0) {
|
if (conf == 0) {
|
||||||
qDebug() << "An attempt to set joined to the non existing room" << jid << "of the account" << getName() << ", skipping";
|
qDebug() << "An attempt to set joined to the non existing room" << jid << "of the account" << getName() << ", skipping";
|
||||||
@ -569,85 +679,51 @@ void Core::Account::setRoomJoined(const QString& jid, bool joined)
|
|||||||
conf->setJoined(joined);
|
conf->setJoined(joined);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Account::onDiscoveryItemsReceived(const QXmppDiscoveryIq& items)
|
void Core::Account::setContactEncryption(const QString& jid, Shared::EncryptionProtocol value) {
|
||||||
{
|
Contact* cnt = rh->getContact(jid);
|
||||||
if (items.from() == getServer()) {
|
if (cnt == nullptr) {
|
||||||
std::set<QString> needToRequest;
|
qDebug() << "An attempt to set encryption to the non-existing contact" << jid << "of the account" << getName() << ", skipping";
|
||||||
qDebug() << "Server items list received for account " << name << ":";
|
return;
|
||||||
for (QXmppDiscoveryIq::Item item : items.items()) {
|
|
||||||
QString jid = item.jid();
|
|
||||||
if (jid != getServer()) {
|
|
||||||
qDebug() << " Node" << jid;
|
|
||||||
needToRequest.insert(jid);
|
|
||||||
} else {
|
|
||||||
qDebug() << " " << item.node().toStdString().c_str();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const QString& jid : needToRequest) {
|
cnt->setEncryption(value);
|
||||||
dm->requestInfo(jid);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
void Core::Account::discoverInfo(const QString& address, const QString& node) {
|
||||||
|
if (state == Shared::ConnectionState::connected) {
|
||||||
|
dm->requestInfo(address, node);
|
||||||
|
} else {
|
||||||
|
qDebug() << "An attempt to send a discover info by account" << name <<
|
||||||
|
"sending request to" << address << "about node" << node <<
|
||||||
|
"but the account is not in the connected state, skipping";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Account::onDiscoveryInfoReceived(const QXmppDiscoveryIq& info)
|
void Core::Account::setPepSupport(Shared::Support support) {
|
||||||
{
|
if (support != pepSupport) {
|
||||||
if (info.from() == getServer()) {
|
pepSupport = support;
|
||||||
bool enableCC = false;
|
emit pepSupportChanged(pepSupport);
|
||||||
qDebug() << "Server info received for account" << name;
|
|
||||||
QStringList features = info.features();
|
|
||||||
qDebug() << "List of supported features of the server " << getServer() << ":";
|
|
||||||
for (const QString& feature : features) {
|
|
||||||
qDebug() << " " << feature.toStdString().c_str();
|
|
||||||
if (feature == "urn:xmpp:carbons:2") {
|
|
||||||
enableCC = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enableCC) {
|
|
||||||
qDebug() << "Enabling carbon copies for account" << name;
|
|
||||||
cm->setCarbonsEnabled(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
qDebug() << "Requesting account" << name << "capabilities";
|
|
||||||
dm->requestInfo(getBareJid());
|
|
||||||
} else if (info.from() == getBareJid()) {
|
|
||||||
qDebug() << "Received capabilities for account" << name << ":";
|
|
||||||
QList<QXmppDiscoveryIq::Identity> identities = info.identities();
|
|
||||||
bool pepSupported = false;
|
|
||||||
for (const QXmppDiscoveryIq::Identity& identity : identities) {
|
|
||||||
QString type = identity.type();
|
|
||||||
qDebug() << " " << identity.category() << type;
|
|
||||||
if (type == "pep") {
|
|
||||||
pepSupported = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rh->setPepSupport(pepSupported);
|
|
||||||
} else {
|
|
||||||
qDebug() << "Received info for account" << name << "about" << info.from();
|
|
||||||
QList<QXmppDiscoveryIq::Identity> identities = info.identities();
|
|
||||||
for (const QXmppDiscoveryIq::Identity& identity : identities) {
|
|
||||||
qDebug() << " " << identity.name() << identity.category() << identity.type();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Account::handleDisconnection()
|
void Core::Account::handleDisconnection() {
|
||||||
{
|
setPepSupport(Shared::Support::unknown);
|
||||||
|
delay->disconnected();
|
||||||
|
#if (QXMPP_VERSION) < QT_VERSION_CHECK(1, 5, 0)
|
||||||
cm->setCarbonsEnabled(false);
|
cm->setCarbonsEnabled(false);
|
||||||
|
#endif
|
||||||
rh->handleOffline();
|
rh->handleOffline();
|
||||||
vh->handleOffline();
|
|
||||||
archiveQueries.clear();
|
archiveQueries.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Account::onContactHistoryResponse(const std::list<Shared::Message>& list, bool last)
|
void Core::Account::onContactHistoryResponse(const std::list<Shared::Message>& list, bool last) {
|
||||||
{
|
|
||||||
RosterItem* contact = static_cast<RosterItem*>(sender());
|
RosterItem* contact = static_cast<RosterItem*>(sender());
|
||||||
|
|
||||||
qDebug() << "Collected history for contact " << contact->jid << list.size() << "elements";
|
qDebug() << "Collected history for contact " << contact->jid << list.size() << "elements";
|
||||||
if (last) {
|
if (last)
|
||||||
qDebug() << "The response contains the first accounted message";
|
qDebug() << "The response contains the first accounted message";
|
||||||
}
|
|
||||||
emit responseArchive(contact->jid, list, last);
|
emit responseArchive(contact->jid, list, last);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -658,9 +734,7 @@ void Core::Account::setActive(bool p_active) {
|
|||||||
if (active != p_active) {
|
if (active != p_active) {
|
||||||
active = p_active;
|
active = p_active;
|
||||||
|
|
||||||
emit changed({
|
emit changed({{"active", active}});
|
||||||
{"active", active}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -695,7 +769,9 @@ void Core::Account::setPasswordType(Shared::AccountPassword pt) {
|
|||||||
passwordType = pt; }
|
passwordType = pt; }
|
||||||
|
|
||||||
void Core::Account::setLogin(const QString& p_login) {
|
void Core::Account::setLogin(const QString& p_login) {
|
||||||
config.setUser(p_login);}
|
config.setUser(p_login);
|
||||||
|
delay->setOwnJid(getBareJid());
|
||||||
|
}
|
||||||
|
|
||||||
void Core::Account::setName(const QString& p_name) {
|
void Core::Account::setName(const QString& p_name) {
|
||||||
name = p_name;}
|
name = p_name;}
|
||||||
@ -706,7 +782,9 @@ void Core::Account::setPassword(const QString& p_password) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Core::Account::setServer(const QString& p_server) {
|
void Core::Account::setServer(const QString& p_server) {
|
||||||
config.setDomain(p_server);}
|
config.setDomain(p_server);
|
||||||
|
delay->setOwnJid(getBareJid());
|
||||||
|
}
|
||||||
|
|
||||||
void Core::Account::sendMessage(const Shared::Message& data) {
|
void Core::Account::sendMessage(const Shared::Message& data) {
|
||||||
mh->sendMessage(data);}
|
mh->sendMessage(data);}
|
||||||
@ -720,11 +798,26 @@ void Core::Account::resendMessage(const QString& jid, const QString& id) {
|
|||||||
void Core::Account::replaceMessage(const QString& originalId, const Shared::Message& data) {
|
void Core::Account::replaceMessage(const QString& originalId, const Shared::Message& data) {
|
||||||
mh->sendMessage(data, false, originalId);}
|
mh->sendMessage(data, false, originalId);}
|
||||||
|
|
||||||
void Core::Account::requestVCard(const QString& jid) {
|
void Core::Account::requestInfo(const QString& jid) {
|
||||||
vh->requestVCard(jid);}
|
//TODO switch case of what kind of entity this info request is about
|
||||||
|
//right now it could be only about myself or some contact
|
||||||
|
delay->getInfo(jid);
|
||||||
|
//vh->requestVCard(jid);
|
||||||
|
}
|
||||||
|
|
||||||
void Core::Account::uploadVCard(const Shared::VCard& card) {
|
void Core::Account::updateInfo(const Shared::Info& info) {
|
||||||
vh->uploadVCard(card);}
|
//TODO switch case of what kind of entity this info update is about
|
||||||
|
//right now it could be only about myself
|
||||||
|
vh->uploadVCard(info.getVCardRef());
|
||||||
|
const std::list<Shared::KeyInfo>& keys = info.getActiveKeysRef();
|
||||||
|
for (const Shared::KeyInfo& info : keys) {
|
||||||
|
qDebug() << "An attempt to save key: ";
|
||||||
|
qDebug() << "id:" << info.id;
|
||||||
|
qDebug() << "label:" << info.label;
|
||||||
|
qDebug() << "current device:" << info.currentDevice;
|
||||||
|
qDebug() << "... but it's not implemented yet, ignoring";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QString Core::Account::getAvatarPath() const {
|
QString Core::Account::getAvatarPath() const {
|
||||||
return vh->getAvatarPath();}
|
return vh->getAvatarPath();}
|
||||||
@ -741,14 +834,12 @@ void Core::Account::addContactToGroupRequest(const QString& jid, const QString&
|
|||||||
void Core::Account::removeContactFromGroupRequest(const QString& jid, const QString& groupName) {
|
void Core::Account::removeContactFromGroupRequest(const QString& jid, const QString& groupName) {
|
||||||
rh->removeContactFromGroupRequest(jid, groupName);}
|
rh->removeContactFromGroupRequest(jid, groupName);}
|
||||||
|
|
||||||
void Core::Account::renameContactRequest(const QString& jid, const QString& newName)
|
void Core::Account::renameContactRequest(const QString& jid, const QString& newName) {
|
||||||
{
|
|
||||||
Contact* cnt = rh->getContact(jid);
|
Contact* cnt = rh->getContact(jid);
|
||||||
if (cnt == 0) {
|
if (cnt == 0)
|
||||||
qDebug() << "An attempt to rename non existing contact" << jid << "of account" << name << ", skipping";
|
qDebug() << "An attempt to rename non existing contact" << jid << "of account" << name << ", skipping";
|
||||||
} else {
|
else
|
||||||
rm->renameItem(jid, newName);
|
rm->renameItem(jid, newName);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Account::invalidatePassword() {
|
void Core::Account::invalidatePassword() {
|
||||||
|
@ -15,9 +15,7 @@
|
|||||||
* 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/>.
|
||||||
*/
|
*/
|
||||||
|
#pragma once
|
||||||
#ifndef CORE_ACCOUNT_H
|
|
||||||
#define CORE_ACCOUNT_H
|
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QCryptographicHash>
|
#include <QCryptographicHash>
|
||||||
@ -29,9 +27,14 @@
|
|||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
#include <QXmppRosterManager.h>
|
#include <QXmppRosterManager.h>
|
||||||
|
#if (QXMPP_VERSION) >= QT_VERSION_CHECK(1, 5, 0)
|
||||||
|
#include <QXmppCarbonManagerV2.h>
|
||||||
|
#else
|
||||||
#include <QXmppCarbonManager.h>
|
#include <QXmppCarbonManager.h>
|
||||||
|
#endif
|
||||||
#include <QXmppDiscoveryManager.h>
|
#include <QXmppDiscoveryManager.h>
|
||||||
#include <QXmppMamManager.h>
|
#include <QXmppMamManager.h>
|
||||||
#include <QXmppMucManager.h>
|
#include <QXmppMucManager.h>
|
||||||
@ -41,25 +44,41 @@
|
|||||||
#include <QXmppUploadRequestManager.h>
|
#include <QXmppUploadRequestManager.h>
|
||||||
#include <QXmppVCardManager.h>
|
#include <QXmppVCardManager.h>
|
||||||
#include <QXmppMessageReceiptManager.h>
|
#include <QXmppMessageReceiptManager.h>
|
||||||
|
#include <QXmppPubSubManager.h>
|
||||||
|
|
||||||
#include "shared/shared.h"
|
#include <shared/shared.h>
|
||||||
|
#include <shared/identity.h>
|
||||||
|
#include <shared/info.h>
|
||||||
|
#include <shared/clientid.h>
|
||||||
#include "contact.h"
|
#include "contact.h"
|
||||||
#include "conference.h"
|
#include "conference.h"
|
||||||
#include "networkaccess.h"
|
#include <core/components/networkaccess.h>
|
||||||
|
#include <core/delayManager/manager.h>
|
||||||
|
|
||||||
#include "handlers/messagehandler.h"
|
#include "handlers/messagehandler.h"
|
||||||
#include "handlers/rosterhandler.h"
|
#include "handlers/rosterhandler.h"
|
||||||
#include "handlers/vcardhandler.h"
|
#include "handlers/vcardhandler.h"
|
||||||
|
#include "handlers/discoveryhandler.h"
|
||||||
|
|
||||||
namespace Core
|
#ifdef WITH_OMEMO
|
||||||
{
|
#include <QXmppOmemoManager.h>
|
||||||
|
#include <QXmppTrustManager.h>
|
||||||
|
#include "handlers/trusthandler.h"
|
||||||
|
#include "handlers/omemohandler.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
class Account : public QObject
|
namespace Core {
|
||||||
{
|
|
||||||
|
class Account : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
friend class MessageHandler;
|
friend class MessageHandler;
|
||||||
friend class RosterHandler;
|
friend class RosterHandler;
|
||||||
friend class VCardHandler;
|
friend class VCardHandler;
|
||||||
|
friend class DiscoveryHandler;
|
||||||
|
#ifdef WITH_OMEMO
|
||||||
|
friend class OmemoHandler;
|
||||||
|
friend class TrustHandler;
|
||||||
|
#endif
|
||||||
public:
|
public:
|
||||||
enum class Error {
|
enum class Error {
|
||||||
authentication,
|
authentication,
|
||||||
@ -109,21 +128,24 @@ public:
|
|||||||
void removeContactFromGroupRequest(const QString& jid, const QString& groupName);
|
void removeContactFromGroupRequest(const QString& jid, const QString& groupName);
|
||||||
void renameContactRequest(const QString& jid, const QString& newName);
|
void renameContactRequest(const QString& jid, const QString& newName);
|
||||||
void requestChangeMessage(const QString& jid, const QString& messageId, const QMap<QString, QVariant>& data);
|
void requestChangeMessage(const QString& jid, const QString& messageId, const QMap<QString, QVariant>& data);
|
||||||
|
void setContactEncryption(const QString& jid, Shared::EncryptionProtocol value);
|
||||||
|
|
||||||
void setRoomJoined(const QString& jid, bool joined);
|
void setRoomJoined(const QString& jid, bool joined);
|
||||||
void setRoomAutoJoin(const QString& jid, bool joined);
|
void setRoomAutoJoin(const QString& jid, bool joined);
|
||||||
void removeRoomRequest(const QString& jid);
|
void removeRoomRequest(const QString& jid);
|
||||||
void addRoomRequest(const QString& jid, const QString& nick, const QString& password, bool autoJoin);
|
void addRoomRequest(const QString& jid, const QString& nick, const QString& password, bool autoJoin);
|
||||||
void uploadVCard(const Shared::VCard& card);
|
void updateInfo(const Shared::Info& info);
|
||||||
void resendMessage(const QString& jid, const QString& id);
|
void resendMessage(const QString& jid, const QString& id);
|
||||||
void replaceMessage(const QString& originalId, const Shared::Message& data);
|
void replaceMessage(const QString& originalId, const Shared::Message& data);
|
||||||
void invalidatePassword();
|
void invalidatePassword();
|
||||||
|
|
||||||
|
void discoverInfo(const QString& address, const QString& node);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void connect();
|
void connect();
|
||||||
void disconnect();
|
void disconnect();
|
||||||
void reconnect();
|
void reconnect();
|
||||||
void requestVCard(const QString& jid);
|
void requestInfo(const QString& jid);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void changed(const QMap<QString, QVariant>& data);
|
void changed(const QMap<QString, QVariant>& data);
|
||||||
@ -147,10 +169,12 @@ signals:
|
|||||||
void addRoomParticipant(const QString& jid, const QString& nickName, const QMap<QString, QVariant>& data);
|
void addRoomParticipant(const QString& jid, const QString& nickName, const QMap<QString, QVariant>& data);
|
||||||
void changeRoomParticipant(const QString& jid, const QString& nickName, const QMap<QString, QVariant>& data);
|
void changeRoomParticipant(const QString& jid, const QString& nickName, const QMap<QString, QVariant>& data);
|
||||||
void removeRoomParticipant(const QString& jid, const QString& nickName);
|
void removeRoomParticipant(const QString& jid, const QString& nickName);
|
||||||
void receivedVCard(const QString& jid, const Shared::VCard& card);
|
void infoReady(const Shared::Info& info);
|
||||||
void uploadFile(const QFileInfo& file, const QUrl& set, const QUrl& get, QMap<QString, QString> headers);
|
void uploadFile(const QFileInfo& file, const QUrl& set, const QUrl& get, QMap<QString, QString> headers);
|
||||||
void uploadFileError(const QString& jid, const QString& messageId, const QString& error);
|
void uploadFileError(const QString& jid, const QString& messageId, const QString& error);
|
||||||
void needPassword();
|
void needPassword();
|
||||||
|
void infoDiscovered(const QString& address, const QString& node, const std::set<Shared::Identity>& identities, const std::set<QString>& features);
|
||||||
|
void pepSupportChanged(Shared::Support support);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString name;
|
QString name;
|
||||||
@ -159,7 +183,26 @@ private:
|
|||||||
QXmppConfiguration config;
|
QXmppConfiguration config;
|
||||||
QXmppPresence presence;
|
QXmppPresence presence;
|
||||||
Shared::ConnectionState state;
|
Shared::ConnectionState state;
|
||||||
|
|
||||||
|
MessageHandler* mh;
|
||||||
|
RosterHandler* rh;
|
||||||
|
VCardHandler* vh;
|
||||||
|
DiscoveryHandler* dh;
|
||||||
|
#if (QXMPP_VERSION) >= QT_VERSION_CHECK(1, 5, 0)
|
||||||
|
TrustHandler* th;
|
||||||
|
#endif
|
||||||
|
#ifdef WITH_OMEMO
|
||||||
|
OmemoHandler* oh;
|
||||||
|
|
||||||
|
QXmppOmemoManager* om;
|
||||||
|
#endif
|
||||||
|
#if (QXMPP_VERSION) >= QT_VERSION_CHECK(1, 5, 0)
|
||||||
|
QXmppTrustManager* tm;
|
||||||
|
QXmppCarbonManagerV2* cm;
|
||||||
|
QXmppPubSubManager* psm;
|
||||||
|
#else
|
||||||
QXmppCarbonManager* cm;
|
QXmppCarbonManager* cm;
|
||||||
|
#endif
|
||||||
QXmppMamManager* am;
|
QXmppMamManager* am;
|
||||||
QXmppMucManager* mm;
|
QXmppMucManager* mm;
|
||||||
QXmppBookmarkManager* bm;
|
QXmppBookmarkManager* bm;
|
||||||
@ -172,15 +215,13 @@ private:
|
|||||||
QTimer* reconnectTimer;
|
QTimer* reconnectTimer;
|
||||||
|
|
||||||
NetworkAccess* network;
|
NetworkAccess* network;
|
||||||
|
DelayManager::Manager* delay;
|
||||||
Shared::AccountPassword passwordType;
|
Shared::AccountPassword passwordType;
|
||||||
Error lastError;
|
Error lastError;
|
||||||
bool pepSupport;
|
Shared::Support pepSupport;
|
||||||
bool active;
|
bool active;
|
||||||
bool notReadyPassword;
|
bool notReadyPassword;
|
||||||
|
bool loadingOmemo;
|
||||||
MessageHandler* mh;
|
|
||||||
RosterHandler* rh;
|
|
||||||
VCardHandler* vh;
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onClientStateChange(QXmppClient::State state);
|
void onClientStateChange(QXmppClient::State state);
|
||||||
@ -194,15 +235,12 @@ private slots:
|
|||||||
|
|
||||||
void onMamLog(QXmppLogger::MessageType type, const QString &msg);
|
void onMamLog(QXmppLogger::MessageType type, const QString &msg);
|
||||||
|
|
||||||
void onDiscoveryItemsReceived (const QXmppDiscoveryIq& items);
|
|
||||||
void onDiscoveryInfoReceived (const QXmppDiscoveryIq& info);
|
|
||||||
void onContactHistoryResponse(const std::list<Shared::Message>& list, bool last);
|
void onContactHistoryResponse(const std::list<Shared::Message>& list, bool last);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void handleDisconnection();
|
void handleDisconnection();
|
||||||
void onReconnectTimer();
|
void onReconnectTimer();
|
||||||
|
void setPepSupport(Shared::Support support);
|
||||||
|
void runDiscoveryService();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif // CORE_ACCOUNT_H
|
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
#define CORE_ADAPTER_FUNCTIONS_H
|
#define CORE_ADAPTER_FUNCTIONS_H
|
||||||
|
|
||||||
#include <QXmppVCardIq.h>
|
#include <QXmppVCardIq.h>
|
||||||
|
#include <QXmppTask.h>
|
||||||
|
#include <QXmppPromise.h>
|
||||||
#include <shared/vcard.h>
|
#include <shared/vcard.h>
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
@ -26,6 +28,19 @@ namespace Core {
|
|||||||
void initializeVCard(Shared::VCard& vCard, const QXmppVCardIq& card);
|
void initializeVCard(Shared::VCard& vCard, const QXmppVCardIq& card);
|
||||||
void initializeQXmppVCard(QXmppVCardIq& card, const Shared::VCard& vCard);
|
void initializeQXmppVCard(QXmppVCardIq& card, const Shared::VCard& vCard);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
QXmppTask<T> makeReadyTask(T &&value) {
|
||||||
|
QXmppPromise<T> promise;
|
||||||
|
promise.finish(std::move(value));
|
||||||
|
return promise.task();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QXmppTask<void> makeReadyTask() {
|
||||||
|
QXmppPromise<void> promise;
|
||||||
|
promise.finish();
|
||||||
|
return promise.task();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
18
core/components/CMakeLists.txt
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
set(SOURCE_FILES
|
||||||
|
networkaccess.cpp
|
||||||
|
clientcache.cpp
|
||||||
|
urlstorage.cpp
|
||||||
|
archive.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(HEADER_FILES
|
||||||
|
networkaccess.h
|
||||||
|
clientcache.h
|
||||||
|
urlstorage.h
|
||||||
|
archive.h
|
||||||
|
)
|
||||||
|
|
||||||
|
target_sources(squawk PRIVATE
|
||||||
|
${SOURCE_FILES}
|
||||||
|
${HEADER_FILES}
|
||||||
|
)
|
419
core/components/archive.cpp
Normal file
@ -0,0 +1,419 @@
|
|||||||
|
/*
|
||||||
|
* 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 "archive.h"
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
Core::Archive::Archive(const QString& account, const QString& p_jid, QObject* parent):
|
||||||
|
QObject(parent),
|
||||||
|
jid(p_jid),
|
||||||
|
account(account),
|
||||||
|
opened(false),
|
||||||
|
db(account + "/" + jid),
|
||||||
|
messages(db.addStorage<QString, Shared::Message>("messages")),
|
||||||
|
order(db.addStorage<uint64_t, QString>("order", true)),
|
||||||
|
stats(db.addStorage<QString, QVariant>("stats")),
|
||||||
|
avatars(db.addStorage<QString, AvatarInfo>("avatars")),
|
||||||
|
stanzaIdToId(db.addStorage<QString, QString>("stanzaIdToId")),
|
||||||
|
cursor(order->createCursor())
|
||||||
|
{}
|
||||||
|
|
||||||
|
Core::Archive::~Archive() {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::Archive::open() {
|
||||||
|
db.open();
|
||||||
|
LMDBAL::WriteTransaction txn = db.beginTransaction();
|
||||||
|
|
||||||
|
AvatarInfo info;
|
||||||
|
bool hasAvatar = false;
|
||||||
|
try {
|
||||||
|
avatars->getRecord(jid, info, txn);
|
||||||
|
hasAvatar = true;
|
||||||
|
} catch (const LMDBAL::NotFound& e) {}
|
||||||
|
|
||||||
|
if (!hasAvatar)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QFile ava(db.getPath() + "/" + jid + "." + info.type);
|
||||||
|
if (ava.exists())
|
||||||
|
return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
avatars->removeRecord(jid, txn);
|
||||||
|
txn.commit();
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
qDebug() << e.what();
|
||||||
|
qDebug() << "error opening archive" << jid << "for account" << account
|
||||||
|
<< ". There is supposed to be avatar but the file doesn't exist, couldn't even drop it, it surely will lead to an error";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::Archive::close() {
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Core::Archive::addElement(const Shared::Message& message) {
|
||||||
|
QString id = message.getId();
|
||||||
|
qDebug() << "Adding message with id " << id;
|
||||||
|
|
||||||
|
try {
|
||||||
|
LMDBAL::WriteTransaction txn = db.beginTransaction();
|
||||||
|
messages->addRecord(id, message, txn);
|
||||||
|
order->addRecord(message.getTime().toMSecsSinceEpoch(), id, txn);
|
||||||
|
QString stanzaId = message.getStanzaId();
|
||||||
|
if (!stanzaId.isEmpty())
|
||||||
|
stanzaIdToId->addRecord(stanzaId, id, txn);
|
||||||
|
|
||||||
|
txn.commit();
|
||||||
|
return true;
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
qDebug() << "Could not add message with id " + id;
|
||||||
|
qDebug() << e.what();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::Archive::clear() {
|
||||||
|
db.drop();
|
||||||
|
}
|
||||||
|
|
||||||
|
Shared::Message Core::Archive::getElement(const QString& id) const {
|
||||||
|
return messages->getRecord(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Core::Archive::hasElement(const QString& id) const {
|
||||||
|
return messages->checkRecord(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::Archive::changeMessage(const QString& id, const QMap<QString, QVariant>& data) {
|
||||||
|
LMDBAL::WriteTransaction txn = db.beginTransaction();
|
||||||
|
Shared::Message msg = messages->getRecord(id, txn);
|
||||||
|
|
||||||
|
bool hadStanzaId = !msg.getStanzaId().isEmpty();
|
||||||
|
QDateTime oTime = msg.getTime();
|
||||||
|
bool idChange = msg.change(data);
|
||||||
|
QString newId = msg.getId();
|
||||||
|
QDateTime nTime = msg.getTime();
|
||||||
|
|
||||||
|
bool orderChange = oTime != nTime;
|
||||||
|
if (idChange || orderChange) {
|
||||||
|
if (idChange)
|
||||||
|
messages->removeRecord(id, txn);
|
||||||
|
|
||||||
|
if (orderChange)
|
||||||
|
order->removeRecord(oTime.toMSecsSinceEpoch(), txn);
|
||||||
|
|
||||||
|
order->forceRecord(nTime.toMSecsSinceEpoch(), newId, txn);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString sid = msg.getStanzaId();
|
||||||
|
if (!sid.isEmpty() && (idChange || !hadStanzaId))
|
||||||
|
stanzaIdToId->forceRecord(sid, newId, txn);
|
||||||
|
|
||||||
|
messages->forceRecord(newId, msg, txn);
|
||||||
|
txn.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
Shared::Message Core::Archive::newest() const {
|
||||||
|
LMDBAL::Transaction txn = db.beginReadOnlyTransaction();
|
||||||
|
|
||||||
|
try {
|
||||||
|
cursor.open(txn);
|
||||||
|
while (true) {
|
||||||
|
std::pair<uint64_t, QString> pair = cursor.prev();
|
||||||
|
Shared::Message msg = messages->getRecord(pair.second, txn);
|
||||||
|
if (msg.serverStored()) {
|
||||||
|
cursor.close();
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (...) {
|
||||||
|
cursor.close();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Core::Archive::newestId() const {
|
||||||
|
Shared::Message msg = newest();
|
||||||
|
return msg.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Core::Archive::oldestId() const {
|
||||||
|
Shared::Message msg = oldest();
|
||||||
|
return msg.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
Shared::Message Core::Archive::oldest() const {
|
||||||
|
LMDBAL::Transaction txn = db.beginReadOnlyTransaction();
|
||||||
|
|
||||||
|
try {
|
||||||
|
cursor.open(txn);
|
||||||
|
while (true) {
|
||||||
|
std::pair<uint64_t, QString> pair = cursor.next();
|
||||||
|
Shared::Message msg = messages->getRecord(pair.second, txn);
|
||||||
|
if (msg.serverStored()) {
|
||||||
|
cursor.close();
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (...) {
|
||||||
|
cursor.close();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int Core::Archive::addElements(const std::list<Shared::Message>& messages) {
|
||||||
|
unsigned int success = 0;
|
||||||
|
LMDBAL::WriteTransaction txn = db.beginTransaction();
|
||||||
|
for (const Shared::Message& message : messages) {
|
||||||
|
QString id = message.getId();
|
||||||
|
bool added = false;
|
||||||
|
try {
|
||||||
|
Core::Archive::messages->addRecord(id, message, txn);
|
||||||
|
added = true;
|
||||||
|
} catch (const LMDBAL::Exist& e) {}
|
||||||
|
|
||||||
|
if (!added)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
order->addRecord(message.getTime().toMSecsSinceEpoch(), id, txn);
|
||||||
|
|
||||||
|
QString sid = message.getStanzaId();
|
||||||
|
if (!sid.isEmpty())
|
||||||
|
stanzaIdToId->addRecord(sid, id, txn);
|
||||||
|
|
||||||
|
++success;
|
||||||
|
}
|
||||||
|
txn.commit();
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
long unsigned int Core::Archive::size() const {
|
||||||
|
return order->count();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<Shared::Message> Core::Archive::getBefore(unsigned int count, const QString& id) {
|
||||||
|
LMDBAL::Transaction txn = db.beginReadOnlyTransaction();
|
||||||
|
std::list<Shared::Message> res;
|
||||||
|
try {
|
||||||
|
cursor.open(txn);
|
||||||
|
if (!id.isEmpty()) {
|
||||||
|
Shared::Message reference = messages->getRecord(id, txn);
|
||||||
|
uint64_t stamp = reference.getTime().toMSecsSinceEpoch();
|
||||||
|
cursor.set(stamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < count; ++i) {
|
||||||
|
std::pair<uint64_t, QString> pair;
|
||||||
|
cursor.prev(pair.first, pair.second);
|
||||||
|
|
||||||
|
res.emplace_back();
|
||||||
|
Shared::Message& msg = res.back();
|
||||||
|
messages->getRecord(pair.second, msg, txn);
|
||||||
|
}
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
return res;
|
||||||
|
} catch (const LMDBAL::NotFound& e) {
|
||||||
|
cursor.close();
|
||||||
|
if (res.empty())
|
||||||
|
throw e;
|
||||||
|
else
|
||||||
|
return res;
|
||||||
|
} catch (...) {
|
||||||
|
cursor.close();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Core::Archive::isFromTheBeginning() const {
|
||||||
|
try {
|
||||||
|
return stats->getRecord("fromTheBeginning").toBool();
|
||||||
|
} catch (const LMDBAL::NotFound& e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::Archive::setFromTheBeginning(bool is) {
|
||||||
|
stats->forceRecord("fromTheBeginning", is);
|
||||||
|
}
|
||||||
|
|
||||||
|
Shared::EncryptionProtocol Core::Archive::encryption() const {
|
||||||
|
try {
|
||||||
|
return stats->getRecord("encryption").value<Shared::EncryptionProtocol>();
|
||||||
|
} catch (const LMDBAL::NotFound& e) {
|
||||||
|
return Shared::EncryptionProtocol::none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Core::Archive::setEncryption(Shared::EncryptionProtocol is) {
|
||||||
|
LMDBAL::WriteTransaction txn = db.beginTransaction();
|
||||||
|
Shared::EncryptionProtocol current = Shared::EncryptionProtocol::none;
|
||||||
|
try {
|
||||||
|
current = stats->getRecord("encryption", txn).value<Shared::EncryptionProtocol>();
|
||||||
|
} catch (const LMDBAL::NotFound& e) {}
|
||||||
|
|
||||||
|
if (is != current) {
|
||||||
|
stats->forceRecord("encryption", static_cast<uint8_t>(is), txn);
|
||||||
|
txn.commit();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Core::Archive::idByStanzaId(const QString& stanzaId) const {
|
||||||
|
return stanzaIdToId->getRecord(stanzaId);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Core::Archive::stanzaIdById(const QString& id) const {
|
||||||
|
try {
|
||||||
|
Shared::Message msg = getElement(id);
|
||||||
|
return msg.getStanzaId();
|
||||||
|
} catch (const LMDBAL::NotFound& e) {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Core::Archive::setAvatar(const QByteArray& data, AvatarInfo& newInfo, bool generated, const QString& resource) {
|
||||||
|
LMDBAL::WriteTransaction txn = db.beginTransaction();
|
||||||
|
AvatarInfo oldInfo;
|
||||||
|
bool haveAvatar = false;
|
||||||
|
QString res = resource.isEmpty() ? jid : resource;
|
||||||
|
try {
|
||||||
|
avatars->getRecord(res, oldInfo, txn);
|
||||||
|
haveAvatar = true;
|
||||||
|
} catch (const LMDBAL::NotFound& e) {}
|
||||||
|
|
||||||
|
if (data.size() == 0) {
|
||||||
|
if (!haveAvatar)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
avatars->removeRecord(res, txn);
|
||||||
|
txn.commit();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString currentPath = db.getPath();
|
||||||
|
bool needToRemoveOld = false;
|
||||||
|
QCryptographicHash hash(QCryptographicHash::Sha1);
|
||||||
|
hash.addData(data);
|
||||||
|
QByteArray newHash(hash.result());
|
||||||
|
if (haveAvatar) {
|
||||||
|
if (!generated && !oldInfo.autogenerated && oldInfo.hash == newHash)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QFile oldAvatar(currentPath + "/" + res + "." + oldInfo.type);
|
||||||
|
if (oldAvatar.exists()) {
|
||||||
|
if (oldAvatar.rename(currentPath + "/" + res + "." + oldInfo.type + ".bak")) {
|
||||||
|
needToRemoveOld = true;
|
||||||
|
} else {
|
||||||
|
qDebug() << "Can't change avatar: couldn't get rid of the old avatar" << oldAvatar.fileName();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QMimeDatabase mimedb;
|
||||||
|
QMimeType type = mimedb.mimeTypeForData(data);
|
||||||
|
QString ext = type.preferredSuffix();
|
||||||
|
QFile newAvatar(currentPath + "/" + res + "." + ext);
|
||||||
|
if (!newAvatar.open(QFile::WriteOnly)) {
|
||||||
|
qDebug() << "Can't change avatar: cant open file to write" << newAvatar.fileName() << "rolling back to the previous state";
|
||||||
|
if (needToRemoveOld) {
|
||||||
|
QFile oldAvatar(currentPath + "/" + res + "." + oldInfo.type + ".bak");
|
||||||
|
oldAvatar.rename(currentPath + "/" + res + "." + oldInfo.type);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
newAvatar.write(data);
|
||||||
|
newAvatar.close();
|
||||||
|
|
||||||
|
newInfo.type = ext;
|
||||||
|
newInfo.hash = newHash;
|
||||||
|
newInfo.autogenerated = generated;
|
||||||
|
try {
|
||||||
|
avatars->forceRecord(res, newInfo, txn);
|
||||||
|
txn.commit();
|
||||||
|
} catch (...) {
|
||||||
|
qDebug() << "Can't change avatar: couldn't store changes to database for" << newAvatar.fileName() << "rolling back to the previous state";
|
||||||
|
if (needToRemoveOld) {
|
||||||
|
QFile oldAvatar(currentPath + "/" + res + "." + oldInfo.type + ".bak");
|
||||||
|
oldAvatar.rename(currentPath + "/" + res + "." + oldInfo.type);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needToRemoveOld) {
|
||||||
|
QFile oldAvatar(currentPath + "/" + res + "." + oldInfo.type + ".bak");
|
||||||
|
oldAvatar.remove();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Core::Archive::readAvatarInfo(Core::Archive::AvatarInfo& target, const QString& resource) const {
|
||||||
|
try {
|
||||||
|
avatars->getRecord(resource.isEmpty() ? jid : resource, target);
|
||||||
|
return true;
|
||||||
|
} catch (const LMDBAL::NotFound& e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::Archive::readAllResourcesAvatars(std::map<QString, AvatarInfo>& data) const {
|
||||||
|
avatars->readAll(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
Core::Archive::AvatarInfo Core::Archive::getAvatarInfo(const QString& resource) const {
|
||||||
|
return avatars->getRecord(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
Core::Archive::AvatarInfo::AvatarInfo():
|
||||||
|
type(),
|
||||||
|
hash(),
|
||||||
|
autogenerated(false)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Core::Archive::AvatarInfo::AvatarInfo(const QString& p_type, const QByteArray& p_hash, bool p_autogenerated):
|
||||||
|
type(p_type),
|
||||||
|
hash(p_hash),
|
||||||
|
autogenerated(p_autogenerated)
|
||||||
|
{}
|
||||||
|
|
||||||
|
QDataStream & operator<<(QDataStream& out, const Core::Archive::AvatarInfo& info) {
|
||||||
|
out << info.type;
|
||||||
|
out << info.hash;
|
||||||
|
out << info.autogenerated;
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDataStream & operator>>(QDataStream& in, Core::Archive::AvatarInfo& info) {
|
||||||
|
in >> info.type;
|
||||||
|
in >> info.hash;
|
||||||
|
in >> info.autogenerated;
|
||||||
|
|
||||||
|
return in;
|
||||||
|
}
|
101
core/components/archive.h
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* 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 <QObject>
|
||||||
|
#include <QCryptographicHash>
|
||||||
|
#include <QMimeDatabase>
|
||||||
|
#include <QMimeType>
|
||||||
|
#include <QDataStream>
|
||||||
|
|
||||||
|
#include "shared/enums.h"
|
||||||
|
#include "shared/message.h"
|
||||||
|
#include "shared/exception.h"
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
#include <base.h>
|
||||||
|
#include <storage.h>
|
||||||
|
#include <cursor.h>
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
|
||||||
|
class Archive : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
class AvatarInfo;
|
||||||
|
|
||||||
|
Archive(const QString& account, const QString& jid, QObject* parent = 0);
|
||||||
|
~Archive();
|
||||||
|
|
||||||
|
void open();
|
||||||
|
void close();
|
||||||
|
|
||||||
|
bool addElement(const Shared::Message& message);
|
||||||
|
unsigned int addElements(const std::list<Shared::Message>& messages);
|
||||||
|
Shared::Message getElement(const QString& id) const;
|
||||||
|
bool hasElement(const QString& id) const;
|
||||||
|
void changeMessage(const QString& id, const QMap<QString, QVariant>& data);
|
||||||
|
Shared::Message oldest() const;
|
||||||
|
QString oldestId() const;
|
||||||
|
Shared::Message newest() const;
|
||||||
|
QString newestId() const;
|
||||||
|
void clear();
|
||||||
|
long unsigned int size() const;
|
||||||
|
std::list<Shared::Message> getBefore(unsigned int count, const QString& id);
|
||||||
|
bool isFromTheBeginning() const;
|
||||||
|
void setFromTheBeginning(bool is);
|
||||||
|
Shared::EncryptionProtocol encryption() const;
|
||||||
|
bool setEncryption(Shared::EncryptionProtocol value); //returns true if changed, false otherwise
|
||||||
|
bool setAvatar(const QByteArray& data, AvatarInfo& info, bool generated = false, const QString& resource = "");
|
||||||
|
AvatarInfo getAvatarInfo(const QString& resource = "") const;
|
||||||
|
bool readAvatarInfo(AvatarInfo& target, const QString& resource = "") const;
|
||||||
|
void readAllResourcesAvatars(std::map<QString, AvatarInfo>& data) const;
|
||||||
|
QString idByStanzaId(const QString& stanzaId) const;
|
||||||
|
QString stanzaIdById(const QString& id) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
const QString jid;
|
||||||
|
const QString account;
|
||||||
|
|
||||||
|
public:
|
||||||
|
class AvatarInfo {
|
||||||
|
public:
|
||||||
|
AvatarInfo();
|
||||||
|
AvatarInfo(const QString& type, const QByteArray& hash, bool autogenerated);
|
||||||
|
|
||||||
|
QString type;
|
||||||
|
QByteArray hash;
|
||||||
|
bool autogenerated;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool opened;
|
||||||
|
LMDBAL::Base db;
|
||||||
|
LMDBAL::Storage<QString, Shared::Message>* messages;
|
||||||
|
LMDBAL::Storage<uint64_t, QString>* order;
|
||||||
|
LMDBAL::Storage<QString, QVariant>* stats;
|
||||||
|
LMDBAL::Storage<QString, AvatarInfo>* avatars;
|
||||||
|
LMDBAL::Storage<QString, QString>* stanzaIdToId;
|
||||||
|
mutable LMDBAL::Cursor<uint64_t, QString> cursor;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QDataStream& operator << (QDataStream &out, const Core::Archive::AvatarInfo& info);
|
||||||
|
QDataStream& operator >> (QDataStream &in, Core::Archive::AvatarInfo& info);
|
77
core/components/clientcache.cpp
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* 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 "clientcache.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
Core::ClientCache::ClientCache():
|
||||||
|
db("clients"),
|
||||||
|
cache(db.addCache<QString, Shared::ClientInfo>("info")),
|
||||||
|
requested(),
|
||||||
|
specific()
|
||||||
|
{
|
||||||
|
db.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
Core::ClientCache::~ClientCache() {
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::ClientCache::open() {
|
||||||
|
db.open();}
|
||||||
|
|
||||||
|
void Core::ClientCache::close() {
|
||||||
|
db.close();}
|
||||||
|
|
||||||
|
bool Core::ClientCache::checkClient(const Shared::ClientId& p_id) {
|
||||||
|
QString id = p_id.getId();
|
||||||
|
if (requested.count(id) == 0 && !cache->checkRecord(id)) {
|
||||||
|
requested.emplace(id, p_id);
|
||||||
|
emit requestClientInfo(id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Core::ClientCache::registerClientInfo (
|
||||||
|
const QString& sourceFullJid,
|
||||||
|
const QString& id,
|
||||||
|
const std::set<Shared::Identity>& identities,
|
||||||
|
const std::set<QString>& features)
|
||||||
|
{
|
||||||
|
std::map<QString, Shared::ClientInfo>::iterator itr = requested.find(id);
|
||||||
|
if (itr != requested.end()) {
|
||||||
|
Shared::ClientInfo& info = itr->second;
|
||||||
|
info.identities = identities;
|
||||||
|
info.extensions = features;
|
||||||
|
|
||||||
|
bool valid = info.valid();
|
||||||
|
if (valid) {
|
||||||
|
cache->addRecord(id, info);
|
||||||
|
} else {
|
||||||
|
info.specificPresence = sourceFullJid;
|
||||||
|
specific.insert(std::make_pair(sourceFullJid, info));
|
||||||
|
}
|
||||||
|
requested.erase(id);
|
||||||
|
return valid;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
63
core/components/clientcache.h
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* 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 <map>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include <cache.h>
|
||||||
|
|
||||||
|
#include <shared/clientid.h>
|
||||||
|
#include <shared/clientinfo.h>
|
||||||
|
#include <shared/identity.h>
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
|
||||||
|
class ClientCache : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
ClientCache();
|
||||||
|
~ClientCache();
|
||||||
|
|
||||||
|
void open();
|
||||||
|
void close();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void requestClientInfo(const QString& id);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
bool checkClient(const Shared::ClientId& id);
|
||||||
|
bool registerClientInfo(
|
||||||
|
const QString& sourceFullJid,
|
||||||
|
const QString& id,
|
||||||
|
const std::set<Shared::Identity>& identities,
|
||||||
|
const std::set<QString>& features
|
||||||
|
);
|
||||||
|
|
||||||
|
private:
|
||||||
|
LMDBAL::Base db;
|
||||||
|
LMDBAL::Cache<QString, Shared::ClientInfo>* cache;
|
||||||
|
std::map<QString, Shared::ClientInfo> requested;
|
||||||
|
std::map<QString, Shared::ClientInfo> specific;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -16,7 +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/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <QtWidgets/QApplication>
|
#include <QtWidgets/QApplication>
|
||||||
#include <QtCore/QDir>
|
#include <QtCore/QDir>
|
||||||
|
|
||||||
@ -35,13 +34,11 @@ Core::NetworkAccess::NetworkAccess(QObject* parent):
|
|||||||
currentPath = settings.value("downloadsPath").toString();
|
currentPath = settings.value("downloadsPath").toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::NetworkAccess::~NetworkAccess()
|
Core::NetworkAccess::~NetworkAccess() {
|
||||||
{
|
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::NetworkAccess::downladFile(const QString& url)
|
void Core::NetworkAccess::downladFile(const QString& url) {
|
||||||
{
|
|
||||||
std::map<QString, Transfer*>::iterator itr = downloads.find(url);
|
std::map<QString, Transfer*>::iterator itr = downloads.find(url);
|
||||||
if (itr != downloads.end()) {
|
if (itr != downloads.end()) {
|
||||||
qDebug() << "NetworkAccess received a request to download a file" << url << ", but the file is currently downloading, skipping";
|
qDebug() << "NetworkAccess received a request to download a file" << url << ", but the file is currently downloading, skipping";
|
||||||
@ -50,27 +47,25 @@ void Core::NetworkAccess::downladFile(const QString& url)
|
|||||||
std::pair<QString, std::list<Shared::MessageInfo>> p = storage.getPath(url);
|
std::pair<QString, std::list<Shared::MessageInfo>> p = storage.getPath(url);
|
||||||
if (p.first.size() > 0) {
|
if (p.first.size() > 0) {
|
||||||
QFileInfo info(p.first);
|
QFileInfo info(p.first);
|
||||||
if (info.exists() && info.isFile()) {
|
if (info.exists() && info.isFile())
|
||||||
emit downloadFileComplete(p.second, p.first);
|
emit downloadFileComplete(p.second, p.first);
|
||||||
|
else
|
||||||
|
startDownload(p.second, url);
|
||||||
} else {
|
} else {
|
||||||
startDownload(p.second, url);
|
startDownload(p.second, url);
|
||||||
}
|
}
|
||||||
} else {
|
} catch (const LMDBAL::NotFound& e) {
|
||||||
startDownload(p.second, url);
|
|
||||||
}
|
|
||||||
} catch (const Archive::NotFound& e) {
|
|
||||||
qDebug() << "NetworkAccess received a request to download a file" << url << ", but there is now record of which message uses that file, downloading anyway";
|
qDebug() << "NetworkAccess received a request to download a file" << url << ", but there is now record of which message uses that file, downloading anyway";
|
||||||
storage.addFile(url);
|
storage.addFile(url);
|
||||||
startDownload(std::list<Shared::MessageInfo>(), url);
|
startDownload(std::list<Shared::MessageInfo>(), url);
|
||||||
} catch (const Archive::Unknown& e) {
|
} catch (const LMDBAL::Unknown& e) {
|
||||||
qDebug() << "Error requesting file path:" << e.what();
|
qDebug() << "Error requesting file path:" << e.what();
|
||||||
emit loadFileError(std::list<Shared::MessageInfo>(), QString("Database error: ") + e.what(), false);
|
emit loadFileError(std::list<Shared::MessageInfo>(), QString("Database error: ") + e.what(), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::NetworkAccess::start()
|
void Core::NetworkAccess::start() {
|
||||||
{
|
|
||||||
if (!running) {
|
if (!running) {
|
||||||
manager = new QNetworkAccessManager();
|
manager = new QNetworkAccessManager();
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
||||||
@ -81,8 +76,7 @@ void Core::NetworkAccess::start()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::NetworkAccess::stop()
|
void Core::NetworkAccess::stop() {
|
||||||
{
|
|
||||||
if (running) {
|
if (running) {
|
||||||
storage.close();
|
storage.close();
|
||||||
manager->deleteLater();
|
manager->deleteLater();
|
||||||
@ -96,8 +90,7 @@ void Core::NetworkAccess::stop()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::NetworkAccess::onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal)
|
void Core::NetworkAccess::onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) {
|
||||||
{
|
|
||||||
QNetworkReply* rpl = static_cast<QNetworkReply*>(sender());
|
QNetworkReply* rpl = static_cast<QNetworkReply*>(sender());
|
||||||
QString url = rpl->url().toString();
|
QString url = rpl->url().toString();
|
||||||
std::map<QString, Transfer*>::const_iterator itr = downloads.find(url);
|
std::map<QString, Transfer*>::const_iterator itr = downloads.find(url);
|
||||||
@ -115,8 +108,7 @@ void Core::NetworkAccess::onDownloadProgress(qint64 bytesReceived, qint64 bytesT
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::NetworkAccess::onDownloadError(QNetworkReply::NetworkError code)
|
void Core::NetworkAccess::onDownloadError(QNetworkReply::NetworkError code) {
|
||||||
{
|
|
||||||
qDebug() << "DEBUG: DOWNLOAD ERROR";
|
qDebug() << "DEBUG: DOWNLOAD ERROR";
|
||||||
QNetworkReply* rpl = static_cast<QNetworkReply*>(sender());
|
QNetworkReply* rpl = static_cast<QNetworkReply*>(sender());
|
||||||
qDebug() << rpl->errorString();
|
qDebug() << rpl->errorString();
|
||||||
@ -134,12 +126,11 @@ void Core::NetworkAccess::onDownloadError(QNetworkReply::NetworkError code)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::NetworkAccess::onDownloadSSLError(const QList<QSslError>& errors)
|
void Core::NetworkAccess::onDownloadSSLError(const QList<QSslError>& errors) {
|
||||||
{
|
|
||||||
qDebug() << "DEBUG: DOWNLOAD SSL ERRORS";
|
qDebug() << "DEBUG: DOWNLOAD SSL ERRORS";
|
||||||
for (const QSslError& err : errors) {
|
for (const QSslError& err : errors)
|
||||||
qDebug() << err.errorString();
|
qDebug() << err.errorString();
|
||||||
}
|
|
||||||
QNetworkReply* rpl = static_cast<QNetworkReply*>(sender());
|
QNetworkReply* rpl = static_cast<QNetworkReply*>(sender());
|
||||||
QString url = rpl->url().toString();
|
QString url = rpl->url().toString();
|
||||||
std::map<QString, Transfer*>::const_iterator itr = downloads.find(url);
|
std::map<QString, Transfer*>::const_iterator itr = downloads.find(url);
|
||||||
@ -154,9 +145,7 @@ void Core::NetworkAccess::onDownloadSSLError(const QList<QSslError>& errors)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString Core::NetworkAccess::getErrorText(QNetworkReply::NetworkError code) {
|
||||||
QString Core::NetworkAccess::getErrorText(QNetworkReply::NetworkError code)
|
|
||||||
{
|
|
||||||
QString errorText("");
|
QString errorText("");
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case QNetworkReply::NoError:
|
case QNetworkReply::NoError:
|
||||||
@ -280,8 +269,7 @@ QString Core::NetworkAccess::getErrorText(QNetworkReply::NetworkError code)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Core::NetworkAccess::onDownloadFinished()
|
void Core::NetworkAccess::onDownloadFinished() {
|
||||||
{
|
|
||||||
qDebug() << "DEBUG: DOWNLOAD FINISHED";
|
qDebug() << "DEBUG: DOWNLOAD FINISHED";
|
||||||
QNetworkReply* rpl = static_cast<QNetworkReply*>(sender());
|
QNetworkReply* rpl = static_cast<QNetworkReply*>(sender());
|
||||||
QString url = rpl->url().toString();
|
QString url = rpl->url().toString();
|
||||||
@ -296,11 +284,11 @@ void Core::NetworkAccess::onDownloadFinished()
|
|||||||
QStringList hops = url.split("/");
|
QStringList hops = url.split("/");
|
||||||
QString fileName = hops.back();
|
QString fileName = hops.back();
|
||||||
QString jid;
|
QString jid;
|
||||||
if (dwn->messages.size() > 0) {
|
if (dwn->messages.size() > 0)
|
||||||
jid = dwn->messages.front().jid;
|
jid = dwn->messages.front().jid;
|
||||||
} else {
|
else
|
||||||
qDebug() << "An attempt to save the file but it doesn't seem to belong to any message, download is definately going to be broken";
|
qDebug() << "An attempt to save the file but it doesn't seem to belong to any message, download is definately going to be broken";
|
||||||
}
|
|
||||||
QString path = prepareDirectory(jid);
|
QString path = prepareDirectory(jid);
|
||||||
if (path.size() > 0) {
|
if (path.size() > 0) {
|
||||||
path = checkFileName(fileName, path);
|
path = checkFileName(fileName, path);
|
||||||
@ -319,12 +307,11 @@ void Core::NetworkAccess::onDownloadFinished()
|
|||||||
err = "Couldn't prepare a directory for file";
|
err = "Couldn't prepare a directory for file";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path.size() > 0) {
|
if (path.size() > 0)
|
||||||
emit downloadFileComplete(dwn->messages, path);
|
emit downloadFileComplete(dwn->messages, path);
|
||||||
} else {
|
else
|
||||||
emit loadFileError(dwn->messages, "Error saving file " + url + "; " + err, false);
|
emit loadFileError(dwn->messages, "Error saving file " + url + "; " + err, false);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
dwn->reply->deleteLater();
|
dwn->reply->deleteLater();
|
||||||
delete dwn;
|
delete dwn;
|
||||||
@ -332,8 +319,7 @@ void Core::NetworkAccess::onDownloadFinished()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::NetworkAccess::startDownload(const std::list<Shared::MessageInfo>& msgs, const QString& url)
|
void Core::NetworkAccess::startDownload(const std::list<Shared::MessageInfo>& msgs, const QString& url) {
|
||||||
{
|
|
||||||
Transfer* dwn = new Transfer({msgs, 0, 0, true, "", url, 0});
|
Transfer* dwn = new Transfer({msgs, 0, 0, true, "", url, 0});
|
||||||
QNetworkRequest req(url);
|
QNetworkRequest req(url);
|
||||||
dwn->reply = manager->get(req);
|
dwn->reply = manager->get(req);
|
||||||
@ -349,8 +335,7 @@ void Core::NetworkAccess::startDownload(const std::list<Shared::MessageInfo>& ms
|
|||||||
emit loadFileProgress(dwn->messages, 0, false);
|
emit loadFileProgress(dwn->messages, 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::NetworkAccess::onUploadError(QNetworkReply::NetworkError code)
|
void Core::NetworkAccess::onUploadError(QNetworkReply::NetworkError code) {
|
||||||
{
|
|
||||||
QNetworkReply* rpl = static_cast<QNetworkReply*>(sender());
|
QNetworkReply* rpl = static_cast<QNetworkReply*>(sender());
|
||||||
QString url = rpl->url().toString();
|
QString url = rpl->url().toString();
|
||||||
std::map<QString, Transfer*>::const_iterator itr = uploads.find(url);
|
std::map<QString, Transfer*>::const_iterator itr = uploads.find(url);
|
||||||
@ -368,8 +353,7 @@ void Core::NetworkAccess::onUploadError(QNetworkReply::NetworkError code)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::NetworkAccess::onUploadFinished()
|
void Core::NetworkAccess::onUploadFinished() {
|
||||||
{
|
|
||||||
QNetworkReply* rpl = static_cast<QNetworkReply*>(sender());
|
QNetworkReply* rpl = static_cast<QNetworkReply*>(sender());
|
||||||
QString url = rpl->url().toString();
|
QString url = rpl->url().toString();
|
||||||
std::map<QString, Transfer*>::const_iterator itr = uploads.find(url);
|
std::map<QString, Transfer*>::const_iterator itr = uploads.find(url);
|
||||||
@ -389,21 +373,17 @@ void Core::NetworkAccess::onUploadFinished()
|
|||||||
|
|
||||||
// Copy {TEMPDIR}/squawk_img_attach_XXXXXX.png to Download folder
|
// Copy {TEMPDIR}/squawk_img_attach_XXXXXX.png to Download folder
|
||||||
bool copyResult = QFile::copy(upl->path, Shared::resolvePath(newPath));
|
bool copyResult = QFile::copy(upl->path, Shared::resolvePath(newPath));
|
||||||
|
if (copyResult)
|
||||||
if (copyResult) {
|
upl->path = newPath; // Change storage
|
||||||
// Change storage
|
else
|
||||||
upl->path = newPath;
|
|
||||||
} else {
|
|
||||||
err = "copying to " + newPath + " failed";
|
err = "copying to " + newPath + " failed";
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
err = "Couldn't prepare a directory for file";
|
err = "Couldn't prepare a directory for file";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err.size() != 0) {
|
if (err.size() != 0)
|
||||||
qDebug() << "failed to copy temporary upload file " << upl->path << " to download folder:" << err;
|
qDebug() << "failed to copy temporary upload file " << upl->path << " to download folder:" << err;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
storage.addFile(upl->messages, upl->url, upl->path);
|
storage.addFile(upl->messages, upl->url, upl->path);
|
||||||
emit uploadFileComplete(upl->messages, upl->url, upl->path);
|
emit uploadFileComplete(upl->messages, upl->url, upl->path);
|
||||||
@ -417,8 +397,7 @@ void Core::NetworkAccess::onUploadFinished()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::NetworkAccess::onUploadProgress(qint64 bytesReceived, qint64 bytesTotal)
|
void Core::NetworkAccess::onUploadProgress(qint64 bytesReceived, qint64 bytesTotal) {
|
||||||
{
|
|
||||||
QNetworkReply* rpl = static_cast<QNetworkReply*>(sender());
|
QNetworkReply* rpl = static_cast<QNetworkReply*>(sender());
|
||||||
QString url = rpl->url().toString();
|
QString url = rpl->url().toString();
|
||||||
std::map<QString, Transfer*>::const_iterator itr = uploads.find(url);
|
std::map<QString, Transfer*>::const_iterator itr = uploads.find(url);
|
||||||
@ -436,13 +415,12 @@ void Core::NetworkAccess::onUploadProgress(qint64 bytesReceived, qint64 bytesTot
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Core::NetworkAccess::getFileRemoteUrl(const QString& path)
|
QString Core::NetworkAccess::getFileRemoteUrl(const QString& path) {
|
||||||
{
|
|
||||||
QString p = Shared::squawkifyPath(path);
|
QString p = Shared::squawkifyPath(path);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
p = storage.getUrl(p);
|
p = storage.getUrl(p);
|
||||||
} catch (const Archive::NotFound& err) {
|
} catch (const LMDBAL::NotFound& err) {
|
||||||
p = "";
|
p = "";
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
throw;
|
throw;
|
||||||
@ -451,8 +429,13 @@ QString Core::NetworkAccess::getFileRemoteUrl(const QString& path)
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::NetworkAccess::uploadFile(const Shared::MessageInfo& info, const QString& path, const QUrl& put, const QUrl& get, const QMap<QString, QString> headers)
|
void Core::NetworkAccess::uploadFile(
|
||||||
{
|
const Shared::MessageInfo& info,
|
||||||
|
const QString& path,
|
||||||
|
const QUrl& put,
|
||||||
|
const QUrl& get,
|
||||||
|
const QMap<QString, QString> headers
|
||||||
|
) {
|
||||||
QFile* file = new QFile(path);
|
QFile* file = new QFile(path);
|
||||||
Transfer* upl = new Transfer({{info}, 0, 0, true, path, get.toString(), file});
|
Transfer* upl = new Transfer({{info}, 0, 0, true, path, get.toString(), file});
|
||||||
QNetworkRequest req(put);
|
QNetworkRequest req(put);
|
||||||
@ -479,22 +462,18 @@ void Core::NetworkAccess::uploadFile(const Shared::MessageInfo& info, const QStr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::NetworkAccess::registerFile(const QString& url, const QString& account, const QString& jid, const QString& id)
|
void Core::NetworkAccess::registerFile(const QString& url, const QString& account, const QString& jid, const QString& id) {
|
||||||
{
|
|
||||||
storage.addFile(url, account, jid, id);
|
storage.addFile(url, account, jid, id);
|
||||||
std::map<QString, Transfer*>::iterator itr = downloads.find(url);
|
std::map<QString, Transfer*>::iterator itr = downloads.find(url);
|
||||||
if (itr != downloads.end()) {
|
if (itr != downloads.end())
|
||||||
itr->second->messages.emplace_back(account, jid, id); //TODO notification is going to happen the next tick, is that okay?
|
itr->second->messages.emplace_back(account, jid, id); //TODO notification is going to happen the next tick, is that okay?
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::NetworkAccess::registerFile(const QString& url, const QString& path, const QString& account, const QString& jid, const QString& id)
|
void Core::NetworkAccess::registerFile(const QString& url, const QString& path, const QString& account, const QString& jid, const QString& id) {
|
||||||
{
|
|
||||||
storage.addFile(url, path, account, jid, id);
|
storage.addFile(url, path, account, jid, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Core::NetworkAccess::checkAndAddToUploading(const QString& acc, const QString& jid, const QString id, const QString path)
|
bool Core::NetworkAccess::checkAndAddToUploading(const QString& acc, const QString& jid, const QString id, const QString path) {
|
||||||
{
|
|
||||||
for (const std::pair<const QString, Transfer*>& pair : uploads) {
|
for (const std::pair<const QString, Transfer*>& pair : uploads) {
|
||||||
Transfer* info = pair.second;
|
Transfer* info = pair.second;
|
||||||
if (pair.second->path == path) {
|
if (pair.second->path == path) {
|
||||||
@ -516,8 +495,7 @@ bool Core::NetworkAccess::checkAndAddToUploading(const QString& acc, const QStri
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Core::NetworkAccess::prepareDirectory(const QString& jid)
|
QString Core::NetworkAccess::prepareDirectory(const QString& jid) {
|
||||||
{
|
|
||||||
QString path = currentPath;
|
QString path = currentPath;
|
||||||
QString addition;
|
QString addition;
|
||||||
if (jid.size() > 0) {
|
if (jid.size() > 0) {
|
||||||
@ -529,25 +507,23 @@ QString Core::NetworkAccess::prepareDirectory(const QString& jid)
|
|||||||
|
|
||||||
if (!location.exists()) {
|
if (!location.exists()) {
|
||||||
bool res = location.mkpath(path);
|
bool res = location.mkpath(path);
|
||||||
if (!res) {
|
if (!res)
|
||||||
return "";
|
return "";
|
||||||
} else {
|
else
|
||||||
return "squawk://" + addition;
|
return "squawk://" + addition;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return "squawk://" + addition;
|
return "squawk://" + addition;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Core::NetworkAccess::checkFileName(const QString& name, const QString& path)
|
QString Core::NetworkAccess::checkFileName(const QString& name, const QString& path) {
|
||||||
{
|
|
||||||
QStringList parts = name.split(".");
|
QStringList parts = name.split(".");
|
||||||
QString suffix("");
|
QString suffix("");
|
||||||
QStringList::const_iterator sItr = parts.begin();
|
QStringList::const_iterator sItr = parts.begin();
|
||||||
QString realName = *sItr;
|
QString realName = *sItr;
|
||||||
++sItr;
|
++sItr;
|
||||||
for (QStringList::const_iterator sEnd = parts.end(); sItr != sEnd; ++sItr) {
|
for (QStringList::const_iterator sEnd = parts.end(); sItr != sEnd; ++sItr)
|
||||||
suffix += "." + (*sItr);
|
suffix += "." + (*sItr);
|
||||||
}
|
|
||||||
QString postfix("");
|
QString postfix("");
|
||||||
QString resolvedPath = Shared::resolvePath(path);
|
QString resolvedPath = Shared::resolvePath(path);
|
||||||
QString count("");
|
QString count("");
|
||||||
@ -562,18 +538,15 @@ QString Core::NetworkAccess::checkFileName(const QString& name, const QString& p
|
|||||||
return path + QDir::separator() + realName + count + suffix;
|
return path + QDir::separator() + realName + count + suffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Core::NetworkAccess::addMessageAndCheckForPath(const QString& url, const QString& account, const QString& jid, const QString& id)
|
QString Core::NetworkAccess::addMessageAndCheckForPath(const QString& url, const QString& account, const QString& jid, const QString& id) {
|
||||||
{
|
|
||||||
return storage.addMessageAndCheckForPath(url, account, jid, id);
|
return storage.addMessageAndCheckForPath(url, account, jid, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<Shared::MessageInfo> Core::NetworkAccess::reportPathInvalid(const QString& path)
|
std::list<Shared::MessageInfo> Core::NetworkAccess::reportPathInvalid(const QString& path) {
|
||||||
{
|
|
||||||
return storage.deletedFile(path);
|
return storage.deletedFile(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::NetworkAccess::moveFilesDirectory(const QString& newPath)
|
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;
|
||||||
@ -582,8 +555,8 @@ void Core::NetworkAccess::moveFilesDirectory(const QString& newPath)
|
|||||||
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";
|
||||||
}
|
|
||||||
currentPath = newPath;
|
currentPath = newPath;
|
||||||
}
|
}
|
@ -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 CORE_NETWORKACCESS_H
|
#pragma once
|
||||||
#define CORE_NETWORKACCESS_H
|
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
@ -30,18 +29,13 @@
|
|||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
#include "storage/urlstorage.h"
|
#include <shared/pathcheck.h>
|
||||||
#include "shared/pathcheck.h"
|
#include "urlstorage.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
/**
|
|
||||||
* @todo write docs
|
|
||||||
*/
|
|
||||||
|
|
||||||
//TODO Need to describe how to get rid of records when file is no longer reachable;
|
//TODO Need to describe how to get rid of records when file is no longer reachable;
|
||||||
class NetworkAccess : public QObject
|
class NetworkAccess : public QObject {
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
struct Transfer;
|
struct Transfer;
|
||||||
public:
|
public:
|
||||||
@ -104,5 +98,3 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // CORE_NETWORKACCESS_H
|
|
252
core/components/urlstorage.cpp
Normal file
@ -0,0 +1,252 @@
|
|||||||
|
/*
|
||||||
|
* 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 <QStandardPaths>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include "urlstorage.h"
|
||||||
|
|
||||||
|
Core::UrlStorage::UrlStorage(const QString& p_name):
|
||||||
|
base(p_name),
|
||||||
|
urlToInfo(base.addStorage<QString, UrlInfo>("urlToInfo")),
|
||||||
|
pathToUrl(base.addStorage<QString, QString>("pathToUrl"))
|
||||||
|
{}
|
||||||
|
|
||||||
|
Core::UrlStorage::~UrlStorage() {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::UrlStorage::open() {
|
||||||
|
base.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::UrlStorage::close() {
|
||||||
|
base.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::UrlStorage::writeInfo(const QString& key, const Core::UrlStorage::UrlInfo& info, bool overwrite) {
|
||||||
|
LMDBAL::WriteTransaction txn = base.beginTransaction();
|
||||||
|
writeInfo(key, info, txn, overwrite);
|
||||||
|
txn.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::UrlStorage::writeInfo(const QString& key, const Core::UrlStorage::UrlInfo& info, const LMDBAL::WriteTransaction& txn, bool overwrite) {
|
||||||
|
if (overwrite)
|
||||||
|
urlToInfo->forceRecord(key, info, txn);
|
||||||
|
else
|
||||||
|
urlToInfo->addRecord(key, info, txn);
|
||||||
|
|
||||||
|
if (info.hasPath())
|
||||||
|
pathToUrl->forceRecord(info.getPath(), key, txn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::UrlStorage::addFile(const QString& url) {
|
||||||
|
addToInfo(url, "", "", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::UrlStorage::addFile(const QString& url, const QString& path) {
|
||||||
|
addToInfo(url, "", "", "", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::UrlStorage::addFile(const QString& url, const QString& account, const QString& jid, const QString& id) {
|
||||||
|
addToInfo(url, account, jid, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::UrlStorage::addFile(const QString& url, const QString& path, const QString& account, const QString& jid, const QString& id) {
|
||||||
|
addToInfo(url, account, jid, id, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::UrlStorage::addFile(const std::list<Shared::MessageInfo>& msgs, const QString& url, const QString& path) {
|
||||||
|
UrlInfo info (path, msgs);
|
||||||
|
writeInfo(url, info, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Core::UrlStorage::addMessageAndCheckForPath(const QString& url, const QString& account, const QString& jid, const QString& id){
|
||||||
|
return addToInfo(url, account, jid, id).getPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
Core::UrlStorage::UrlInfo Core::UrlStorage::addToInfo(
|
||||||
|
const QString& url,
|
||||||
|
const QString& account,
|
||||||
|
const QString& jid,
|
||||||
|
const QString& id,
|
||||||
|
const QString& path
|
||||||
|
) {
|
||||||
|
UrlInfo info;
|
||||||
|
LMDBAL::WriteTransaction txn = base.beginTransaction();
|
||||||
|
|
||||||
|
try {
|
||||||
|
urlToInfo->getRecord(url, info, txn);
|
||||||
|
} catch (const LMDBAL::NotFound& e) {}
|
||||||
|
|
||||||
|
bool pathChange = false;
|
||||||
|
bool listChange = false;
|
||||||
|
if (path != "-s") {
|
||||||
|
if (info.getPath() != path) {
|
||||||
|
info.setPath(path);
|
||||||
|
pathChange = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (account.size() > 0 && jid.size() > 0 && id.size() > 0)
|
||||||
|
listChange = info.addMessage(account, jid, id);
|
||||||
|
|
||||||
|
if (pathChange || listChange) {
|
||||||
|
writeInfo(url, info, txn, true);
|
||||||
|
txn.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<Shared::MessageInfo> Core::UrlStorage::setPath(const QString& url, const QString& path) {
|
||||||
|
std::list<Shared::MessageInfo> list;
|
||||||
|
LMDBAL::WriteTransaction txn = base.beginTransaction();
|
||||||
|
UrlInfo info;
|
||||||
|
|
||||||
|
try {
|
||||||
|
urlToInfo->getRecord(url, info, txn);
|
||||||
|
info.getMessages(list);
|
||||||
|
} catch (const LMDBAL::NotFound& e) {}
|
||||||
|
|
||||||
|
info.setPath(path);
|
||||||
|
writeInfo(url, info, txn, true);
|
||||||
|
txn.commit();
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<Shared::MessageInfo> Core::UrlStorage::removeFile(const QString& url) {
|
||||||
|
std::list<Shared::MessageInfo> list;
|
||||||
|
LMDBAL::WriteTransaction txn = base.beginTransaction();
|
||||||
|
UrlInfo info;
|
||||||
|
|
||||||
|
urlToInfo->getRecord(url, info, txn);
|
||||||
|
urlToInfo->removeRecord(url, txn);
|
||||||
|
info.getMessages(list);
|
||||||
|
|
||||||
|
if (info.hasPath())
|
||||||
|
pathToUrl->removeRecord(info.getPath(), txn);
|
||||||
|
|
||||||
|
txn.commit();
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<Shared::MessageInfo> Core::UrlStorage::deletedFile(const QString& path) {
|
||||||
|
std::list<Shared::MessageInfo> list;
|
||||||
|
LMDBAL::WriteTransaction txn = base.beginTransaction();
|
||||||
|
|
||||||
|
QString url = pathToUrl->getRecord(path, txn);
|
||||||
|
pathToUrl->removeRecord(path, txn);
|
||||||
|
|
||||||
|
UrlInfo info = urlToInfo->getRecord(url, txn);
|
||||||
|
info.getMessages(list);
|
||||||
|
info.setPath(QString());
|
||||||
|
urlToInfo->changeRecord(url, info, txn);
|
||||||
|
|
||||||
|
txn.commit();
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Core::UrlStorage::getUrl(const QString& path) {
|
||||||
|
return pathToUrl->getRecord(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<QString, std::list<Shared::MessageInfo>> Core::UrlStorage::getPath(const QString& url) {
|
||||||
|
UrlInfo info = urlToInfo->getRecord(url);
|
||||||
|
std::list<Shared::MessageInfo> container;
|
||||||
|
info.getMessages(container);
|
||||||
|
return std::make_pair(info.getPath(), container);
|
||||||
|
}
|
||||||
|
|
||||||
|
Core::UrlStorage::UrlInfo::UrlInfo():
|
||||||
|
localPath(),
|
||||||
|
messages() {}
|
||||||
|
|
||||||
|
Core::UrlStorage::UrlInfo::UrlInfo(const QString& path):
|
||||||
|
localPath(path),
|
||||||
|
messages() {}
|
||||||
|
|
||||||
|
Core::UrlStorage::UrlInfo::UrlInfo(const QString& path, const std::list<Shared::MessageInfo>& msgs):
|
||||||
|
localPath(path),
|
||||||
|
messages(msgs) {}
|
||||||
|
|
||||||
|
Core::UrlStorage::UrlInfo::~UrlInfo() {}
|
||||||
|
|
||||||
|
bool Core::UrlStorage::UrlInfo::addMessage(const QString& acc, const QString& jid, const QString& id) {
|
||||||
|
for (const Shared::MessageInfo& info : messages) {
|
||||||
|
if (info.account == acc && info.jid == jid && info.messageId == id)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
messages.emplace_back(acc, jid, id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::UrlStorage::UrlInfo::serialize(QDataStream& data) const {
|
||||||
|
data << localPath;
|
||||||
|
std::list<Shared::MessageInfo>::size_type size = messages.size();
|
||||||
|
data << quint32(size);
|
||||||
|
for (const Shared::MessageInfo& info : messages) {
|
||||||
|
data << info.account;
|
||||||
|
data << info.jid;
|
||||||
|
data << info.messageId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QDataStream & operator << (QDataStream& in, const Core::UrlStorage::UrlInfo& info) {
|
||||||
|
info.serialize(in);
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDataStream & operator >> (QDataStream& out, Core::UrlStorage::UrlInfo& info) {
|
||||||
|
info.deserialize(out);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::UrlStorage::UrlInfo::deserialize(QDataStream& data) {
|
||||||
|
data >> localPath;
|
||||||
|
quint32 size;
|
||||||
|
data >> size;
|
||||||
|
for (quint32 i = 0; i < size; ++i) {
|
||||||
|
messages.emplace_back();
|
||||||
|
Shared::MessageInfo& info = messages.back();
|
||||||
|
data >> info.account;
|
||||||
|
data >> info.jid;
|
||||||
|
data >> info.messageId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::UrlStorage::UrlInfo::getMessages(std::list<Shared::MessageInfo>& container) const {
|
||||||
|
for (const Shared::MessageInfo& info : messages)
|
||||||
|
container.emplace_back(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Core::UrlStorage::UrlInfo::getPath() const {
|
||||||
|
return localPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Core::UrlStorage::UrlInfo::hasPath() const {
|
||||||
|
return localPath.size() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::UrlStorage::UrlInfo::setPath(const QString& path) {
|
||||||
|
localPath = path;
|
||||||
|
}
|
@ -16,25 +16,23 @@
|
|||||||
* 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 CORE_URLSTORAGE_H
|
#pragma once
|
||||||
#define CORE_URLSTORAGE_H
|
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QDataStream>
|
#include <QDataStream>
|
||||||
#include <lmdb.h>
|
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
#include "archive.h"
|
#include <storage.h>
|
||||||
|
|
||||||
#include <shared/messageinfo.h>
|
#include <shared/messageinfo.h>
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
/**
|
class UrlStorage {
|
||||||
* @todo write docs
|
public:
|
||||||
*/
|
|
||||||
class UrlStorage
|
|
||||||
{
|
|
||||||
class UrlInfo;
|
class UrlInfo;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
UrlStorage(const QString& name);
|
UrlStorage(const QString& name);
|
||||||
~UrlStorage();
|
~UrlStorage();
|
||||||
@ -55,20 +53,16 @@ public:
|
|||||||
std::pair<QString, std::list<Shared::MessageInfo>> getPath(const QString& url);
|
std::pair<QString, std::list<Shared::MessageInfo>> getPath(const QString& url);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString name;
|
LMDBAL::Base base;
|
||||||
bool opened;
|
LMDBAL::Storage<QString, UrlInfo>* urlToInfo;
|
||||||
MDB_env* environment;
|
LMDBAL::Storage<QString, QString>* pathToUrl;
|
||||||
MDB_dbi base;
|
|
||||||
MDB_dbi map;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void writeInfo(const QString& key, const UrlInfo& info, bool overwrite = false);
|
void writeInfo(const QString& key, const UrlInfo& info, bool overwrite = false);
|
||||||
void writeInfo(const QString& key, const UrlInfo& info, MDB_txn* txn, bool overwrite = false);
|
void writeInfo(const QString& key, const UrlInfo& info, const LMDBAL::WriteTransaction& txn, bool overwrite = false);
|
||||||
void readInfo(const QString& key, UrlInfo& info);
|
|
||||||
void readInfo(const QString& key, UrlInfo& info, MDB_txn* txn);
|
|
||||||
UrlInfo addToInfo(const QString& url, const QString& account, const QString& jid, const QString& id, const QString& path = "-s");
|
UrlInfo addToInfo(const QString& url, const QString& account, const QString& jid, const QString& id, const QString& path = "-s");
|
||||||
|
|
||||||
private:
|
public:
|
||||||
class UrlInfo {
|
class UrlInfo {
|
||||||
public:
|
public:
|
||||||
UrlInfo(const QString& path);
|
UrlInfo(const QString& path);
|
||||||
@ -96,4 +90,5 @@ private:
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // CORE_URLSTORAGE_H
|
QDataStream& operator >> (QDataStream &in, Core::UrlStorage::UrlInfo& info);
|
||||||
|
QDataStream& operator << (QDataStream &out, const Core::UrlStorage::UrlInfo& info);
|
@ -42,57 +42,48 @@ Core::Conference::Conference(const QString& p_jid, const QString& p_account, boo
|
|||||||
connect(room, &QXmppMucRoom::error, this, &Conference::onRoomError);
|
connect(room, &QXmppMucRoom::error, this, &Conference::onRoomError);
|
||||||
|
|
||||||
room->setNickName(nick);
|
room->setNickName(nick);
|
||||||
if (autoJoin) {
|
if (autoJoin)
|
||||||
room->join();
|
room->join();
|
||||||
}
|
|
||||||
|
|
||||||
archive->readAllResourcesAvatars(exParticipants);
|
archive->readAllResourcesAvatars(exParticipants);
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::Conference::~Conference()
|
Core::Conference::~Conference(){
|
||||||
{
|
if (joined)
|
||||||
if (joined) {
|
|
||||||
room->leave();
|
room->leave();
|
||||||
}
|
|
||||||
room->deleteLater();
|
room->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Core::Conference::getNick() const
|
QString Core::Conference::getNick() const {
|
||||||
{
|
|
||||||
return nick;
|
return nick;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Core::Conference::getAutoJoin()
|
bool Core::Conference::getAutoJoin() const {
|
||||||
{
|
|
||||||
return autoJoin;
|
return autoJoin;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Core::Conference::getJoined() const
|
bool Core::Conference::getJoined() const {
|
||||||
{
|
|
||||||
return joined;
|
return joined;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Conference::setJoined(bool p_joined)
|
void Core::Conference::setJoined(bool p_joined) {
|
||||||
{
|
|
||||||
if (joined != p_joined) {
|
if (joined != p_joined) {
|
||||||
if (p_joined) {
|
if (p_joined)
|
||||||
room->join();
|
room->join();
|
||||||
} else {
|
else
|
||||||
room->leave();
|
room->leave();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Conference::setAutoJoin(bool p_autoJoin)
|
void Core::Conference::setAutoJoin(bool p_autoJoin) {
|
||||||
{
|
|
||||||
if (autoJoin != p_autoJoin) {
|
if (autoJoin != p_autoJoin) {
|
||||||
autoJoin = p_autoJoin;
|
autoJoin = p_autoJoin;
|
||||||
emit autoJoinChanged(autoJoin);
|
emit autoJoinChanged(autoJoin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Conference::setNick(const QString& p_nick)
|
void Core::Conference::setNick(const QString& p_nick) {
|
||||||
{
|
|
||||||
if (nick != p_nick) {
|
if (nick != p_nick) {
|
||||||
if (joined) {
|
if (joined) {
|
||||||
room->setNickName(p_nick);
|
room->setNickName(p_nick);
|
||||||
@ -103,105 +94,99 @@ void Core::Conference::setNick(const QString& p_nick)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Conference::onRoomJoined()
|
void Core::Conference::onRoomJoined() {
|
||||||
{
|
|
||||||
joined = true;
|
joined = true;
|
||||||
emit joinedChanged(joined);
|
emit joinedChanged(joined);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Conference::onRoomLeft()
|
void Core::Conference::onRoomLeft() {
|
||||||
{
|
|
||||||
joined = false;
|
joined = false;
|
||||||
emit joinedChanged(joined);
|
emit joinedChanged(joined);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Conference::onRoomNameChanged(const QString& p_name)
|
void Core::Conference::onRoomNameChanged(const QString& p_name) {
|
||||||
{
|
|
||||||
setName(p_name);
|
setName(p_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Conference::onRoomNickNameChanged(const QString& p_nick)
|
void Core::Conference::onRoomNickNameChanged(const QString& p_nick) {
|
||||||
{
|
|
||||||
if (p_nick != nick) {
|
if (p_nick != nick) {
|
||||||
nick = p_nick;
|
nick = p_nick;
|
||||||
emit nickChanged(nick);
|
emit nickChanged(nick);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Conference::onRoomError(const QXmppStanza::Error& err)
|
void Core::Conference::onRoomError(const QXmppStanza::Error& err) {
|
||||||
{
|
|
||||||
qDebug() << "MUC" << jid << "error:" << err.text();
|
qDebug() << "MUC" << jid << "error:" << err.text();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Conference::onRoomParticipantAdded(const QString& p_name)
|
void Core::Conference::onRoomParticipantAdded(const QString& p_name) {
|
||||||
{
|
|
||||||
QStringList comps = p_name.split("/");
|
QStringList comps = p_name.split("/");
|
||||||
QString resource = comps.back();
|
QString resource = comps.back();
|
||||||
QXmppPresence pres = room->participantPresence(p_name);
|
QXmppPresence pres = room->participantPresence(p_name);
|
||||||
QXmppMucItem mi = pres.mucItem();
|
QXmppMucItem mi = pres.mucItem();
|
||||||
if (resource == jid) {
|
if (resource == jid)
|
||||||
resource = "";
|
resource = "";
|
||||||
}
|
|
||||||
|
|
||||||
std::map<QString, Archive::AvatarInfo>::const_iterator itr = exParticipants.find(resource);
|
std::map<QString, Archive::AvatarInfo>::const_iterator itr = exParticipants.find(resource);
|
||||||
bool hasAvatar = itr != exParticipants.end();
|
bool hasAvatar = itr != exParticipants.end();
|
||||||
|
|
||||||
if (resource.size() > 0) {
|
if (resource.size() > 0) {
|
||||||
QDateTime lastInteraction = pres.lastUserInteraction();
|
QDateTime lastInteraction = pres.lastUserInteraction();
|
||||||
if (!lastInteraction.isValid()) {
|
if (!lastInteraction.isValid())
|
||||||
lastInteraction = QDateTime::currentDateTimeUtc();
|
lastInteraction = QDateTime::currentDateTimeUtc();
|
||||||
}
|
|
||||||
|
|
||||||
QMap<QString, QVariant> cData = {
|
QMap<QString, QVariant> cData = {
|
||||||
{"lastActivity", lastInteraction},
|
{"lastActivity", lastInteraction},
|
||||||
{"availability", pres.availableStatusType()},
|
{"availability", pres.availableStatusType()},
|
||||||
{"status", pres.statusText()},
|
{"status", pres.statusText()},
|
||||||
{"affiliation", mi.affiliation()},
|
{"affiliation", mi.affiliation()},
|
||||||
{"role", mi.role()}
|
{"role", mi.role()},
|
||||||
|
{"client", QVariant::fromValue(
|
||||||
|
Shared::ClientId(
|
||||||
|
pres.capabilityNode(),
|
||||||
|
pres.capabilityVer().toBase64(),
|
||||||
|
pres.capabilityHash())
|
||||||
|
)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
careAboutAvatar(hasAvatar, itr->second, cData, resource, p_name);
|
||||||
if (hasAvatar) {
|
|
||||||
if (itr->second.autogenerated) {
|
|
||||||
cData.insert("avatarState", static_cast<uint>(Shared::Avatar::valid));
|
|
||||||
} else {
|
|
||||||
cData.insert("avatarState", static_cast<uint>(Shared::Avatar::autocreated));
|
|
||||||
}
|
|
||||||
cData.insert("avatarPath", avatarPath(resource) + "." + itr->second.type);
|
|
||||||
} else {
|
|
||||||
cData.insert("avatarState", static_cast<uint>(Shared::Avatar::empty));
|
|
||||||
cData.insert("avatarPath", "");
|
|
||||||
requestVCard(p_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
emit addParticipant(resource, cData);
|
emit addParticipant(resource, cData);
|
||||||
}
|
|
||||||
|
|
||||||
|
if (!hasAvatar) // because this way vCard is already requested, no need to handle possible avatar update
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
handlePossibleAvatarUpdate(pres, resource, hasAvatar, itr->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::Conference::handlePossibleAvatarUpdate (
|
||||||
|
const QXmppPresence& pres,
|
||||||
|
const QString& resource,
|
||||||
|
bool hasAvatar,
|
||||||
|
const Archive::AvatarInfo& info
|
||||||
|
) {
|
||||||
switch (pres.vCardUpdateType()) {
|
switch (pres.vCardUpdateType()) {
|
||||||
case QXmppPresence::VCardUpdateNone: //this presence has nothing to do with photo
|
case QXmppPresence::VCardUpdateNone: //this presence has nothing to do with photo
|
||||||
break;
|
break;
|
||||||
case QXmppPresence::VCardUpdateNotReady: //let's say the photo didn't change here
|
case QXmppPresence::VCardUpdateNotReady: //let's say the photo didn't change here
|
||||||
break;
|
break;
|
||||||
case QXmppPresence::VCardUpdateNoPhoto: { //there is no photo, need to drop if any
|
case QXmppPresence::VCardUpdateNoPhoto: //there is no photo, need to drop if any
|
||||||
if (!hasAvatar || !itr->second.autogenerated) {
|
if (!hasAvatar || !info.autogenerated)
|
||||||
setAutoGeneratedAvatar(resource);
|
setAutoGeneratedAvatar(resource);
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case QXmppPresence::VCardUpdateValidPhoto:{ //there is a photo, need to load
|
case QXmppPresence::VCardUpdateValidPhoto: //there is a photo, need to load
|
||||||
if (hasAvatar) {
|
if (hasAvatar) {
|
||||||
if (itr->second.autogenerated || itr->second.hash != pres.photoHash()) {
|
if (info.autogenerated || info.hash != pres.photoHash())
|
||||||
emit requestVCard(p_name);
|
emit requestVCard(pres.from());
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
emit requestVCard(p_name);
|
emit requestVCard(pres.from());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Conference::onRoomParticipantChanged(const QString& p_name)
|
void Core::Conference::onRoomParticipantChanged(const QString& p_name) {
|
||||||
{
|
|
||||||
QStringList comps = p_name.split("/");
|
QStringList comps = p_name.split("/");
|
||||||
QString resource = comps.back();
|
QString resource = comps.back();
|
||||||
QXmppPresence pres = room->participantPresence(p_name);
|
QXmppPresence pres = room->participantPresence(p_name);
|
||||||
@ -209,22 +194,27 @@ void Core::Conference::onRoomParticipantChanged(const QString& p_name)
|
|||||||
handlePresence(pres);
|
handlePresence(pres);
|
||||||
if (resource != jid) {
|
if (resource != jid) {
|
||||||
QDateTime lastInteraction = pres.lastUserInteraction();
|
QDateTime lastInteraction = pres.lastUserInteraction();
|
||||||
if (!lastInteraction.isValid()) {
|
if (!lastInteraction.isValid())
|
||||||
lastInteraction = QDateTime::currentDateTimeUtc();
|
lastInteraction = QDateTime::currentDateTimeUtc();
|
||||||
}
|
|
||||||
|
|
||||||
emit changeParticipant(resource, {
|
emit changeParticipant(resource, {
|
||||||
{"lastActivity", lastInteraction},
|
{"lastActivity", lastInteraction},
|
||||||
{"availability", pres.availableStatusType()},
|
{"availability", pres.availableStatusType()},
|
||||||
{"status", pres.statusText()},
|
{"status", pres.statusText()},
|
||||||
{"affiliation", mi.affiliation()},
|
{"affiliation", mi.affiliation()},
|
||||||
{"role", mi.role()}
|
{"role", mi.role()},
|
||||||
|
{"client", QVariant::fromValue(
|
||||||
|
Shared::ClientId(
|
||||||
|
pres.capabilityNode(),
|
||||||
|
pres.capabilityVer().toBase64(),
|
||||||
|
pres.capabilityHash())
|
||||||
|
)
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Conference::onRoomParticipantRemoved(const QString& p_name)
|
void Core::Conference::onRoomParticipantRemoved(const QString& p_name) {
|
||||||
{
|
|
||||||
QStringList comps = p_name.split("/");
|
QStringList comps = p_name.split("/");
|
||||||
QString resource = comps.back();
|
QString resource = comps.back();
|
||||||
if (resource == jid) {
|
if (resource == jid) {
|
||||||
@ -234,69 +224,40 @@ void Core::Conference::onRoomParticipantRemoved(const QString& p_name)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Core::Conference::getSubject() const
|
QString Core::Conference::getSubject() const {
|
||||||
{
|
if (joined)
|
||||||
if (joined) {
|
|
||||||
return room->subject();
|
return room->subject();
|
||||||
} else {
|
else
|
||||||
return "";
|
return "";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Conference::onRoomSubjectChanged(const QString& p_name)
|
void Core::Conference::onRoomSubjectChanged(const QString& p_name) {
|
||||||
{
|
|
||||||
emit subjectChanged(p_name);
|
emit subjectChanged(p_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Conference::handlePresence(const QXmppPresence& pres)
|
void Core::Conference::handlePresence(const QXmppPresence& pres) {
|
||||||
{
|
|
||||||
QString id = pres.from();
|
QString id = pres.from();
|
||||||
QStringList comps = id.split("/");
|
QStringList comps = id.split("/");
|
||||||
QString jid = comps.front();
|
QString jid = comps.front();
|
||||||
QString resource("");
|
QString resource("");
|
||||||
if (comps.size() > 1) {
|
if (comps.size() > 1)
|
||||||
resource = comps.back();
|
resource = comps.back();
|
||||||
}
|
|
||||||
|
|
||||||
switch (pres.vCardUpdateType()) {
|
|
||||||
case QXmppPresence::VCardUpdateNone: //this presence has nothing to do with photo
|
|
||||||
break;
|
|
||||||
case QXmppPresence::VCardUpdateNotReady: //let's say the photo didn't change here
|
|
||||||
break;
|
|
||||||
case QXmppPresence::VCardUpdateNoPhoto: { //there is no photo, need to drop if any
|
|
||||||
Archive::AvatarInfo info;
|
Archive::AvatarInfo info;
|
||||||
bool hasAvatar = readAvatarInfo(info, resource);
|
bool hasAvatar = readAvatarInfo(info, resource);
|
||||||
if (!hasAvatar || !info.autogenerated) {
|
handlePossibleAvatarUpdate(pres, resource, hasAvatar, info);
|
||||||
setAutoGeneratedAvatar(resource);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case QXmppPresence::VCardUpdateValidPhoto:{ //there is a photo, need to load
|
|
||||||
Archive::AvatarInfo info;
|
|
||||||
bool hasAvatar = readAvatarInfo(info, resource);
|
|
||||||
if (hasAvatar) {
|
|
||||||
if (info.autogenerated || info.hash != pres.photoHash()) {
|
|
||||||
emit requestVCard(id);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
emit requestVCard(id);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Core::Conference::setAutoGeneratedAvatar(const QString& resource)
|
bool Core::Conference::setAutoGeneratedAvatar(const QString& resource) {
|
||||||
{
|
|
||||||
Archive::AvatarInfo newInfo;
|
Archive::AvatarInfo newInfo;
|
||||||
bool result = RosterItem::setAutoGeneratedAvatar(newInfo, resource);
|
bool result = RosterItem::setAutoGeneratedAvatar(newInfo, resource);
|
||||||
if (result && resource.size() != 0) {
|
if (result && resource.size() != 0) {
|
||||||
std::map<QString, Archive::AvatarInfo>::iterator itr = exParticipants.find(resource);
|
std::map<QString, Archive::AvatarInfo>::iterator itr = exParticipants.find(resource);
|
||||||
if (itr == exParticipants.end()) {
|
if (itr == exParticipants.end())
|
||||||
exParticipants.insert(std::make_pair(resource, newInfo));
|
exParticipants.insert(std::make_pair(resource, newInfo));
|
||||||
} else {
|
else
|
||||||
itr->second = newInfo;
|
itr->second = newInfo;
|
||||||
}
|
|
||||||
emit changeParticipant(resource, {
|
emit changeParticipant(resource, {
|
||||||
{"avatarState", static_cast<uint>(Shared::Avatar::autocreated)},
|
{"avatarState", static_cast<uint>(Shared::Avatar::autocreated)},
|
||||||
{"avatarPath", avatarPath(resource) + "." + newInfo.type}
|
{"avatarPath", avatarPath(resource) + "." + newInfo.type}
|
||||||
@ -306,17 +267,15 @@ bool Core::Conference::setAutoGeneratedAvatar(const QString& resource)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Core::Conference::setAvatar(const QByteArray& data, Archive::AvatarInfo& info, const QString& resource)
|
bool Core::Conference::setAvatar(const QByteArray& data, Archive::AvatarInfo& info, const QString& resource) {
|
||||||
{
|
|
||||||
bool result = RosterItem::setAvatar(data, info, resource);
|
bool result = RosterItem::setAvatar(data, info, resource);
|
||||||
if (result && resource.size() != 0) {
|
if (result && resource.size() != 0) {
|
||||||
if (data.size() > 0) {
|
if (data.size() > 0) {
|
||||||
std::map<QString, Archive::AvatarInfo>::iterator itr = exParticipants.find(resource);
|
std::map<QString, Archive::AvatarInfo>::iterator itr = exParticipants.find(resource);
|
||||||
if (itr == exParticipants.end()) {
|
if (itr == exParticipants.end())
|
||||||
exParticipants.insert(std::make_pair(resource, info));
|
exParticipants.insert(std::make_pair(resource, info));
|
||||||
} else {
|
else
|
||||||
itr->second = info;
|
itr->second = info;
|
||||||
}
|
|
||||||
|
|
||||||
emit changeParticipant(resource, {
|
emit changeParticipant(resource, {
|
||||||
{"avatarState", static_cast<uint>(Shared::Avatar::autocreated)},
|
{"avatarState", static_cast<uint>(Shared::Avatar::autocreated)},
|
||||||
@ -324,9 +283,8 @@ bool Core::Conference::setAvatar(const QByteArray& data, Archive::AvatarInfo& in
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
std::map<QString, Archive::AvatarInfo>::iterator itr = exParticipants.find(resource);
|
std::map<QString, Archive::AvatarInfo>::iterator itr = exParticipants.find(resource);
|
||||||
if (itr != exParticipants.end()) {
|
if (itr != exParticipants.end())
|
||||||
exParticipants.erase(itr);
|
exParticipants.erase(itr);
|
||||||
}
|
|
||||||
|
|
||||||
emit changeParticipant(resource, {
|
emit changeParticipant(resource, {
|
||||||
{"avatarState", static_cast<uint>(Shared::Avatar::empty)},
|
{"avatarState", static_cast<uint>(Shared::Avatar::empty)},
|
||||||
@ -339,25 +297,31 @@ bool Core::Conference::setAvatar(const QByteArray& data, Archive::AvatarInfo& in
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Shared::VCard Core::Conference::handleResponseVCard(const QXmppVCardIq& card, const QString &resource)
|
void Core::Conference::handleResponseVCard(const QXmppVCardIq& card, const QString &resource, Shared::VCard& out) {
|
||||||
{
|
RosterItem::handleResponseVCard(card, resource, out);
|
||||||
Shared::VCard result = RosterItem::handleResponseVCard(card, resource);
|
if (resource.size() > 0)
|
||||||
|
|
||||||
if (resource.size() > 0) {
|
|
||||||
emit changeParticipant(resource, {
|
emit changeParticipant(resource, {
|
||||||
{"avatarState", static_cast<uint>(result.getAvatarType())},
|
{"avatarState", static_cast<uint>(out.getAvatarType())},
|
||||||
{"avatarPath", result.getAvatarPath()}
|
{"avatarPath", out.getAvatarPath()}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QMap<QString, QVariant> Core::Conference::getAllAvatars() const
|
QMap<QString, QVariant> Core::Conference::getAllAvatars() const {
|
||||||
{
|
|
||||||
QMap<QString, QVariant> result;
|
QMap<QString, QVariant> result;
|
||||||
for (const std::pair<const QString, Archive::AvatarInfo>& pair : exParticipants) {
|
for (const std::pair<const QString, Archive::AvatarInfo>& pair : exParticipants)
|
||||||
result.insert(pair.first, avatarPath(pair.first) + "." + pair.second.type);
|
result.insert(pair.first, avatarPath(pair.first) + "." + pair.second.type);
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QMap<QString, QVariant> Core::Conference::getInfo() const {
|
||||||
|
QMap<QString, QVariant> data = RosterItem::getInfo();
|
||||||
|
|
||||||
|
data.insert("autoJoin", getAutoJoin());
|
||||||
|
data.insert("joined", getJoined());
|
||||||
|
data.insert("nick", getNick());
|
||||||
|
data.insert("avatars", getAllAvatars());
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -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 CORE_CONFERENCE_H
|
#pragma once
|
||||||
#define CORE_CONFERENCE_H
|
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
|
||||||
@ -26,16 +25,11 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
#include "rosteritem.h"
|
#include "rosteritem.h"
|
||||||
#include "shared/global.h"
|
#include <shared/global.h>
|
||||||
|
#include <shared/clientid.h>
|
||||||
|
|
||||||
namespace Core
|
namespace Core {
|
||||||
{
|
class Conference : public RosterItem {
|
||||||
|
|
||||||
/**
|
|
||||||
* @todo write docs
|
|
||||||
*/
|
|
||||||
class Conference : public RosterItem
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
Conference(const QString& p_jid, const QString& p_account, bool p_autoJoin, const QString& p_name, const QString& p_nick, QXmppMucRoom* p_room);
|
Conference(const QString& p_jid, const QString& p_account, bool p_autoJoin, const QString& p_name, const QString& p_nick, QXmppMucRoom* p_room);
|
||||||
@ -48,12 +42,13 @@ public:
|
|||||||
bool getJoined() const;
|
bool getJoined() const;
|
||||||
void setJoined(bool p_joined);
|
void setJoined(bool p_joined);
|
||||||
|
|
||||||
bool getAutoJoin();
|
bool getAutoJoin() const;
|
||||||
void setAutoJoin(bool p_autoJoin);
|
void setAutoJoin(bool p_autoJoin);
|
||||||
void handlePresence(const QXmppPresence & pres) override;
|
void handlePresence(const QXmppPresence & pres) override;
|
||||||
bool setAutoGeneratedAvatar(const QString& resource = "") override;
|
bool setAutoGeneratedAvatar(const QString& resource = "") override;
|
||||||
Shared::VCard handleResponseVCard(const QXmppVCardIq & card, const QString &resource) override;
|
void handleResponseVCard(const QXmppVCardIq & card, const QString &resource, Shared::VCard& out) override;
|
||||||
QMap<QString, QVariant> getAllAvatars() const;
|
QMap<QString, QVariant> getAllAvatars() const;
|
||||||
|
QMap<QString, QVariant> getInfo() const override;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void nickChanged(const QString& nick);
|
void nickChanged(const QString& nick);
|
||||||
@ -67,6 +62,14 @@ signals:
|
|||||||
protected:
|
protected:
|
||||||
bool setAvatar(const QByteArray &data, Archive::AvatarInfo& info, const QString &resource = "") override;
|
bool setAvatar(const QByteArray &data, Archive::AvatarInfo& info, const QString &resource = "") override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void handlePossibleAvatarUpdate(
|
||||||
|
const QXmppPresence& pres,
|
||||||
|
const QString& resource,
|
||||||
|
bool hasAvatar,
|
||||||
|
const Archive::AvatarInfo& info
|
||||||
|
);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString nick;
|
QString nick;
|
||||||
QXmppMucRoom* room;
|
QXmppMucRoom* room;
|
||||||
@ -89,5 +92,3 @@ private slots:
|
|||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // CORE_CONFERENCE_H
|
|
||||||
|
@ -22,55 +22,49 @@
|
|||||||
Core::Contact::Contact(const QString& pJid, const QString& account, QObject* parent):
|
Core::Contact::Contact(const QString& pJid, const QString& account, QObject* parent):
|
||||||
RosterItem(pJid, account, parent),
|
RosterItem(pJid, account, parent),
|
||||||
groups(),
|
groups(),
|
||||||
subscriptionState(Shared::SubscriptionState::unknown)
|
subscriptionState(Shared::SubscriptionState::unknown),
|
||||||
{
|
pep(Shared::Support::unknown)
|
||||||
}
|
|
||||||
|
|
||||||
Core::Contact::~Contact()
|
#ifdef WITH_OMEMO
|
||||||
{
|
,omemoBundles(Shared::Possible::unknown)
|
||||||
}
|
#endif
|
||||||
|
{}
|
||||||
|
|
||||||
QSet<QString> Core::Contact::getGroups() const
|
Core::Contact::~Contact() {}
|
||||||
{
|
|
||||||
|
QSet<QString> Core::Contact::getGroups() const {
|
||||||
return groups;
|
return groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int Core::Contact::groupsCount() const
|
unsigned int Core::Contact::groupsCount() const {
|
||||||
{
|
|
||||||
return groups.size();
|
return groups.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Contact::setGroups(const QSet<QString>& set)
|
void Core::Contact::setGroups(const QSet<QString>& set) {
|
||||||
{
|
|
||||||
QSet<QString> toRemove = groups - set;
|
QSet<QString> toRemove = groups - set;
|
||||||
QSet<QString> toAdd = set - groups;
|
QSet<QString> toAdd = set - groups;
|
||||||
|
|
||||||
groups = set;
|
groups = set;
|
||||||
|
|
||||||
for (QSet<QString>::iterator itr = toRemove.begin(), end = toRemove.end(); itr != end; ++itr) {
|
for (const QString& group : toRemove)
|
||||||
emit groupRemoved(*itr);
|
emit groupRemoved(group);
|
||||||
}
|
|
||||||
|
|
||||||
for (QSet<QString>::iterator itr = toAdd.begin(), end = toAdd.end(); itr != end; ++itr) {
|
for (const QString& group : toAdd)
|
||||||
emit groupAdded(*itr);
|
emit groupAdded(group);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Shared::SubscriptionState Core::Contact::getSubscriptionState() const
|
Shared::SubscriptionState Core::Contact::getSubscriptionState() const {
|
||||||
{
|
|
||||||
return subscriptionState;
|
return subscriptionState;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Contact::setSubscriptionState(Shared::SubscriptionState state)
|
void Core::Contact::setSubscriptionState(Shared::SubscriptionState state) {
|
||||||
{
|
|
||||||
if (subscriptionState != state) {
|
if (subscriptionState != state) {
|
||||||
subscriptionState = state;
|
subscriptionState = state;
|
||||||
emit subscriptionStateChanged(subscriptionState);
|
emit subscriptionStateChanged(subscriptionState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Contact::handlePresence(const QXmppPresence& pres)
|
void Core::Contact::handlePresence(const QXmppPresence& pres) {
|
||||||
{
|
|
||||||
switch (pres.vCardUpdateType()) {
|
switch (pres.vCardUpdateType()) {
|
||||||
case QXmppPresence::VCardUpdateNone: //this presence has nothing to do with photo
|
case QXmppPresence::VCardUpdateNone: //this presence has nothing to do with photo
|
||||||
break;
|
break;
|
||||||
@ -79,18 +73,17 @@ void Core::Contact::handlePresence(const QXmppPresence& pres)
|
|||||||
case QXmppPresence::VCardUpdateNoPhoto: { //there is no photo, need to drop if any
|
case QXmppPresence::VCardUpdateNoPhoto: { //there is no photo, need to drop if any
|
||||||
Archive::AvatarInfo info;
|
Archive::AvatarInfo info;
|
||||||
bool hasAvatar = readAvatarInfo(info);
|
bool hasAvatar = readAvatarInfo(info);
|
||||||
if (!hasAvatar || !info.autogenerated) {
|
if (!hasAvatar || !info.autogenerated)
|
||||||
setAutoGeneratedAvatar();
|
setAutoGeneratedAvatar();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case QXmppPresence::VCardUpdateValidPhoto:{ //there is a photo, need to load
|
case QXmppPresence::VCardUpdateValidPhoto:{ //there is a photo, need to load
|
||||||
Archive::AvatarInfo info;
|
Archive::AvatarInfo info;
|
||||||
bool hasAvatar = readAvatarInfo(info);
|
bool hasAvatar = readAvatarInfo(info);
|
||||||
if (hasAvatar) {
|
if (hasAvatar) {
|
||||||
if (info.autogenerated || info.hash != pres.photoHash()) {
|
if (info.autogenerated || info.hash != pres.photoHash())
|
||||||
emit requestVCard(jid);
|
emit requestVCard(jid);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
emit requestVCard(jid);
|
emit requestVCard(jid);
|
||||||
}
|
}
|
||||||
@ -98,3 +91,23 @@ void Core::Contact::handlePresence(const QXmppPresence& pres)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Core::Contact::setPepSupport(Shared::Support support) {
|
||||||
|
if (pep != support)
|
||||||
|
pep = support;
|
||||||
|
}
|
||||||
|
|
||||||
|
Shared::Support Core::Contact::getPepSupport() const {
|
||||||
|
return pep;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMap<QString, QVariant> Core::Contact::getInfo() const {
|
||||||
|
QMap<QString, QVariant> data = RosterItem::getInfo();
|
||||||
|
|
||||||
|
data.insert("state", QVariant::fromValue(subscriptionState));
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -16,17 +16,18 @@
|
|||||||
* 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 CORE_CONTACT_H
|
#pragma once
|
||||||
#define CORE_CONTACT_H
|
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
|
|
||||||
#include "rosteritem.h"
|
#include "rosteritem.h"
|
||||||
|
|
||||||
|
#include <shared/enums.h>
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
class Contact : public RosterItem
|
class Contact : public RosterItem {
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
Contact(const QString& pJid, const QString& account, QObject* parent = 0);
|
Contact(const QString& pJid, const QString& account, QObject* parent = 0);
|
||||||
@ -38,7 +39,11 @@ public:
|
|||||||
|
|
||||||
void setSubscriptionState(Shared::SubscriptionState state);
|
void setSubscriptionState(Shared::SubscriptionState state);
|
||||||
Shared::SubscriptionState getSubscriptionState() const;
|
Shared::SubscriptionState getSubscriptionState() const;
|
||||||
|
void setPepSupport(Shared::Support support);
|
||||||
|
Shared::Support getPepSupport() const;
|
||||||
|
|
||||||
void handlePresence(const QXmppPresence & pres) override;
|
void handlePresence(const QXmppPresence & pres) override;
|
||||||
|
QMap<QString, QVariant> getInfo() const override;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void groupAdded(const QString& name);
|
void groupAdded(const QString& name);
|
||||||
@ -48,7 +53,11 @@ signals:
|
|||||||
private:
|
private:
|
||||||
QSet<QString> groups;
|
QSet<QString> groups;
|
||||||
Shared::SubscriptionState subscriptionState;
|
Shared::SubscriptionState subscriptionState;
|
||||||
|
Shared::Support pep;
|
||||||
|
|
||||||
|
#ifdef WITH_OMEMO
|
||||||
|
public:
|
||||||
|
Shared::Possible omemoBundles;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // CORE_CONTACT_H
|
|
||||||
|
26
core/delayManager/CMakeLists.txt
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
set(SOURCE_FILES
|
||||||
|
manager.cpp
|
||||||
|
job.cpp
|
||||||
|
cardinternal.cpp
|
||||||
|
infoforuser.cpp
|
||||||
|
owncardinternal.cpp
|
||||||
|
owninfoforuser.cpp
|
||||||
|
contact.cpp
|
||||||
|
info.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(HEADER_FILES
|
||||||
|
manager.h
|
||||||
|
job.h
|
||||||
|
cardinternal.h
|
||||||
|
infoforuser.h
|
||||||
|
owncardinternal.h
|
||||||
|
owninfoforuser.h
|
||||||
|
contact.h
|
||||||
|
info.h
|
||||||
|
)
|
||||||
|
|
||||||
|
target_sources(squawk PRIVATE
|
||||||
|
${SOURCE_FILES}
|
||||||
|
${HEADER_FILES}
|
||||||
|
)
|
30
core/delayManager/cardinternal.cpp
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* 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 "cardinternal.h"
|
||||||
|
|
||||||
|
Core::DelayManager::CardInternal::CardInternal(Id p_id, const QString& p_jid) :
|
||||||
|
Job(p_id, Type::cardInternal),
|
||||||
|
Contact(p_id, p_jid, Type::cardInternal)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
Core::DelayManager::CardInternal::CardInternal(const CardInternal& other) :
|
||||||
|
Job(other),
|
||||||
|
Contact(other)
|
||||||
|
{}
|
35
core/delayManager/cardinternal.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* 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 <QString>
|
||||||
|
|
||||||
|
#include "contact.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
namespace DelayManager {
|
||||||
|
|
||||||
|
class CardInternal : public Contact {
|
||||||
|
public:
|
||||||
|
CardInternal(Id id, const QString& jid);
|
||||||
|
CardInternal(const CardInternal& other);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
28
core/delayManager/contact.cpp
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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 "contact.h"
|
||||||
|
|
||||||
|
Core::DelayManager::Contact::Contact(const Contact& other):
|
||||||
|
Job(other),
|
||||||
|
jid(other.jid) {}
|
||||||
|
|
||||||
|
|
||||||
|
Core::DelayManager::Contact::Contact(Id p_id, const QString& p_jid, Type p_type):
|
||||||
|
Job(p_id, p_type),
|
||||||
|
jid(p_jid) {}
|
@ -16,41 +16,23 @@
|
|||||||
* 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 CORE_STORAGE_H
|
#pragma once
|
||||||
#define CORE_STORAGE_H
|
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <lmdb.h>
|
|
||||||
|
|
||||||
#include "archive.h"
|
#include "job.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
namespace DelayManager {
|
||||||
|
|
||||||
|
class Contact : public virtual Job {
|
||||||
|
protected:
|
||||||
|
Contact(Id id, const QString& jid, Type type);
|
||||||
|
Contact(const Contact& other);
|
||||||
|
|
||||||
/**
|
|
||||||
* @todo write docs
|
|
||||||
*/
|
|
||||||
class Storage
|
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
Storage(const QString& name);
|
const QString jid;
|
||||||
~Storage();
|
|
||||||
|
|
||||||
void open();
|
|
||||||
void close();
|
|
||||||
|
|
||||||
void addRecord(const QString& key, const QString& value);
|
|
||||||
void changeRecord(const QString& key, const QString& value);
|
|
||||||
void removeRecord(const QString& key);
|
|
||||||
QString getRecord(const QString& key) const;
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString name;
|
|
||||||
bool opened;
|
|
||||||
MDB_env* environment;
|
|
||||||
MDB_dbi base;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endif // CORE_STORAGE_H
|
|
58
core/delayManager/info.cpp
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* 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 "info.h"
|
||||||
|
|
||||||
|
Core::DelayManager::Info::Info(Id p_id, Type p_type) :
|
||||||
|
Job(p_id, p_type),
|
||||||
|
stage(Stage::waitingForVCard),
|
||||||
|
info(nullptr)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Core::DelayManager::Info::Info(const Info& other) :
|
||||||
|
Job(other),
|
||||||
|
stage(other.stage),
|
||||||
|
info(nullptr)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Core::DelayManager::Info::~Info() {
|
||||||
|
if (stage == Stage::waitingForBundles) {
|
||||||
|
delete info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Core::DelayManager::Info::Stage Core::DelayManager::Info::getStage() const {
|
||||||
|
return stage;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::DelayManager::Info::receivedVCard(const Shared::VCard& card) {
|
||||||
|
if (stage != Stage::waitingForVCard)
|
||||||
|
throw 245;
|
||||||
|
|
||||||
|
info = new Shared::VCard(card);
|
||||||
|
stage = Stage::waitingForBundles;
|
||||||
|
}
|
||||||
|
|
||||||
|
Shared::VCard * Core::DelayManager::Info::claim() {
|
||||||
|
if (stage != Stage::waitingForBundles)
|
||||||
|
throw 246;
|
||||||
|
|
||||||
|
Shared::VCard* res = info;
|
||||||
|
info = nullptr;
|
||||||
|
return res;
|
||||||
|
}
|
55
core/delayManager/info.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* 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 "job.h"
|
||||||
|
|
||||||
|
#include <shared/vcard.h>
|
||||||
|
#include <shared/info.h>
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
namespace DelayManager {
|
||||||
|
|
||||||
|
class Info : public virtual Job {
|
||||||
|
public:
|
||||||
|
enum class Stage {
|
||||||
|
waitingForVCard,
|
||||||
|
waitingForBundles,
|
||||||
|
finished
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Info(Id id, Type type);
|
||||||
|
Info(const Info& other);
|
||||||
|
|
||||||
|
public:
|
||||||
|
~Info();
|
||||||
|
|
||||||
|
void receivedVCard(const Shared::VCard& card);
|
||||||
|
Shared::VCard* claim();
|
||||||
|
Stage getStage() const;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
Stage stage;
|
||||||
|
Shared::VCard* info;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
31
core/delayManager/infoforuser.cpp
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* 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 "infoforuser.h"
|
||||||
|
|
||||||
|
Core::DelayManager::InfoForUser::InfoForUser(Id p_id, const QString& p_jid) :
|
||||||
|
Job(p_id, Type::infoForUser),
|
||||||
|
Contact(p_id, p_jid, Type::infoForUser),
|
||||||
|
Info(p_id, Type::infoForUser)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Core::DelayManager::InfoForUser::InfoForUser(const InfoForUser& other) :
|
||||||
|
Job(other),
|
||||||
|
Contact(other),
|
||||||
|
Info(other)
|
||||||
|
{}
|
34
core/delayManager/infoforuser.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* 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 "contact.h"
|
||||||
|
#include "info.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
namespace DelayManager {
|
||||||
|
|
||||||
|
class InfoForUser : public Contact, public Info {
|
||||||
|
public:
|
||||||
|
InfoForUser(Id id, const QString& jid);
|
||||||
|
InfoForUser(const InfoForUser& other);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
30
core/delayManager/job.cpp
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* 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 "job.h"
|
||||||
|
|
||||||
|
Core::DelayManager::Job::Job(Id p_id, Type p_type) :
|
||||||
|
id (p_id),
|
||||||
|
type (p_type) {}
|
||||||
|
|
||||||
|
|
||||||
|
Core::DelayManager::Job::Job(const Job& other) :
|
||||||
|
id(other.id),
|
||||||
|
type(other.type) {}
|
||||||
|
|
||||||
|
Core::DelayManager::Job::~Job() {}
|
54
core/delayManager/job.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* 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 <stdint.h>
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
namespace DelayManager {
|
||||||
|
|
||||||
|
class Job {
|
||||||
|
public:
|
||||||
|
typedef uint16_t Id;
|
||||||
|
|
||||||
|
enum class Type {
|
||||||
|
cardInternal,
|
||||||
|
ownCardInternal,
|
||||||
|
infoForUser,
|
||||||
|
ownInfoForUser
|
||||||
|
};
|
||||||
|
inline static constexpr const char * const TypeString[] = {
|
||||||
|
"cardInternal",
|
||||||
|
"ownCardInternal",
|
||||||
|
"infoForUser",
|
||||||
|
"ownInfoForUser"
|
||||||
|
};
|
||||||
|
protected:
|
||||||
|
Job(Id id, Type type);
|
||||||
|
Job(const Job& other);
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~Job();
|
||||||
|
|
||||||
|
const Id id;
|
||||||
|
const Type type;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
435
core/delayManager/manager.cpp
Normal file
@ -0,0 +1,435 @@
|
|||||||
|
/*
|
||||||
|
* 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 "manager.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include "cardinternal.h"
|
||||||
|
#include "infoforuser.h"
|
||||||
|
#include "owncardinternal.h"
|
||||||
|
#include "owninfoforuser.h"
|
||||||
|
|
||||||
|
Core::DelayManager::Manager::Manager(const QString& poj, Job::Id mpj, QObject* parent) :
|
||||||
|
QObject(parent),
|
||||||
|
maxParallelJobs(mpj),
|
||||||
|
nextJobId(1),
|
||||||
|
scheduledJobs(),
|
||||||
|
scheduledJobsById(scheduledJobs.get<id>()),
|
||||||
|
jobSequence(scheduledJobs.get<sequence>()),
|
||||||
|
runningJobs(),
|
||||||
|
ownVCardJobId(0),
|
||||||
|
ownInfoJobId(0),
|
||||||
|
scheduledVCards(),
|
||||||
|
requestedVCards(),
|
||||||
|
#ifdef WITH_OMEMO
|
||||||
|
requestedBundles(),
|
||||||
|
#endif
|
||||||
|
ownJid(poj)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Core::DelayManager::Manager::~Manager() {
|
||||||
|
for (const std::pair<const Job::Id, Job*>& pair : runningJobs)
|
||||||
|
delete pair.second;
|
||||||
|
|
||||||
|
for (Job* job : jobSequence)
|
||||||
|
delete job;
|
||||||
|
}
|
||||||
|
|
||||||
|
Core::DelayManager::Job::Id Core::DelayManager::Manager::getNextJobId() {
|
||||||
|
Job::Id id = nextJobId++;
|
||||||
|
if (id == 0)
|
||||||
|
id = nextJobId++;
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::DelayManager::Manager::getInfo(const QString& jid) {
|
||||||
|
if (jid == ownJid)
|
||||||
|
return getOwnInfo();
|
||||||
|
|
||||||
|
Job* job = nullptr;
|
||||||
|
#ifdef WITH_OMEMO
|
||||||
|
std::map<QString, Job::Id>::const_iterator bitr = requestedBundles.find(jid);
|
||||||
|
if (bitr != requestedBundles.end()) {
|
||||||
|
std::map<Job::Id, Job*>::const_iterator itr = runningJobs.find(bitr->second);
|
||||||
|
if (itr == runningJobs.end())
|
||||||
|
throw JobNotFound(bitr->second);
|
||||||
|
|
||||||
|
job = itr->second;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
job = getVCardJob(jid);
|
||||||
|
|
||||||
|
if (job != nullptr) {
|
||||||
|
if (job->type == Job::Type::cardInternal)
|
||||||
|
replaceJob(new InfoForUser(job->id, jid));
|
||||||
|
} else
|
||||||
|
scheduleJob(new InfoForUser(getNextJobId(), jid));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::DelayManager::Manager::getOwnInfo() {
|
||||||
|
if (ownInfoJobId == 0) {
|
||||||
|
if (ownVCardJobId != 0)
|
||||||
|
replaceJob(new OwnInfoForUser(ownVCardJobId));
|
||||||
|
else
|
||||||
|
scheduleJob(new OwnInfoForUser(getNextJobId()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::DelayManager::Manager::getVCard(const QString& jid) {
|
||||||
|
Job* job = getVCardJob(jid);
|
||||||
|
if (job == nullptr)
|
||||||
|
scheduleJob(new CardInternal(getNextJobId(), jid));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::DelayManager::Manager::getOwnVCard() {
|
||||||
|
if (ownVCardJobId == 0)
|
||||||
|
scheduleJob(new OwnCardInternal(getNextJobId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Core::DelayManager::Manager::isOwnVCardPending() const {
|
||||||
|
return ownVCardJobId != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Core::DelayManager::Job* Core::DelayManager::Manager::getVCardJob(const QString& jid) {
|
||||||
|
Job* job = nullptr;
|
||||||
|
std::map<QString, Job::Id>::const_iterator sitr = scheduledVCards.find(jid);
|
||||||
|
if (sitr == scheduledVCards.end()) {
|
||||||
|
std::map<QString, Job::Id>::const_iterator ritr = requestedVCards.find(jid);
|
||||||
|
if (ritr != requestedVCards.end()) {
|
||||||
|
std::map<Job::Id, Job*>::const_iterator itr = runningJobs.find(ritr->second);
|
||||||
|
if (itr == runningJobs.end())
|
||||||
|
throw JobNotFound(ritr->second, "getVCardJob:1");
|
||||||
|
|
||||||
|
job = itr->second;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
StorageById::const_iterator itr = scheduledJobsById.find(sitr->second);
|
||||||
|
if (itr == scheduledJobsById.end())
|
||||||
|
throw JobNotFound(sitr->second, "getVCardJob:2");
|
||||||
|
|
||||||
|
job = *itr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return job;
|
||||||
|
}
|
||||||
|
void Core::DelayManager::Manager::preScheduleJob(Job* job) {
|
||||||
|
switch (job->type) {
|
||||||
|
case Job::Type::cardInternal:
|
||||||
|
scheduledVCards.emplace(dynamic_cast<CardInternal*>(job)->jid, job->id);
|
||||||
|
break;
|
||||||
|
case Job::Type::ownCardInternal:
|
||||||
|
ownVCardJobId = job->id;
|
||||||
|
break;
|
||||||
|
case Job::Type::infoForUser:
|
||||||
|
scheduledVCards.emplace(dynamic_cast<InfoForUser*>(job)->jid, job->id);
|
||||||
|
break;
|
||||||
|
case Job::Type::ownInfoForUser:
|
||||||
|
ownVCardJobId = job->id;
|
||||||
|
ownInfoJobId = job->id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::DelayManager::Manager::scheduleJob(Job* job) {
|
||||||
|
preScheduleJob(job);
|
||||||
|
if (runningJobs.size() < maxParallelJobs)
|
||||||
|
executeJob(job);
|
||||||
|
else
|
||||||
|
scheduledJobs.push_back(job);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::DelayManager::Manager::preExecuteJob(Job* job) {
|
||||||
|
switch (job->type) {
|
||||||
|
case Job::Type::cardInternal:
|
||||||
|
case Job::Type::infoForUser: {
|
||||||
|
Contact* cij = dynamic_cast<Contact*>(job);
|
||||||
|
requestedVCards.emplace(cij->jid, job->id);
|
||||||
|
scheduledVCards.erase(cij->jid);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Job::Type::ownInfoForUser:
|
||||||
|
case Job::Type::ownCardInternal:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::DelayManager::Manager::executeJob(Job* job) {
|
||||||
|
preExecuteJob(job);
|
||||||
|
runningJobs.emplace(job->id, job);
|
||||||
|
switch (job->type) {
|
||||||
|
case Job::Type::cardInternal:
|
||||||
|
case Job::Type::infoForUser:
|
||||||
|
emit requestVCard(dynamic_cast<Contact*>(job)->jid);
|
||||||
|
break;
|
||||||
|
case Job::Type::ownInfoForUser:
|
||||||
|
case Job::Type::ownCardInternal:
|
||||||
|
emit requestOwnVCard();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::DelayManager::Manager::jobIsDone(Job::Id jobId) {
|
||||||
|
std::map<Job::Id, Job*>::const_iterator itr = runningJobs.find(jobId);
|
||||||
|
if (itr == runningJobs.end())
|
||||||
|
throw JobNotFound(jobId, "jobIsDone");
|
||||||
|
|
||||||
|
Job* job = itr->second;
|
||||||
|
delete job;
|
||||||
|
runningJobs.erase(itr);
|
||||||
|
if (scheduledJobs.size() > 0) {
|
||||||
|
Job* job = scheduledJobs.front();
|
||||||
|
scheduledJobs.pop_front();
|
||||||
|
executeJob(job);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::DelayManager::Manager::replaceJob(Job* job) {
|
||||||
|
preScheduleJob(job);
|
||||||
|
std::map<Job::Id, Job*>::iterator itr = runningJobs.find(job->id);
|
||||||
|
if (itr != runningJobs.end()) {
|
||||||
|
preExecuteJob(job);
|
||||||
|
delete itr->second;
|
||||||
|
itr->second = job;
|
||||||
|
} else {
|
||||||
|
StorageById::iterator sitr = scheduledJobsById.find(job->id);
|
||||||
|
if (sitr != scheduledJobsById.end()) {
|
||||||
|
delete *(sitr);
|
||||||
|
scheduledJobsById.replace(sitr, job);
|
||||||
|
} else
|
||||||
|
throw JobNotFound(job->id, "replaceJob");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::DelayManager::Manager::jobIsCanceled(Job* job, bool wasRunning) {
|
||||||
|
switch (job->type) {
|
||||||
|
case Job::Type::cardInternal: {
|
||||||
|
CardInternal* jb = dynamic_cast<CardInternal*>(job);
|
||||||
|
if (wasRunning)
|
||||||
|
requestedVCards.erase(jb->jid);
|
||||||
|
else
|
||||||
|
scheduledVCards.erase(jb->jid);
|
||||||
|
|
||||||
|
emit gotVCard(jb->jid, Shared::VCard());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Job::Type::infoForUser: {
|
||||||
|
InfoForUser* jb = dynamic_cast<InfoForUser*>(job);
|
||||||
|
switch (jb->getStage()) {
|
||||||
|
case InfoForUser::Stage::waitingForVCard:
|
||||||
|
if (wasRunning)
|
||||||
|
requestedVCards.erase(jb->jid);
|
||||||
|
else
|
||||||
|
scheduledVCards.erase(jb->jid);
|
||||||
|
|
||||||
|
emit gotVCard(jb->jid, Shared::VCard());
|
||||||
|
break;
|
||||||
|
case InfoForUser::Stage::waitingForBundles:
|
||||||
|
requestedBundles.erase(jb->jid);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
emit gotInfo(Shared::Info(jb->jid));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Job::Type::ownInfoForUser: {
|
||||||
|
OwnInfoForUser* jb = dynamic_cast<OwnInfoForUser*>(job);
|
||||||
|
if (jb->getStage() == OwnInfoForUser::Stage::waitingForVCard) {
|
||||||
|
ownVCardJobId = 0;
|
||||||
|
emit gotOwnVCard(Shared::VCard());
|
||||||
|
}
|
||||||
|
ownInfoJobId = 0;
|
||||||
|
emit gotOwnInfo(Shared::Info (ownJid));
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case Job::Type::ownCardInternal:
|
||||||
|
ownVCardJobId = 0;
|
||||||
|
emit gotOwnVCard(Shared::VCard());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete job;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::DelayManager::Manager::disconnected() {
|
||||||
|
for (const std::pair<const Job::Id, Job*> pair : runningJobs)
|
||||||
|
jobIsCanceled(pair.second, true);
|
||||||
|
|
||||||
|
for (Job* job : scheduledJobs)
|
||||||
|
jobIsCanceled(job, false);
|
||||||
|
|
||||||
|
runningJobs.clear();
|
||||||
|
scheduledJobs.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::DelayManager::Manager::receivedVCard(const QString& jid, const Shared::VCard& card) {
|
||||||
|
std::map<QString, Job::Id>::const_iterator cardItr = requestedVCards.find(jid);
|
||||||
|
if (cardItr == requestedVCards.end()) {
|
||||||
|
qDebug() << "received VCard for" << jid << "but it was never requested through manager, ignoring";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Job::Id jobId = cardItr->second;
|
||||||
|
requestedVCards.erase(cardItr);
|
||||||
|
std::map<Job::Id, Job*>::const_iterator itr = runningJobs.find(jobId);
|
||||||
|
if (itr == runningJobs.end())
|
||||||
|
throw JobNotFound(jobId, "receivedVCard");
|
||||||
|
|
||||||
|
Job* job = itr->second;
|
||||||
|
|
||||||
|
switch (job->type) {
|
||||||
|
case Job::Type::cardInternal:
|
||||||
|
jobIsDone(jobId);
|
||||||
|
emit gotVCard(jid, card);
|
||||||
|
break;
|
||||||
|
case Job::Type::infoForUser: {
|
||||||
|
#ifdef WITH_OMEMO
|
||||||
|
requestedBundles.emplace(jid, jobId);
|
||||||
|
InfoForUser* jb = dynamic_cast<InfoForUser*>(job);
|
||||||
|
jb->receivedVCard(card);
|
||||||
|
emit requestBundles(jid);
|
||||||
|
#else
|
||||||
|
Shared::Info info(jid);
|
||||||
|
info.turnIntoContact(card);
|
||||||
|
emit gotInfo(info);
|
||||||
|
jobIsDone(jobId);
|
||||||
|
#endif
|
||||||
|
emit gotVCard(jid, card);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw UnexpectedJobType(job->type, "receivedVCard");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::DelayManager::Manager::receivedOwnVCard(const Shared::VCard& card) {
|
||||||
|
if (ownVCardJobId == 0) {
|
||||||
|
qDebug() << "received own VCard for" << ownJid << "but it was never requested through manager, ignoring";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Job::Id jobId = ownVCardJobId;
|
||||||
|
ownVCardJobId = 0;
|
||||||
|
std::map<Job::Id, Job*>::const_iterator itr = runningJobs.find(jobId);
|
||||||
|
if (itr == runningJobs.end())
|
||||||
|
throw JobNotFound(jobId, "receivedOwnVCard");
|
||||||
|
|
||||||
|
Job* job = itr->second;
|
||||||
|
switch (job->type) {
|
||||||
|
case Job::Type::ownCardInternal:
|
||||||
|
jobIsDone(jobId);
|
||||||
|
emit gotOwnVCard(card);
|
||||||
|
break;
|
||||||
|
case Job::Type::ownInfoForUser: {
|
||||||
|
#ifdef WITH_OMEMO
|
||||||
|
OwnInfoForUser* jb = dynamic_cast<OwnInfoForUser*>(job);
|
||||||
|
jb->receivedVCard(card);
|
||||||
|
emit requestOwnBundles();
|
||||||
|
#else
|
||||||
|
Shared::Info info(ownJid);
|
||||||
|
info.turnIntoOwnAccount(card);
|
||||||
|
emit gotOwnInfo(info);
|
||||||
|
jobIsDone(jobId);
|
||||||
|
#endif
|
||||||
|
emit gotOwnVCard(card);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw UnexpectedJobType(job->type, "receivedVCard");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::DelayManager::Manager::receivedBundles(const QString& jid, const std::list<Shared::KeyInfo>& keys) {
|
||||||
|
std::map<QString, Job::Id>::const_iterator itr = requestedBundles.find(jid);
|
||||||
|
if (itr == requestedBundles.end()) {
|
||||||
|
qDebug() << "received bundles for" << jid << "but they were never requested through manager, ignoring";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Job::Id jobId = itr->second;
|
||||||
|
requestedBundles.erase(itr);
|
||||||
|
std::map<Job::Id, Job*>::const_iterator jitr = runningJobs.find(jobId);
|
||||||
|
if (jitr == runningJobs.end())
|
||||||
|
throw JobNotFound(jobId, "receivedBundles");
|
||||||
|
|
||||||
|
Job* jb = jitr->second;
|
||||||
|
InfoForUser* job = dynamic_cast<InfoForUser*>(jb);
|
||||||
|
|
||||||
|
Shared::Info info(jid);
|
||||||
|
info.turnIntoContact(job->claim(), new std::list<Shared::KeyInfo>(keys));
|
||||||
|
emit gotInfo(info);
|
||||||
|
jobIsDone(jobId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::DelayManager::Manager::receivedOwnBundles(const std::list<Shared::KeyInfo>& keys) {
|
||||||
|
if (ownInfoJobId == 0) {
|
||||||
|
qDebug() << "received own bundles for" << ownJid << "but they were never requested through manager, ignoring";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Job::Id jobId = ownInfoJobId;
|
||||||
|
ownInfoJobId = 0;
|
||||||
|
std::map<Job::Id, Job*>::const_iterator jitr = runningJobs.find(jobId);
|
||||||
|
if (jitr == runningJobs.end())
|
||||||
|
throw JobNotFound(jobId, "receivedOwnBundles");
|
||||||
|
|
||||||
|
Job* jb = jitr->second;
|
||||||
|
OwnInfoForUser* job = dynamic_cast<OwnInfoForUser*>(jb);
|
||||||
|
|
||||||
|
Shared::Info info(ownJid);
|
||||||
|
info.turnIntoOwnAccount(job->claim(), new std::list<Shared::KeyInfo>(keys));
|
||||||
|
emit gotOwnInfo(info);
|
||||||
|
jobIsDone(jobId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::DelayManager::Manager::setOwnJid(const QString& jid) {
|
||||||
|
ownJid = jid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Core::DelayManager::Manager::UnexpectedJobType::UnexpectedJobType(Job::Type p_type, const std::string& p_method):
|
||||||
|
Exception(),
|
||||||
|
type(p_type),
|
||||||
|
method(p_method)
|
||||||
|
{}
|
||||||
|
|
||||||
|
std::string Core::DelayManager::Manager::UnexpectedJobType::getMessage() const{
|
||||||
|
std::string msg("Unexpected job type: ");
|
||||||
|
msg += Job::TypeString[static_cast<int>(type)];
|
||||||
|
if (method.size() > 0)
|
||||||
|
msg += " in method " + method;
|
||||||
|
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
Core::DelayManager::Manager::JobNotFound::JobNotFound(Job::Id p_id, const std::string& p_method) :
|
||||||
|
Exception(),
|
||||||
|
id(p_id),
|
||||||
|
method(p_method)
|
||||||
|
{}
|
||||||
|
|
||||||
|
std::string Core::DelayManager::Manager::JobNotFound::getMessage() const {
|
||||||
|
std::string msg("Job with id ");
|
||||||
|
msg += std::to_string(id);
|
||||||
|
msg += " was not found";
|
||||||
|
if (method.size() > 0)
|
||||||
|
msg += " in method " + method;
|
||||||
|
|
||||||
|
return msg;
|
||||||
|
}
|
147
core/delayManager/manager.h
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
* 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 <list>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <boost/multi_index_container.hpp>
|
||||||
|
#include <boost/multi_index/ordered_index.hpp>
|
||||||
|
#include <boost/multi_index/sequenced_index.hpp>
|
||||||
|
#include <boost/multi_index/member.hpp>
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include <shared/vcard.h>
|
||||||
|
#include <shared/info.h>
|
||||||
|
#include <shared/exception.h>
|
||||||
|
|
||||||
|
#include "job.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
namespace DelayManager {
|
||||||
|
|
||||||
|
class Manager : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
Manager(const QString& ownJid, Job::Id maxParallelJobs = 5, QObject* parent = nullptr);
|
||||||
|
~Manager();
|
||||||
|
|
||||||
|
void setOwnJid(const QString& jid);
|
||||||
|
bool isOwnVCardPending() const;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void getOwnVCard();
|
||||||
|
void getOwnInfo();
|
||||||
|
void getVCard(const QString& jid);
|
||||||
|
void getInfo(const QString& jid);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void requestVCard(const QString& jid);
|
||||||
|
void requestOwnVCard();
|
||||||
|
void requestBundles(const QString& jid);
|
||||||
|
void requestOwnBundles();
|
||||||
|
|
||||||
|
void gotVCard(const QString& jid, const Shared::VCard& info);
|
||||||
|
void gotOwnVCard(const Shared::VCard& info);
|
||||||
|
void gotInfo(const Shared::Info& info);
|
||||||
|
void gotOwnInfo(const Shared::Info& info);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void disconnected();
|
||||||
|
void receivedOwnVCard(const Shared::VCard& card);
|
||||||
|
void receivedVCard(const QString& jid, const Shared::VCard& card);
|
||||||
|
void receivedBundles(const QString& jid, const std::list<Shared::KeyInfo>& keys);
|
||||||
|
void receivedOwnBundles(const std::list<Shared::KeyInfo>& keys);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void preScheduleJob(Job* job);
|
||||||
|
void scheduleJob(Job* job);
|
||||||
|
void preExecuteJob(Job* job);
|
||||||
|
void executeJob(Job* job);
|
||||||
|
void jobIsCanceled(Job* job, bool wasRunning);
|
||||||
|
void jobIsDone(Job::Id jobId);
|
||||||
|
Job::Id getNextJobId();
|
||||||
|
void replaceJob(Job* job);
|
||||||
|
Job* getVCardJob(const QString& jid);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct id {};
|
||||||
|
struct sequence {};
|
||||||
|
|
||||||
|
typedef boost::multi_index_container<
|
||||||
|
Job*,
|
||||||
|
boost::multi_index::indexed_by<
|
||||||
|
boost::multi_index::sequenced<
|
||||||
|
boost::multi_index::tag<sequence>
|
||||||
|
>,
|
||||||
|
boost::multi_index::ordered_unique<
|
||||||
|
boost::multi_index::tag<id>,
|
||||||
|
boost::multi_index::member<
|
||||||
|
Job,
|
||||||
|
const Job::Id,
|
||||||
|
&Job::id
|
||||||
|
>
|
||||||
|
>
|
||||||
|
>
|
||||||
|
> Storage;
|
||||||
|
|
||||||
|
|
||||||
|
typedef Storage::index<id>::type StorageById;
|
||||||
|
typedef Storage::index<sequence>::type StorageSequence;
|
||||||
|
Job::Id maxParallelJobs;
|
||||||
|
Job::Id nextJobId;
|
||||||
|
|
||||||
|
Storage scheduledJobs;
|
||||||
|
StorageById& scheduledJobsById;
|
||||||
|
StorageSequence& jobSequence;
|
||||||
|
std::map<Job::Id, Job*> runningJobs;
|
||||||
|
|
||||||
|
Job::Id ownVCardJobId;
|
||||||
|
Job::Id ownInfoJobId;
|
||||||
|
std::map<QString, Job::Id> scheduledVCards;
|
||||||
|
std::map<QString, Job::Id> requestedVCards;
|
||||||
|
#ifdef WITH_OMEMO
|
||||||
|
std::map<QString, Job::Id> requestedBundles;
|
||||||
|
#endif
|
||||||
|
QString ownJid;
|
||||||
|
|
||||||
|
public:
|
||||||
|
class UnexpectedJobType: public Utils::Exception {
|
||||||
|
public:
|
||||||
|
UnexpectedJobType(Job::Type p_type, const std::string& p_method = "");
|
||||||
|
std::string getMessage() const override;
|
||||||
|
private:
|
||||||
|
Job::Type type;
|
||||||
|
std::string method;
|
||||||
|
};
|
||||||
|
|
||||||
|
class JobNotFound: public Utils::Exception {
|
||||||
|
public:
|
||||||
|
JobNotFound(Job::Id p_id, const std::string& p_method = "");
|
||||||
|
std::string getMessage() const override;
|
||||||
|
private:
|
||||||
|
Job::Id id;
|
||||||
|
std::string method;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
32
core/delayManager/owncardinternal.cpp
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* 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 "owncardinternal.h"
|
||||||
|
|
||||||
|
Core::DelayManager::OwnCardInternal::OwnCardInternal(Id p_id) :
|
||||||
|
Job(p_id, Type::ownCardInternal)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Core::DelayManager::OwnCardInternal::OwnCardInternal(Id p_id, Type p_type) :
|
||||||
|
Job(p_id, p_type)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Core::DelayManager::OwnCardInternal::OwnCardInternal(const OwnCardInternal& other) :
|
||||||
|
Job(other)
|
||||||
|
{}
|
||||||
|
|
36
core/delayManager/owncardinternal.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* 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 "job.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
namespace DelayManager {
|
||||||
|
|
||||||
|
class OwnCardInternal : public Job {
|
||||||
|
protected:
|
||||||
|
OwnCardInternal(Id id, Type type);
|
||||||
|
|
||||||
|
public:
|
||||||
|
OwnCardInternal(Id id);
|
||||||
|
OwnCardInternal(const OwnCardInternal& other);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
29
core/delayManager/owninfoforuser.cpp
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* 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 "owninfoforuser.h"
|
||||||
|
|
||||||
|
Core::DelayManager::OwnInfoForUser::OwnInfoForUser(Id p_id) :
|
||||||
|
Job(p_id, Type::ownInfoForUser),
|
||||||
|
Info(p_id, Type::ownInfoForUser)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Core::DelayManager::OwnInfoForUser::OwnInfoForUser(const OwnInfoForUser& other) :
|
||||||
|
Job(other),
|
||||||
|
Info(other)
|
||||||
|
{}
|
34
core/delayManager/owninfoforuser.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* 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 "contact.h"
|
||||||
|
#include "info.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
namespace DelayManager {
|
||||||
|
|
||||||
|
class OwnInfoForUser : public Info {
|
||||||
|
public:
|
||||||
|
OwnInfoForUser(Id id);
|
||||||
|
OwnInfoForUser(const OwnInfoForUser& other);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,22 @@
|
|||||||
target_sources(squawk PRIVATE
|
set(SOURCE_FILES
|
||||||
messagehandler.cpp
|
messagehandler.cpp
|
||||||
messagehandler.h
|
|
||||||
rosterhandler.cpp
|
rosterhandler.cpp
|
||||||
rosterhandler.h
|
|
||||||
vcardhandler.cpp
|
vcardhandler.cpp
|
||||||
|
discoveryhandler.cpp
|
||||||
|
omemohandler.cpp
|
||||||
|
trusthandler.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(HEADER_FILES
|
||||||
|
messagehandler.h
|
||||||
|
rosterhandler.h
|
||||||
vcardhandler.h
|
vcardhandler.h
|
||||||
)
|
discoveryhandler.h
|
||||||
|
omemohandler.h
|
||||||
|
trusthandler.h
|
||||||
|
)
|
||||||
|
|
||||||
|
target_sources(squawk PRIVATE
|
||||||
|
${SOURCE_FILES}
|
||||||
|
${HEADER_FILES}
|
||||||
|
)
|
||||||
|
155
core/handlers/discoveryhandler.cpp
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
// 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 "discoveryhandler.h"
|
||||||
|
#include "core/account.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
Core::DiscoveryHandler::DiscoveryHandler(Core::Account* account):
|
||||||
|
QObject(),
|
||||||
|
acc(account),
|
||||||
|
omemoToCarbonsConnected (false) {}
|
||||||
|
|
||||||
|
Core::DiscoveryHandler::~DiscoveryHandler() {}
|
||||||
|
|
||||||
|
void Core::DiscoveryHandler::initialize()
|
||||||
|
{
|
||||||
|
QObject::connect(acc->dm, &QXmppDiscoveryManager::itemsReceived, this, &DiscoveryHandler::onItemsReceived);
|
||||||
|
QObject::connect(acc->dm, &QXmppDiscoveryManager::infoReceived, this, &DiscoveryHandler::onInfoReceived);
|
||||||
|
|
||||||
|
acc->dm->setClientType("pc");
|
||||||
|
acc->dm->setClientCategory("client");
|
||||||
|
acc->dm->setClientName(qApp->applicationDisplayName() + " " + qApp->applicationVersion());
|
||||||
|
acc->dm->setClientCapabilitiesNode("https://git.macaw.me/blue/squawk");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::DiscoveryHandler::onItemsReceived(const QXmppDiscoveryIq& items)
|
||||||
|
{
|
||||||
|
QString server = acc->getServer();
|
||||||
|
if (items.from() == server) {
|
||||||
|
std::set<QString> needToRequest;
|
||||||
|
qDebug() << "Server items list received for account " << acc->getName() << ":";
|
||||||
|
for (QXmppDiscoveryIq::Item item : items.items()) {
|
||||||
|
QString jid = item.jid();
|
||||||
|
if (jid != server) {
|
||||||
|
qDebug() << " Node" << jid;
|
||||||
|
needToRequest.insert(jid);
|
||||||
|
} else {
|
||||||
|
qDebug() << " " << item.node().toStdString().c_str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const QString& jid : needToRequest) {
|
||||||
|
acc->dm->requestInfo(jid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::DiscoveryHandler::onInfoReceived(const QXmppDiscoveryIq& info)
|
||||||
|
{
|
||||||
|
QString from = info.from();
|
||||||
|
QString server = acc->getServer();
|
||||||
|
QString accName = acc->getName();
|
||||||
|
QString bareJid = acc->getBareJid();
|
||||||
|
if (from == server) {
|
||||||
|
bool enableCC = false;
|
||||||
|
qDebug() << "Server info received for account" << accName;
|
||||||
|
QStringList features = info.features();
|
||||||
|
qDebug() << "List of supported features of the server " << server << ":";
|
||||||
|
for (const QString& feature : features) {
|
||||||
|
qDebug() << " " << feature.toStdString().c_str();
|
||||||
|
if (feature == "urn:xmpp:carbons:2") {
|
||||||
|
enableCC = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enableCC) {
|
||||||
|
qDebug() << "Enabling carbon copies for account" << accName;
|
||||||
|
#if (QXMPP_VERSION) < QT_VERSION_CHECK(1, 5, 0)
|
||||||
|
acc->cm->setCarbonsEnabled(true);
|
||||||
|
#endif
|
||||||
|
#ifdef WITH_OMEMO
|
||||||
|
if (!omemoToCarbonsConnected && acc->oh->hasOwnDevice()) {
|
||||||
|
// connect(this, &QXmppCarbonManager::messageSent, acc->om, &QXmppOmemoManager::handleMessage);
|
||||||
|
// connect(this, &QXmppCarbonManager::messageReceived, acc->om, &QXmppOmemoManager::handleMessage);
|
||||||
|
omemoToCarbonsConnected = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (omemoToCarbonsConnected) {
|
||||||
|
// disconnect(this, &QXmppCarbonManager::messageSent, acc->om, &QXmppOmemoManager::handleMessage);
|
||||||
|
// disconnect(this, &QXmppCarbonManager::messageReceived, acc->om, &QXmppOmemoManager::handleMessage);
|
||||||
|
omemoToCarbonsConnected = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "Requesting account" << accName << "capabilities";
|
||||||
|
acc->dm->requestInfo(bareJid);
|
||||||
|
} else if (from == bareJid) {
|
||||||
|
qDebug() << "Received capabilities for account" << accName << ":";
|
||||||
|
QList<QXmppDiscoveryIq::Identity> identities = info.identities();
|
||||||
|
bool pepSupported = false;
|
||||||
|
for (const QXmppDiscoveryIq::Identity& identity : identities) {
|
||||||
|
QString type = identity.type();
|
||||||
|
QString category = identity.category();
|
||||||
|
qDebug() << " " << category << type;
|
||||||
|
if (type == "pep" && category == "pubsub") {
|
||||||
|
pepSupported = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
acc->setPepSupport(pepSupported ? Shared::Support::supported : Shared::Support::unsupported);
|
||||||
|
} else {
|
||||||
|
QString node = info.queryNode();
|
||||||
|
if (!node.isEmpty()) {
|
||||||
|
qDebug() << "Received features and identities for account" << accName << "about" << from;
|
||||||
|
QStringList feats = info.features();
|
||||||
|
std::set<Shared::Identity> identities;
|
||||||
|
std::set<QString> features(feats.begin(), feats.end());
|
||||||
|
QList<QXmppDiscoveryIq::Identity> idents = info.identities();
|
||||||
|
for (const QXmppDiscoveryIq::Identity& ident : idents) {
|
||||||
|
Shared::Identity identity;
|
||||||
|
identity.category = ident.category();
|
||||||
|
identity.language = ident.language();
|
||||||
|
identity.name = ident.name();
|
||||||
|
identity.type = ident.type();
|
||||||
|
identities.insert(identity);
|
||||||
|
|
||||||
|
qDebug() << " " << identity.name << identity.category << identity.type;
|
||||||
|
}
|
||||||
|
for (const QString& feat : features) {
|
||||||
|
qDebug() << " " << feat;
|
||||||
|
}
|
||||||
|
emit acc->infoDiscovered(from, node, identities, features);
|
||||||
|
} else {
|
||||||
|
Contact* cont = acc->rh->getContact(from);
|
||||||
|
if (cont != nullptr) {
|
||||||
|
qDebug() << "Received info for account" << accName << "about contact" << from;
|
||||||
|
QList<QXmppDiscoveryIq::Identity> identities = info.identities();
|
||||||
|
bool pepSupported = false;
|
||||||
|
for (const QXmppDiscoveryIq::Identity& identity : identities) {
|
||||||
|
QString type = identity.type();
|
||||||
|
QString category = identity.category();
|
||||||
|
qDebug() << " " << category << type;
|
||||||
|
if (type == "pep" && category == "pubsub") {
|
||||||
|
pepSupported = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cont->setPepSupport(pepSupported ? Shared::Support::supported : Shared::Support::unsupported);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
48
core/handlers/discoveryhandler.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
#ifndef CORE_DISCOVERYHANDLER_H
|
||||||
|
#define CORE_DISCOVERYHANDLER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include <QXmppDiscoveryManager.h>
|
||||||
|
#include <QXmppDiscoveryIq.h>
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class Account;
|
||||||
|
|
||||||
|
class DiscoveryHandler : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
DiscoveryHandler(Account* account);
|
||||||
|
~DiscoveryHandler();
|
||||||
|
|
||||||
|
void initialize();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onItemsReceived (const QXmppDiscoveryIq& items);
|
||||||
|
void onInfoReceived (const QXmppDiscoveryIq& info);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Account* acc;
|
||||||
|
bool omemoToCarbonsConnected;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CORE_DISCOVERYHANDLER_H
|
@ -19,59 +19,86 @@
|
|||||||
#include "messagehandler.h"
|
#include "messagehandler.h"
|
||||||
#include "core/account.h"
|
#include "core/account.h"
|
||||||
|
|
||||||
|
static const QMap<QString, QVariant> statePending({{"state", static_cast<uint8_t>(Shared::Message::State::pending)}});
|
||||||
|
static const QMap<QString, QVariant> stateDelivered({{"state", static_cast<uint8_t>(Shared::Message::State::delivered)}});
|
||||||
|
static const QMap<QString, QVariant> stateSent({{"state", static_cast<uint8_t>(Shared::Message::State::sent)}});
|
||||||
|
|
||||||
Core::MessageHandler::MessageHandler(Core::Account* account):
|
Core::MessageHandler::MessageHandler(Core::Account* account):
|
||||||
QObject(),
|
QObject(),
|
||||||
acc(account),
|
acc(account),
|
||||||
pendingStateMessages(),
|
pendingStateMessages(),
|
||||||
uploadingSlotsQueue()
|
uploadingSlotsQueue()
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
void Core::MessageHandler::onMessageReceived(const QXmppMessage& msg)
|
void Core::MessageHandler::onMessageReceived(const QXmppMessage& msg) {
|
||||||
{
|
#if (QXMPP_VERSION) >= QT_VERSION_CHECK(1, 5, 0)
|
||||||
|
#ifdef WITH_OMEMO
|
||||||
|
switch (msg.encryptionMethod()) {
|
||||||
|
case QXmpp::NoEncryption:
|
||||||
|
break; //just do nothing
|
||||||
|
case QXmpp::UnknownEncryption:
|
||||||
|
qDebug() << "Account" << acc->getName() << "received a message with unknown encryption type";
|
||||||
|
break; //let it go the way it is, there is nothing I can do here
|
||||||
|
case QXmpp::Otr:
|
||||||
|
qDebug() << "Account" << acc->getName() << "received an OTR encrypted message, not supported yet";
|
||||||
|
break; //let it go the way it is, there is nothing I can do yet
|
||||||
|
case QXmpp::LegacyOpenPgp:
|
||||||
|
qDebug() << "Account" << acc->getName() << "received an LegacyOpenPgp encrypted message, not supported yet";
|
||||||
|
break; //let it go the way it is, there is nothing I can do yet
|
||||||
|
case QXmpp::Ox:
|
||||||
|
qDebug() << "Account" << acc->getName() << "received an Ox encrypted message, not supported yet";
|
||||||
|
break; //let it go the way it is, there is nothing I can do yet
|
||||||
|
case QXmpp::Omemo0:
|
||||||
|
qDebug() << "Account" << acc->getName() << "received an Omemo0 encrypted message, not supported yet";
|
||||||
|
break; //let it go the way it is, there is nothing I can do yet
|
||||||
|
case QXmpp::Omemo1:
|
||||||
|
qDebug() << "Account" << acc->getName() << "received an Omemo1 encrypted message, not supported yet";
|
||||||
|
break; //let it go the way it is, there is nothing I can do yet
|
||||||
|
case QXmpp::Omemo2:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
bool handled = false;
|
bool handled = false;
|
||||||
switch (msg.type()) {
|
switch (msg.type()) {
|
||||||
case QXmppMessage::Normal:
|
case QXmppMessage::Normal:
|
||||||
qDebug() << "received a message with type \"Normal\", not sure what to do with it now, skipping";
|
qDebug() << "received a message with type \"Normal\", not sure what to do with it now, skipping";
|
||||||
break;
|
break;
|
||||||
case QXmppMessage::Chat:
|
case QXmppMessage::Chat:
|
||||||
|
#if (QXMPP_VERSION) >= QT_VERSION_CHECK(1, 5, 0)
|
||||||
|
handled = handleChatMessage(msg, false, msg.isCarbonForwarded(), true);
|
||||||
|
#else
|
||||||
handled = handleChatMessage(msg);
|
handled = handleChatMessage(msg);
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
case QXmppMessage::GroupChat:
|
case QXmppMessage::GroupChat:
|
||||||
handled = handleGroupMessage(msg);
|
handled = handleGroupMessage(msg);
|
||||||
break;
|
break;
|
||||||
case QXmppMessage::Error: {
|
case QXmppMessage::Error:
|
||||||
std::tuple<bool, QString, QString> ids = getOriginalPendingMessageId(msg.id());
|
handled = handlePendingMessageError(msg.id(), msg.error().text());
|
||||||
if (std::get<0>(ids)) {
|
if (!handled)
|
||||||
QString id = std::get<1>(ids);
|
|
||||||
QString jid = std::get<2>(ids);
|
|
||||||
RosterItem* cnt = acc->rh->getRosterItem(jid);
|
|
||||||
QMap<QString, QVariant> cData = {
|
|
||||||
{"state", static_cast<uint>(Shared::Message::State::error)},
|
|
||||||
{"errorText", msg.error().text()}
|
|
||||||
};
|
|
||||||
if (cnt != 0) {
|
|
||||||
cnt->changeMessage(id, cData);
|
|
||||||
}
|
|
||||||
emit acc->changeMessage(jid, id, cData);
|
|
||||||
handled = true;
|
|
||||||
} else {
|
|
||||||
qDebug() << "received a message with type \"Error\", not sure what to do with it now, skipping";
|
qDebug() << "received a message with type \"Error\", not sure what to do with it now, skipping";
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case QXmppMessage::Headline:
|
case QXmppMessage::Headline:
|
||||||
qDebug() << "received a message with type \"Headline\", not sure what to do with it now, skipping";
|
qDebug() << "received a message with type \"Headline\", not sure what to do with it now, skipping";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!handled) {
|
if (!handled)
|
||||||
logMessage(msg);
|
logMessage(msg);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Core::MessageHandler::handleChatMessage(const QXmppMessage& msg, bool outgoing, bool forwarded, bool guessing)
|
bool Core::MessageHandler::handlePendingMessageError(const QString& id, const QString& errorText) {
|
||||||
{
|
return adjustPendingMessage(id, {
|
||||||
if (msg.body().size() != 0 || msg.outOfBandUrl().size() > 0) {
|
{"state", static_cast<uint8_t>(Shared::Message::State::error)},
|
||||||
|
{"errorText", errorText}
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Core::MessageHandler::handleChatMessage(const QXmppMessage& msg, bool outgoing, bool forwarded, bool guessing) {
|
||||||
|
if (msg.body().isEmpty() && msg.outOfBandUrl().isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
Shared::Message sMsg(Shared::Message::chat);
|
Shared::Message sMsg(Shared::Message::chat);
|
||||||
initializeMessage(sMsg, msg, outgoing, forwarded, guessing);
|
initializeMessage(sMsg, msg, outgoing, forwarded, guessing);
|
||||||
QString jid = sMsg.getPenPalJid();
|
QString jid = sMsg.getPenPalJid();
|
||||||
@ -80,10 +107,9 @@ bool Core::MessageHandler::handleChatMessage(const QXmppMessage& msg, bool outgo
|
|||||||
cnt = acc->rh->addOutOfRosterContact(jid);
|
cnt = acc->rh->addOutOfRosterContact(jid);
|
||||||
qDebug() << "appending message" << sMsg.getId() << "to an out of roster contact";
|
qDebug() << "appending message" << sMsg.getId() << "to an out of roster contact";
|
||||||
}
|
}
|
||||||
if (outgoing) {
|
if (sMsg.getOutgoing()) {
|
||||||
if (forwarded) {
|
if (sMsg.getForwarded())
|
||||||
sMsg.setState(Shared::Message::State::sent);
|
sMsg.setState(Shared::Message::State::sent);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
sMsg.setState(Shared::Message::State::delivered);
|
sMsg.setState(Shared::Message::State::delivered);
|
||||||
}
|
}
|
||||||
@ -101,29 +127,24 @@ bool Core::MessageHandler::handleChatMessage(const QXmppMessage& msg, bool outgo
|
|||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Core::MessageHandler::handleGroupMessage(const QXmppMessage& msg, bool outgoing, bool forwarded, bool guessing)
|
bool Core::MessageHandler::handleGroupMessage(const QXmppMessage& msg, bool outgoing, bool forwarded, bool guessing) {
|
||||||
{
|
|
||||||
const QString& body(msg.body());
|
const QString& body(msg.body());
|
||||||
if (body.size() != 0) {
|
if (body.isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
Shared::Message sMsg(Shared::Message::groupChat);
|
Shared::Message sMsg(Shared::Message::groupChat);
|
||||||
initializeMessage(sMsg, msg, outgoing, forwarded, guessing);
|
initializeMessage(sMsg, msg, outgoing, forwarded, guessing);
|
||||||
QString jid = sMsg.getPenPalJid();
|
QString jid = sMsg.getPenPalJid();
|
||||||
Conference* cnt = acc->rh->getConference(jid);
|
Conference* cnt = acc->rh->getConference(jid);
|
||||||
if (cnt == 0) {
|
if (cnt == 0)
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
std::tuple<bool, QString, QString> ids = getOriginalPendingMessageId(msg.id());
|
bool result = adjustPendingMessage(msg.id(), stateDelivered, true);
|
||||||
if (std::get<0>(ids)) {
|
if (result) //then it was an echo of my own sent message, nothing else needs to be done
|
||||||
QMap<QString, QVariant> cData = {{"state", static_cast<uint>(Shared::Message::State::delivered)}};
|
return result;
|
||||||
cnt->changeMessage(std::get<1>(ids), cData);
|
|
||||||
emit acc->changeMessage(std::get<2>(ids), std::get<1>(ids), cData);
|
|
||||||
} else {
|
|
||||||
QString oId = msg.replaceId();
|
QString oId = msg.replaceId();
|
||||||
if (oId.size() > 0) {
|
if (oId.size() > 0) {
|
||||||
QMap<QString, QVariant> cData = {
|
QMap<QString, QVariant> cData = {
|
||||||
@ -135,29 +156,21 @@ bool Core::MessageHandler::handleGroupMessage(const QXmppMessage& msg, bool outg
|
|||||||
} else {
|
} else {
|
||||||
cnt->appendMessageToArchive(sMsg);
|
cnt->appendMessageToArchive(sMsg);
|
||||||
QDateTime minAgo = QDateTime::currentDateTimeUtc().addSecs(-60);
|
QDateTime minAgo = QDateTime::currentDateTimeUtc().addSecs(-60);
|
||||||
if (sMsg.getTime() > minAgo) { //otherwise it's considered a delayed delivery, most probably MUC history receipt
|
if (sMsg.getTime() > minAgo) //otherwise it's considered a delayed delivery, most probably MUC history initial fetch
|
||||||
emit acc->message(sMsg);
|
emit acc->message(sMsg);
|
||||||
} else {
|
|
||||||
//qDebug() << "Delayed delivery: ";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Core::MessageHandler::initializeMessage(Shared::Message& target, const QXmppMessage& source, bool outgoing, bool forwarded, bool guessing) const {
|
||||||
void Core::MessageHandler::initializeMessage(Shared::Message& target, const QXmppMessage& source, bool outgoing, bool forwarded, bool guessing) const
|
|
||||||
{
|
|
||||||
const QDateTime& time(source.stamp());
|
const QDateTime& time(source.stamp());
|
||||||
QString id;
|
QString id;
|
||||||
#if (QXMPP_VERSION) >= QT_VERSION_CHECK(1, 3, 0)
|
#if (QXMPP_VERSION) >= QT_VERSION_CHECK(1, 3, 0)
|
||||||
id = source.originId();
|
id = source.originId();
|
||||||
if (id.size() == 0) {
|
if (id.size() == 0)
|
||||||
id = source.id();
|
id = source.id();
|
||||||
}
|
|
||||||
target.setStanzaId(source.stanzaId());
|
target.setStanzaId(source.stanzaId());
|
||||||
qDebug() << "initializing message with originId:" << source.originId() << ", id:" << source.id() << ", stansaId:" << source.stanzaId();
|
qDebug() << "initializing message with originId:" << source.originId() << ", id:" << source.id() << ", stansaId:" << source.stanzaId();
|
||||||
#else
|
#else
|
||||||
@ -174,30 +187,30 @@ void Core::MessageHandler::initializeMessage(Shared::Message& target, const QXmp
|
|||||||
target.setTo(source.to());
|
target.setTo(source.to());
|
||||||
target.setBody(source.body());
|
target.setBody(source.body());
|
||||||
target.setForwarded(forwarded);
|
target.setForwarded(forwarded);
|
||||||
|
#ifdef WITH_OMEMO
|
||||||
|
#if (QXMPP_VERSION) >= QT_VERSION_CHECK(1, 5, 0)
|
||||||
|
if (source.encryptionMethod() == QXmpp::EncryptionMethod::Omemo2)
|
||||||
|
target.setEncryption(Shared::EncryptionProtocol::omemo2);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (guessing)
|
||||||
|
outgoing = target.getFromJid() == acc->getBareJid();
|
||||||
|
|
||||||
if (guessing) {
|
|
||||||
if (target.getFromJid() == acc->getBareJid()) {
|
|
||||||
outgoing = true;
|
|
||||||
} else {
|
|
||||||
outgoing = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
target.setOutgoing(outgoing);
|
target.setOutgoing(outgoing);
|
||||||
if (time.isValid()) {
|
if (time.isValid())
|
||||||
target.setTime(time);
|
target.setTime(time);
|
||||||
} else {
|
else
|
||||||
target.setCurrentTime();
|
target.setCurrentTime();
|
||||||
}
|
|
||||||
|
|
||||||
QString oob = source.outOfBandUrl();
|
QString oob = source.outOfBandUrl();
|
||||||
if (oob.size() > 0) {
|
if (oob.size() > 0)
|
||||||
target.setAttachPath(acc->network->addMessageAndCheckForPath(oob, acc->getName(), target.getPenPalJid(), messageId));
|
target.setAttachPath(acc->network->addMessageAndCheckForPath(oob, acc->getName(), target.getPenPalJid(), messageId));
|
||||||
}
|
|
||||||
target.setOutOfBandUrl(oob);
|
target.setOutOfBandUrl(oob);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::MessageHandler::logMessage(const QXmppMessage& msg, const QString& reason)
|
void Core::MessageHandler::logMessage(const QXmppMessage& msg, const QString& reason) {
|
||||||
{
|
|
||||||
qDebug() << reason;
|
qDebug() << reason;
|
||||||
qDebug() << "- from: " << msg.from();
|
qDebug() << "- from: " << msg.from();
|
||||||
qDebug() << "- to: " << msg.to();
|
qDebug() << "- to: " << msg.to();
|
||||||
@ -213,58 +226,44 @@ void Core::MessageHandler::logMessage(const QXmppMessage& msg, const QString& re
|
|||||||
qDebug() << "==============================";
|
qDebug() << "==============================";
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::MessageHandler::onCarbonMessageReceived(const QXmppMessage& msg)
|
#if (QXMPP_VERSION) < QT_VERSION_CHECK(1, 5, 0)
|
||||||
{
|
void Core::MessageHandler::onCarbonMessageReceived(const QXmppMessage& msg) {
|
||||||
handleChatMessage(msg, false, true);
|
handleChatMessage(msg, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::MessageHandler::onCarbonMessageSent(const QXmppMessage& msg)
|
void Core::MessageHandler::onCarbonMessageSent(const QXmppMessage& msg) {
|
||||||
{
|
|
||||||
handleChatMessage(msg, true, true);
|
handleChatMessage(msg, true, true);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
std::tuple<bool, QString, QString> Core::MessageHandler::getOriginalPendingMessageId(const QString& id)
|
std::optional<Shared::MessageInfo> Core::MessageHandler::getOriginalPendingMessageId(const QString& id, bool clear) {
|
||||||
{
|
|
||||||
std::tuple<bool, QString, QString> result({false, "", ""});
|
|
||||||
std::map<QString, QString>::const_iterator itr = pendingStateMessages.find(id);
|
std::map<QString, QString>::const_iterator itr = pendingStateMessages.find(id);
|
||||||
if (itr != pendingStateMessages.end()) {
|
if (itr != pendingStateMessages.end()) {
|
||||||
std::get<0>(result) = true;
|
Shared::MessageInfo info(acc->name, itr->second, itr->first);
|
||||||
std::get<2>(result) = itr->second;
|
|
||||||
|
|
||||||
std::map<QString, QString>::const_iterator itrC = pendingCorrectionMessages.find(id);
|
std::map<QString, QString>::const_iterator itrC = pendingCorrectionMessages.find(id);
|
||||||
if (itrC != pendingCorrectionMessages.end()) {
|
if (itrC != pendingCorrectionMessages.end()) {
|
||||||
if (itrC->second.size() > 0) {
|
if (itrC->second.size() > 0)
|
||||||
std::get<1>(result) = itrC->second;
|
info.jid = itrC->second;
|
||||||
} else {
|
|
||||||
std::get<1>(result) = itr->first;
|
if (clear)
|
||||||
}
|
|
||||||
pendingCorrectionMessages.erase(itrC);
|
pendingCorrectionMessages.erase(itrC);
|
||||||
} else {
|
|
||||||
std::get<1>(result) = itr->first;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (clear)
|
||||||
pendingStateMessages.erase(itr);
|
pendingStateMessages.erase(itr);
|
||||||
|
|
||||||
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::MessageHandler::onReceiptReceived(const QString& jid, const QString& id)
|
void Core::MessageHandler::onReceiptReceived(const QString& jid, const QString& id) {
|
||||||
{
|
SHARED_UNUSED(jid);
|
||||||
std::tuple<bool, QString, QString> ids = getOriginalPendingMessageId(id);
|
adjustPendingMessage(id, {{"state", static_cast<uint>(Shared::Message::State::delivered)}}, true);
|
||||||
if (std::get<0>(ids)) {
|
|
||||||
QMap<QString, QVariant> cData = {{"state", static_cast<uint>(Shared::Message::State::delivered)}};
|
|
||||||
RosterItem* ri = acc->rh->getRosterItem(std::get<2>(ids));
|
|
||||||
|
|
||||||
if (ri != 0) {
|
|
||||||
ri->changeMessage(std::get<1>(ids), cData);
|
|
||||||
}
|
|
||||||
emit acc->changeMessage(std::get<2>(ids), std::get<1>(ids), cData);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::MessageHandler::sendMessage(const Shared::Message& data, bool newMessage, QString originalId)
|
void Core::MessageHandler::sendMessage(const Shared::Message& data, bool newMessage, QString originalId) {
|
||||||
{
|
|
||||||
if (data.getOutOfBandUrl().size() == 0 && data.getAttachPath().size() > 0) {
|
if (data.getOutOfBandUrl().size() == 0 && data.getAttachPath().size() > 0) {
|
||||||
pendingCorrectionMessages.insert(std::make_pair(data.getId(), originalId));
|
pendingCorrectionMessages.insert(std::make_pair(data.getId(), originalId));
|
||||||
prepareUpload(data, newMessage);
|
prepareUpload(data, newMessage);
|
||||||
@ -273,83 +272,148 @@ void Core::MessageHandler::sendMessage(const Shared::Message& data, bool newMess
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::MessageHandler::performSending(Shared::Message data, const QString& originalId, bool newMessage)
|
void Core::MessageHandler::performSending(Shared::Message data, const QString& originalId, bool newMessage) {
|
||||||
{
|
|
||||||
QString jid = data.getPenPalJid();
|
QString jid = data.getPenPalJid();
|
||||||
QString id = data.getId();
|
QString id = data.getId();
|
||||||
qDebug() << "Sending message with id:" << id;
|
qDebug() << "Sending message with id:" << id;
|
||||||
if (originalId.size() > 0) {
|
if (originalId.size() > 0)
|
||||||
qDebug() << "To replace one with id:" << originalId;
|
qDebug() << "To replace the one with id:" << originalId;
|
||||||
}
|
|
||||||
RosterItem* ri = acc->rh->getRosterItem(jid);
|
RosterItem* ri = acc->rh->getRosterItem(jid);
|
||||||
bool sent = false;
|
if (newMessage && originalId.size() > 0)
|
||||||
if (newMessage && originalId.size() > 0) {
|
|
||||||
newMessage = false;
|
newMessage = false;
|
||||||
}
|
|
||||||
QDateTime sendTime = QDateTime::currentDateTimeUtc();
|
QDateTime sendTime = QDateTime::currentDateTimeUtc();
|
||||||
if (acc->state == Shared::ConnectionState::connected) {
|
std::pair<Shared::Message::State, QString> result = scheduleSending(data, sendTime, originalId);
|
||||||
QXmppMessage msg(createPacket(data, sendTime, originalId));
|
data.setState(result.first);
|
||||||
|
data.setErrorText(result.second);
|
||||||
sent = acc->client.sendPacket(msg);
|
|
||||||
if (sent) {
|
|
||||||
data.setState(Shared::Message::State::sent);
|
|
||||||
} else {
|
|
||||||
data.setState(Shared::Message::State::error);
|
|
||||||
data.setErrorText("Couldn't send message: internal QXMPP library error, probably need to check out the logs");
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
data.setState(Shared::Message::State::error);
|
|
||||||
data.setErrorText("You are is offline or reconnecting");
|
|
||||||
}
|
|
||||||
|
|
||||||
QMap<QString, QVariant> changes(getChanges(data, sendTime, newMessage, originalId));
|
QMap<QString, QVariant> changes(getChanges(data, sendTime, newMessage, originalId));
|
||||||
|
if (ri != nullptr) {
|
||||||
QString realId;
|
if (newMessage)
|
||||||
if (originalId.size() > 0) {
|
|
||||||
realId = originalId;
|
|
||||||
} else {
|
|
||||||
realId = id;
|
|
||||||
}
|
|
||||||
if (ri != 0) {
|
|
||||||
if (newMessage) {
|
|
||||||
ri->appendMessageToArchive(data);
|
ri->appendMessageToArchive(data);
|
||||||
} else {
|
else
|
||||||
ri->changeMessage(realId, changes);
|
ri->changeMessage(originalId.isEmpty() ? id : originalId, changes);
|
||||||
}
|
|
||||||
if (sent) {
|
if (data.getState() != Shared::Message::State::error) {
|
||||||
pendingStateMessages.insert(std::make_pair(id, jid));
|
pendingStateMessages.insert(std::make_pair(id, jid));
|
||||||
if (originalId.size() > 0) {
|
if (originalId.size() > 0)
|
||||||
pendingCorrectionMessages.insert(std::make_pair(id, originalId));
|
pendingCorrectionMessages.insert(std::make_pair(id, originalId));
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
pendingStateMessages.erase(id);
|
pendingStateMessages.erase(id);
|
||||||
pendingCorrectionMessages.erase(id);
|
pendingCorrectionMessages.erase(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emit acc->changeMessage(jid, realId, changes);
|
emit acc->changeMessage(jid, originalId.isEmpty() ? id : originalId, changes);
|
||||||
}
|
}
|
||||||
|
|
||||||
QMap<QString, QVariant> Core::MessageHandler::getChanges(Shared::Message& data, const QDateTime& time, bool newMessage, const QString& originalId) const
|
std::pair<Shared::Message::State, QString> Core::MessageHandler::scheduleSending(
|
||||||
{
|
const Shared::Message& message,
|
||||||
|
const QDateTime& sendTime,
|
||||||
|
const QString& originalId
|
||||||
|
) {
|
||||||
|
if (acc->state != Shared::ConnectionState::connected)
|
||||||
|
return {Shared::Message::State::error, "You are is offline or reconnecting"};
|
||||||
|
|
||||||
|
QXmppMessage msg = createPacket(message, sendTime, originalId);
|
||||||
|
QString id = msg.id();
|
||||||
|
#ifdef WITH_OMEMO
|
||||||
|
if (message.getEncryption() == Shared::EncryptionProtocol::omemo2) {
|
||||||
|
QXmppTask<QXmppE2eeExtension::MessageEncryptResult> task = acc->om->encryptMessage(std::move(msg), std::nullopt);
|
||||||
|
if (task.isFinished()) {
|
||||||
|
const QXmppE2eeExtension::MessageEncryptResult& res = task.result();
|
||||||
|
if (std::holds_alternative<std::unique_ptr<QXmppMessage>>(res)) {
|
||||||
|
qDebug() << "Successfully encrypted a message";
|
||||||
|
const std::unique_ptr<QXmppMessage>& encrypted = std::get<std::unique_ptr<QXmppMessage>>(res);
|
||||||
|
encrypted->setBody(QString());
|
||||||
|
encrypted->setOutOfBandUrl(QString());
|
||||||
|
bool success = acc->client.sendPacket(*encrypted.get());
|
||||||
|
if (success) {
|
||||||
|
qDebug() << "Successfully sent an encrypted message";
|
||||||
|
return {Shared::Message::State::sent, ""};
|
||||||
|
} else {
|
||||||
|
qDebug() << "Couldn't sent an encrypted message";
|
||||||
|
return {Shared::Message::State::error, "Error sending successfully encrypted message"};
|
||||||
|
}
|
||||||
|
} else if (std::holds_alternative<QXmppError>(res)) {
|
||||||
|
qDebug() << "Couldn't encrypt a message";
|
||||||
|
const QXmppError& err = std::get<QXmppError>(res);
|
||||||
|
return {Shared::Message::State::error, err.description};
|
||||||
|
} else {
|
||||||
|
qDebug() << "Couldn't encrypt a message";
|
||||||
|
return {Shared::Message::State::error, "Unexpected error ecryptng the message"};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
task.then(this, [this, id] (QXmppE2eeExtension::MessageEncryptResult&& result) {
|
||||||
|
if (std::holds_alternative<std::unique_ptr<QXmppMessage>>(result)) {
|
||||||
|
qDebug() << "Successfully encrypted a message";
|
||||||
|
const std::unique_ptr<QXmppMessage>& encrypted = std::get<std::unique_ptr<QXmppMessage>>(result);
|
||||||
|
encrypted->setBody(QString());
|
||||||
|
encrypted->setOutOfBandUrl(QString());
|
||||||
|
bool success = acc->client.sendPacket(*encrypted.get());
|
||||||
|
if (success) {
|
||||||
|
qDebug() << "Successfully sent an encrypted message";
|
||||||
|
if (!adjustPendingMessage(id, stateSent, false))
|
||||||
|
qDebug() << "Encrypted message has been successfully sent, but it couldn't be found to update the sate";
|
||||||
|
} else {
|
||||||
|
qDebug() << "Couldn't sent an encrypted message";
|
||||||
|
handlePendingMessageError(id, "Error sending successfully encrypted message");
|
||||||
|
}
|
||||||
|
} else if (std::holds_alternative<QXmppError>(result)) {
|
||||||
|
qDebug() << "Couldn't encrypt a message";
|
||||||
|
const QXmppError& err = std::get<QXmppError>(result);
|
||||||
|
handlePendingMessageError(id, err.description);
|
||||||
|
} else {
|
||||||
|
qDebug() << "Couldn't encrypt a message";
|
||||||
|
handlePendingMessageError(id, "Unexpected error ecryptng the message");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return {Shared::Message::State::pending, ""};
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
bool success = acc->client.sendPacket(msg);
|
||||||
|
if (success)
|
||||||
|
return {Shared::Message::State::sent, ""};
|
||||||
|
else
|
||||||
|
return {Shared::Message::State::error, "Error sending message, internal QXMPP error"};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Core::MessageHandler::adjustPendingMessage(const QString& messageId, const QMap<QString, QVariant>& data, bool final) {
|
||||||
|
std::optional<Shared::MessageInfo> info = getOriginalPendingMessageId(messageId, final);
|
||||||
|
if (info) {
|
||||||
|
RosterItem* ri = acc->rh->getRosterItem(info->jid);
|
||||||
|
if (ri != nullptr)
|
||||||
|
ri->changeMessage(info->messageId, data);
|
||||||
|
|
||||||
|
emit acc->changeMessage(info->jid, info->messageId, data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMap<QString, QVariant> Core::MessageHandler::getChanges(Shared::Message& data, const QDateTime& time, bool newMessage, const QString& originalId) const {
|
||||||
QMap<QString, QVariant> changes;
|
QMap<QString, QVariant> changes;
|
||||||
|
|
||||||
QString oob = data.getOutOfBandUrl();
|
QString oob = data.getOutOfBandUrl();
|
||||||
Shared::Message::State mstate = data.getState();
|
Shared::Message::State mstate = data.getState();
|
||||||
changes.insert("state", static_cast<uint>(mstate));
|
changes.insert("state", static_cast<uint>(mstate));
|
||||||
if (mstate == Shared::Message::State::error) {
|
if (mstate == Shared::Message::State::error)
|
||||||
changes.insert("errorText", data.getErrorText());
|
changes.insert("errorText", data.getErrorText());
|
||||||
}
|
|
||||||
if (oob.size() > 0) {
|
if (oob.size() > 0)
|
||||||
changes.insert("outOfBandUrl", oob);
|
changes.insert("outOfBandUrl", oob);
|
||||||
}
|
|
||||||
if (newMessage) {
|
if (newMessage)
|
||||||
data.setTime(time);
|
data.setTime(time);
|
||||||
}
|
|
||||||
if (originalId.size() > 0) {
|
if (originalId.size() > 0)
|
||||||
changes.insert("body", data.getBody());
|
changes.insert("body", data.getBody());
|
||||||
}
|
|
||||||
changes.insert("stamp", time);
|
changes.insert("stamp", time);
|
||||||
|
|
||||||
//sometimes (when the image is pasted with ctrl+v)
|
//sometimes (when the image is pasted with ctrl+v)
|
||||||
@ -359,22 +423,20 @@ QMap<QString, QVariant> Core::MessageHandler::getChanges(Shared::Message& data,
|
|||||||
if (attachPath.size() > 0) {
|
if (attachPath.size() > 0) {
|
||||||
QString squawkified = Shared::squawkifyPath(attachPath);
|
QString squawkified = Shared::squawkifyPath(attachPath);
|
||||||
changes.insert("attachPath", squawkified);
|
changes.insert("attachPath", squawkified);
|
||||||
if (attachPath != squawkified) {
|
if (attachPath != squawkified)
|
||||||
data.setAttachPath(squawkified);
|
data.setAttachPath(squawkified);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return changes;
|
return changes;
|
||||||
}
|
}
|
||||||
|
|
||||||
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(acc->getFullJid(), data.getTo(), data.getBody(), data.getThread());
|
||||||
QString id(data.getId());
|
QString id(data.getId());
|
||||||
|
|
||||||
if (originalId.size() > 0) {
|
if (originalId.size() > 0)
|
||||||
msg.setReplaceId(originalId);
|
msg.setReplaceId(originalId);
|
||||||
}
|
|
||||||
|
|
||||||
#if (QXMPP_VERSION) >= QT_VERSION_CHECK(1, 3, 0)
|
#if (QXMPP_VERSION) >= QT_VERSION_CHECK(1, 3, 0)
|
||||||
msg.setOriginId(id);
|
msg.setOriginId(id);
|
||||||
@ -388,59 +450,58 @@ QXmppMessage Core::MessageHandler::createPacket(const Shared::Message& data, con
|
|||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::MessageHandler::prepareUpload(const Shared::Message& data, bool newMessage)
|
void Core::MessageHandler::prepareUpload(const Shared::Message& data, bool newMessage) {
|
||||||
{
|
if (acc->state != Shared::ConnectionState::connected) {
|
||||||
if (acc->state == Shared::ConnectionState::connected) {
|
handleUploadError(data.getPenPalJid(), data.getId(), "Account is offline or reconnecting");
|
||||||
|
qDebug() << "An attempt to send message with not connected account " << acc->name << ", skipping";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QString jid = data.getPenPalJid();
|
QString jid = data.getPenPalJid();
|
||||||
QString id = data.getId();
|
QString id = data.getId();
|
||||||
RosterItem* ri = acc->rh->getRosterItem(jid);
|
RosterItem* ri = acc->rh->getRosterItem(jid);
|
||||||
if (!ri) {
|
if (ri == nullptr) {
|
||||||
qDebug() << "An attempt to initialize upload in" << acc->name << "for pal" << jid << "but the object for this pal wasn't found, something went terrebly wrong, skipping send";
|
qDebug() << "An attempt to initialize upload in" << acc->name << "for pal" << jid << "but the object for this pal wasn't found, something went terrebly wrong, skipping send";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString path = data.getAttachPath();
|
QString path = data.getAttachPath();
|
||||||
QString url = acc->network->getFileRemoteUrl(path);
|
QString url = acc->network->getFileRemoteUrl(path);
|
||||||
if (url.size() != 0) {
|
if (url.size() != 0)
|
||||||
sendMessageWithLocalUploadedFile(data, url, newMessage);
|
return sendMessageWithLocalUploadedFile(data, url, newMessage);
|
||||||
} else {
|
|
||||||
pendingStateMessages.insert(std::make_pair(id, jid));
|
pendingStateMessages.insert(std::make_pair(id, jid));
|
||||||
if (newMessage) {
|
if (newMessage) {
|
||||||
ri->appendMessageToArchive(data);
|
ri->appendMessageToArchive(data);
|
||||||
} else {
|
} else {
|
||||||
QMap<QString, QVariant> changes({
|
ri->changeMessage(id, statePending);
|
||||||
{"state", (uint)Shared::Message::State::pending}
|
emit acc->changeMessage(jid, id, statePending);
|
||||||
});
|
|
||||||
ri->changeMessage(id, changes);
|
|
||||||
emit acc->changeMessage(jid, id, changes);
|
|
||||||
}
|
}
|
||||||
//this checks if the file is already uploading, and if so it subscribes to it's success, so, i need to do stuff only if the network knows nothing of this file
|
|
||||||
if (!acc->network->checkAndAddToUploading(acc->getName(), jid, id, path)) {
|
//this checks if the file is already uploading, and if so it subscribes to it's success,
|
||||||
if (acc->um->serviceFound()) {
|
//So, I need to do stuff only if the network knows nothing of this file
|
||||||
|
if (acc->network->checkAndAddToUploading(acc->getName(), jid, id, path))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!acc->um->serviceFound()) {
|
||||||
|
handleUploadError(jid, id, "Your server doesn't support file upload service, or it's prohibited for your account");
|
||||||
|
qDebug() << "Requested upload slot in account" << acc->name << "for file" << path << "but upload manager didn't discover any upload services";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
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(path, id);
|
||||||
if (uploadingSlotsQueue.size() == 1) {
|
if (uploadingSlotsQueue.size() == 1)
|
||||||
acc->um->requestUploadSlot(file);
|
acc->um->requestUploadSlot(file);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
handleUploadError(jid, id, "Uploading file no longer exists or your system user has no permission to read it");
|
handleUploadError(jid, id, "Uploading file no longer exists or your system user has no permission to read it");
|
||||||
qDebug() << "Requested upload slot in account" << acc->name << "for file" << path << "but the file doesn't exist or is not readable";
|
qDebug() << "Requested upload slot in account" << acc->name << "for file" << path << "but the file doesn't exist or is not readable";
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
handleUploadError(jid, id, "Your server doesn't support file upload service, or it's prohibited for your account");
|
|
||||||
qDebug() << "Requested upload slot in account" << acc->name << "for file" << path << "but upload manager didn't discover any upload services";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
handleUploadError(data.getPenPalJid(), data.getId(), "Account is offline or reconnecting");
|
|
||||||
qDebug() << "An attempt to send message with not connected account " << acc->name << ", skipping";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::MessageHandler::onUploadSlotReceived(const QXmppHttpUploadSlotIq& slot)
|
void Core::MessageHandler::onUploadSlotReceived(const QXmppHttpUploadSlotIq& slot) {
|
||||||
{
|
|
||||||
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 {
|
||||||
@ -450,14 +511,12 @@ void Core::MessageHandler::onUploadSlotReceived(const QXmppHttpUploadSlotIq& slo
|
|||||||
acc->network->uploadFile({acc->name, palJid, mId}, pair.first, slot.putUrl(), slot.getUrl(), slot.putHeaders());
|
acc->network->uploadFile({acc->name, palJid, mId}, pair.first, slot.putUrl(), slot.getUrl(), slot.putHeaders());
|
||||||
|
|
||||||
uploadingSlotsQueue.pop_front();
|
uploadingSlotsQueue.pop_front();
|
||||||
if (uploadingSlotsQueue.size() > 0) {
|
if (uploadingSlotsQueue.size() > 0)
|
||||||
acc->um->requestUploadSlot(uploadingSlotsQueue.front().first);
|
acc->um->requestUploadSlot(uploadingSlotsQueue.front().first);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::MessageHandler::onUploadSlotRequestFailed(const QXmppHttpUploadRequestIq& request)
|
void Core::MessageHandler::onUploadSlotRequestFailed(const QXmppHttpUploadRequestIq& request) {
|
||||||
{
|
|
||||||
QString err(request.error().text());
|
QString err(request.error().text());
|
||||||
if (uploadingSlotsQueue.size() == 0) {
|
if (uploadingSlotsQueue.size() == 0) {
|
||||||
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";
|
||||||
@ -468,42 +527,38 @@ void Core::MessageHandler::onUploadSlotRequestFailed(const QXmppHttpUploadReques
|
|||||||
handleUploadError(pendingStateMessages.at(pair.second), pair.second, err);
|
handleUploadError(pendingStateMessages.at(pair.second), pair.second, err);
|
||||||
|
|
||||||
uploadingSlotsQueue.pop_front();
|
uploadingSlotsQueue.pop_front();
|
||||||
if (uploadingSlotsQueue.size() > 0) {
|
if (uploadingSlotsQueue.size() > 0)
|
||||||
acc->um->requestUploadSlot(uploadingSlotsQueue.front().first);
|
acc->um->requestUploadSlot(uploadingSlotsQueue.front().first);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::MessageHandler::onDownloadFileComplete(const std::list<Shared::MessageInfo>& msgs, const QString& path)
|
void Core::MessageHandler::onDownloadFileComplete(const std::list<Shared::MessageInfo>& msgs, const QString& path) {
|
||||||
{
|
|
||||||
QMap<QString, QVariant> cData = {
|
QMap<QString, QVariant> cData = {
|
||||||
{"attachPath", path}
|
{"attachPath", path}
|
||||||
};
|
};
|
||||||
for (const Shared::MessageInfo& info : msgs) {
|
for (const Shared::MessageInfo& info : msgs) {
|
||||||
if (info.account == acc->getName()) {
|
if (info.account != acc->getName())
|
||||||
|
continue;
|
||||||
|
|
||||||
RosterItem* cnt = acc->rh->getRosterItem(info.jid);
|
RosterItem* cnt = acc->rh->getRosterItem(info.jid);
|
||||||
if (cnt != 0) {
|
if (cnt != nullptr) {
|
||||||
if (cnt->changeMessage(info.messageId, cData)) {
|
bool changed = cnt->changeMessage(info.messageId, cData);
|
||||||
|
if (changed)
|
||||||
emit acc->changeMessage(info.jid, info.messageId, cData);
|
emit acc->changeMessage(info.jid, info.messageId, cData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::MessageHandler::onLoadFileError(const std::list<Shared::MessageInfo>& msgs, const QString& text, bool up)
|
void Core::MessageHandler::onLoadFileError(const std::list<Shared::MessageInfo>& msgs, const QString& text, bool up) {
|
||||||
{
|
if (!up)
|
||||||
if (up) {
|
return;
|
||||||
for (const Shared::MessageInfo& info : msgs) {
|
|
||||||
if (info.account == acc->getName()) {
|
for (const Shared::MessageInfo& info : msgs)
|
||||||
|
if (info.account == acc->getName())
|
||||||
handleUploadError(info.jid, info.messageId, text);
|
handleUploadError(info.jid, info.messageId, text);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::MessageHandler::handleUploadError(const QString& jid, const QString& messageId, const QString& errorText)
|
void Core::MessageHandler::handleUploadError(const QString& jid, const QString& messageId, const QString& errorText) {
|
||||||
{
|
|
||||||
emit acc->uploadFileError(jid, messageId, "Error requesting slot to upload file: " + errorText);
|
emit acc->uploadFileError(jid, messageId, "Error requesting slot to upload file: " + errorText);
|
||||||
pendingStateMessages.erase(messageId);
|
pendingStateMessages.erase(messageId);
|
||||||
pendingCorrectionMessages.erase(messageId);
|
pendingCorrectionMessages.erase(messageId);
|
||||||
@ -513,12 +568,13 @@ void Core::MessageHandler::handleUploadError(const QString& jid, const QString&
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::MessageHandler::onUploadFileComplete(const std::list<Shared::MessageInfo>& msgs, const QString& url, const QString& path)
|
void Core::MessageHandler::onUploadFileComplete(const std::list<Shared::MessageInfo>& msgs, const QString& url, const QString& path) {
|
||||||
{
|
|
||||||
for (const Shared::MessageInfo& info : msgs) {
|
for (const Shared::MessageInfo& info : msgs) {
|
||||||
if (info.account == acc->getName()) {
|
if (info.account != acc->getName())
|
||||||
|
continue;
|
||||||
|
|
||||||
RosterItem* ri = acc->rh->getRosterItem(info.jid);
|
RosterItem* ri = acc->rh->getRosterItem(info.jid);
|
||||||
if (ri != 0) {
|
if (ri != nullptr) {
|
||||||
Shared::Message msg = ri->getMessage(info.messageId);
|
Shared::Message msg = ri->getMessage(info.messageId);
|
||||||
msg.setAttachPath(path);
|
msg.setAttachPath(path);
|
||||||
sendMessageWithLocalUploadedFile(msg, url, false);
|
sendMessageWithLocalUploadedFile(msg, url, false);
|
||||||
@ -526,15 +582,13 @@ void Core::MessageHandler::onUploadFileComplete(const std::list<Shared::MessageI
|
|||||||
qDebug() << "A signal received about complete upload to" << acc->name << "for pal" << info.jid << "but the object for this pal wasn't found, something went terrebly wrong, skipping send";
|
qDebug() << "A signal received about complete upload to" << acc->name << "for pal" << info.jid << "but the object for this pal wasn't found, something went terrebly wrong, skipping send";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::MessageHandler::sendMessageWithLocalUploadedFile(Shared::Message msg, const QString& url, bool newMessage)
|
void Core::MessageHandler::sendMessageWithLocalUploadedFile(Shared::Message msg, const QString& url, bool newMessage) {
|
||||||
{
|
|
||||||
msg.setOutOfBandUrl(url);
|
msg.setOutOfBandUrl(url);
|
||||||
if (msg.getBody().size() == 0) { //not sure why, but most messages do that
|
if (msg.getBody().size() == 0) //not sure why, but most messengers do that
|
||||||
msg.setBody(url); //they duplicate oob in body, some of them wouldn't even show an attachment if you don't do that
|
msg.setBody(url); //they duplicate oob in body, some of them wouldn't even show an attachment if you don't do that
|
||||||
}
|
|
||||||
performSending(msg, pendingCorrectionMessages.at(msg.getId()), newMessage);
|
performSending(msg, pendingCorrectionMessages.at(msg.getId()), newMessage);
|
||||||
//TODO removal/progress update
|
//TODO removal/progress update
|
||||||
}
|
}
|
||||||
@ -546,10 +600,9 @@ static const std::set<QString> allowedToChangeKeys({
|
|||||||
"errorText"
|
"errorText"
|
||||||
});
|
});
|
||||||
|
|
||||||
void Core::MessageHandler::requestChangeMessage(const QString& jid, const QString& messageId, const QMap<QString, QVariant>& data)
|
void Core::MessageHandler::requestChangeMessage(const QString& jid, const QString& messageId, const QMap<QString, QVariant>& data) {
|
||||||
{
|
|
||||||
RosterItem* cnt = acc->rh->getRosterItem(jid);
|
RosterItem* cnt = acc->rh->getRosterItem(jid);
|
||||||
if (cnt != 0) {
|
if (cnt != nullptr) {
|
||||||
bool allSupported = true;
|
bool allSupported = true;
|
||||||
QString unsupportedString;
|
QString unsupportedString;
|
||||||
for (QMap<QString, QVariant>::const_iterator itr = data.begin(); itr != data.end(); ++itr) { //I need all this madness
|
for (QMap<QString, QVariant>::const_iterator itr = data.begin(); itr != data.end(); ++itr) { //I need all this madness
|
||||||
@ -569,14 +622,13 @@ void Core::MessageHandler::requestChangeMessage(const QString& jid, const QStrin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::MessageHandler::resendMessage(const QString& jid, const QString& id)
|
void Core::MessageHandler::resendMessage(const QString& jid, const QString& id) {
|
||||||
{
|
|
||||||
RosterItem* cnt = acc->rh->getRosterItem(jid);
|
RosterItem* cnt = acc->rh->getRosterItem(jid);
|
||||||
if (cnt != 0) {
|
if (cnt != nullptr) {
|
||||||
try {
|
try {
|
||||||
Shared::Message msg = cnt->getMessage(id);
|
Shared::Message msg = cnt->getMessage(id);
|
||||||
if (msg.getState() == Shared::Message::State::error) {
|
if (msg.getState() == Shared::Message::State::error) {
|
||||||
if (msg.getEdited()){
|
if (msg.getEdited()) {
|
||||||
QString originalId = msg.getId();
|
QString originalId = msg.getId();
|
||||||
msg.generateRandomId();
|
msg.generateRandomId();
|
||||||
sendMessage(msg, false, originalId);
|
sendMessage(msg, false, originalId);
|
||||||
@ -586,7 +638,7 @@ void Core::MessageHandler::resendMessage(const QString& jid, const QString& id)
|
|||||||
} else {
|
} else {
|
||||||
qDebug() << "An attempt to resend a message to" << jid << "by account" << acc->getName() << ", but this message seems to have been normally sent, this method was made to retry sending failed to be sent messages, skipping";
|
qDebug() << "An attempt to resend a message to" << jid << "by account" << acc->getName() << ", but this message seems to have been normally sent, this method was made to retry sending failed to be sent messages, skipping";
|
||||||
}
|
}
|
||||||
} catch (const Archive::NotFound& err) {
|
} catch (const LMDBAL::NotFound& err) {
|
||||||
qDebug() << "An attempt to resend a message to" << jid << "by account" << acc->getName() << ", but this message wasn't found in history, skipping";
|
qDebug() << "An attempt to resend a message to" << jid << "by account" << acc->getName() << ", but this message wasn't found in history, skipping";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -16,31 +16,29 @@
|
|||||||
* 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 CORE_MESSAGEHANDLER_H
|
#pragma once
|
||||||
#define CORE_MESSAGEHANDLER_H
|
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <functional>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
#include <QXmppMessage.h>
|
#include <QXmppMessage.h>
|
||||||
#include <QXmppHttpUploadIq.h>
|
#include <QXmppHttpUploadIq.h>
|
||||||
|
#ifdef WITH_OMEMO
|
||||||
|
#include <QXmppE2eeExtension.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <shared/message.h>
|
#include <shared/message.h>
|
||||||
#include <shared/messageinfo.h>
|
#include <shared/messageinfo.h>
|
||||||
#include <shared/pathcheck.h>
|
#include <shared/pathcheck.h>
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
/**
|
|
||||||
* @todo write docs
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Account;
|
class Account;
|
||||||
|
|
||||||
class MessageHandler : public QObject
|
class MessageHandler : public QObject {
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
MessageHandler(Account* account);
|
MessageHandler(Account* account);
|
||||||
@ -52,8 +50,10 @@ public:
|
|||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void onMessageReceived(const QXmppMessage& message);
|
void onMessageReceived(const QXmppMessage& message);
|
||||||
|
#if (QXMPP_VERSION) < QT_VERSION_CHECK(1, 5, 0)
|
||||||
void onCarbonMessageReceived(const QXmppMessage& message);
|
void onCarbonMessageReceived(const QXmppMessage& message);
|
||||||
void onCarbonMessageSent(const QXmppMessage& message);
|
void onCarbonMessageSent(const QXmppMessage& message);
|
||||||
|
#endif
|
||||||
void onReceiptReceived(const QString& jid, const QString& id);
|
void onReceiptReceived(const QString& jid, const QString& id);
|
||||||
void onUploadSlotReceived(const QXmppHttpUploadSlotIq& slot);
|
void onUploadSlotReceived(const QXmppHttpUploadSlotIq& slot);
|
||||||
void onUploadSlotRequestFailed(const QXmppHttpUploadRequestIq& request);
|
void onUploadSlotRequestFailed(const QXmppHttpUploadRequestIq& request);
|
||||||
@ -72,7 +72,10 @@ private:
|
|||||||
void handleUploadError(const QString& jid, const QString& messageId, const QString& errorText);
|
void handleUploadError(const QString& jid, const QString& messageId, const QString& errorText);
|
||||||
QXmppMessage createPacket(const Shared::Message& data, const QDateTime& time, const QString& originalId) const;
|
QXmppMessage createPacket(const Shared::Message& data, const QDateTime& time, const QString& originalId) const;
|
||||||
QMap<QString, QVariant> getChanges(Shared::Message& data, const QDateTime& time, bool newMessage, const QString& originalId) const;
|
QMap<QString, QVariant> getChanges(Shared::Message& data, const QDateTime& time, bool newMessage, const QString& originalId) const;
|
||||||
std::tuple<bool, QString, QString> getOriginalPendingMessageId(const QString& id);
|
std::optional<Shared::MessageInfo> getOriginalPendingMessageId(const QString& id, bool clear = true);
|
||||||
|
bool handlePendingMessageError(const QString& id, const QString& errorText);
|
||||||
|
std::pair<Shared::Message::State, QString> scheduleSending(const Shared::Message& message, const QDateTime& sendTime, const QString& originalId);
|
||||||
|
bool adjustPendingMessage(const QString& messageId, const QMap<QString, QVariant>& data, bool final);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Account* acc;
|
Account* acc;
|
||||||
@ -82,5 +85,3 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // CORE_MESSAGEHANDLER_H
|
|
||||||
|
285
core/handlers/omemohandler.cpp
Normal file
@ -0,0 +1,285 @@
|
|||||||
|
/*
|
||||||
|
* 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 <QDebug>
|
||||||
|
#include "omemohandler.h"
|
||||||
|
#include "core/account.h"
|
||||||
|
#include "core/adapterfunctions.h"
|
||||||
|
|
||||||
|
Core::OmemoHandler::OmemoHandler(Account* account) :
|
||||||
|
QObject(),
|
||||||
|
QXmppOmemoStorage(),
|
||||||
|
acc(account),
|
||||||
|
ownDevice(std::nullopt),
|
||||||
|
db(acc->getName() + "/omemo"),
|
||||||
|
meta(db.addCache<QString, QVariant>("meta")),
|
||||||
|
devices(db.addCache<QString, QHash<uint32_t, Device>>("devices")),
|
||||||
|
preKeyPairs(db.addCache<uint32_t, QByteArray>("preKeyPairs")),
|
||||||
|
signedPreKeyPairs(db.addCache<uint32_t, SignedPreKeyPair>("signedPreKeyPairs"))
|
||||||
|
{
|
||||||
|
db.open();
|
||||||
|
try {
|
||||||
|
QVariant own = meta->getRecord("ownDevice");
|
||||||
|
ownDevice = own.value<OwnDevice>();
|
||||||
|
qDebug() << "Successfully found own device omemo data for account" << acc->getName();
|
||||||
|
} catch (const LMDBAL::NotFound& e) {
|
||||||
|
qDebug() << "No device omemo data was found for account" << acc->getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Core::OmemoHandler::~OmemoHandler() {
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Core::OmemoHandler::hasOwnDevice() {
|
||||||
|
return ownDevice.has_value();
|
||||||
|
}
|
||||||
|
|
||||||
|
QXmppTask<QXmppOmemoStorage::OmemoData> Core::OmemoHandler::allData() {
|
||||||
|
OmemoData data;
|
||||||
|
data.ownDevice = ownDevice;
|
||||||
|
|
||||||
|
LMDBAL::Transaction txn = db.beginReadOnlyTransaction();
|
||||||
|
std::map<uint32_t, QByteArray> pkeys = preKeyPairs->readAll(txn);
|
||||||
|
for (const std::pair<const uint32_t, QByteArray>& pair : pkeys)
|
||||||
|
data.preKeyPairs.insert(pair.first, pair.second);
|
||||||
|
|
||||||
|
std::map<uint32_t, SignedPreKeyPair> spre = signedPreKeyPairs->readAll(txn);
|
||||||
|
for (const std::pair<const uint32_t, SignedPreKeyPair>& pair : spre) {
|
||||||
|
QXmppOmemoStorage::SignedPreKeyPair qxpair = {pair.second.first, pair.second.second};
|
||||||
|
data.signedPreKeyPairs.insert(pair.first, qxpair);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<QString, QHash<uint32_t, Device>> devs = devices->readAll(txn);
|
||||||
|
for (const std::pair<const QString, QHash<uint32_t, Device>>& pair : devs)
|
||||||
|
data.devices.insert(pair.first, pair.second);
|
||||||
|
|
||||||
|
return Core::makeReadyTask(std::move(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
QXmppTask<void> Core::OmemoHandler::addDevice(const QString& jid, uint32_t deviceId, const QXmppOmemoStorage::Device& device) {
|
||||||
|
QHash<uint32_t, Device> devs;
|
||||||
|
LMDBAL::WriteTransaction txn = db.beginTransaction();
|
||||||
|
bool had = true;
|
||||||
|
try {
|
||||||
|
devices->getRecord(jid, devs, txn);
|
||||||
|
} catch (const LMDBAL::NotFound& error) {
|
||||||
|
had = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
devs.insert(deviceId, device); //overwrites
|
||||||
|
if (had)
|
||||||
|
devices->changeRecord(jid, devs, txn);
|
||||||
|
else
|
||||||
|
devices->addRecord(jid, devs, txn);
|
||||||
|
|
||||||
|
txn.commit();
|
||||||
|
return Core::makeReadyTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
QXmppTask<void> Core::OmemoHandler::addPreKeyPairs(const QHash<uint32_t, QByteArray>& keyPairs) {
|
||||||
|
LMDBAL::WriteTransaction txn = db.beginTransaction();
|
||||||
|
for (QHash<uint32_t, QByteArray>::const_iterator itr = keyPairs.begin(), end = keyPairs.end(); itr != end; ++itr)
|
||||||
|
preKeyPairs->forceRecord(itr.key(), itr.value(), txn);
|
||||||
|
|
||||||
|
txn.commit();
|
||||||
|
return Core::makeReadyTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
QXmppTask<void> Core::OmemoHandler::addSignedPreKeyPair(uint32_t keyId, const QXmppOmemoStorage::SignedPreKeyPair& keyPair) {
|
||||||
|
signedPreKeyPairs->forceRecord(keyId, std::make_pair(keyPair.creationDate, keyPair.data));
|
||||||
|
return Core::makeReadyTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
QXmppTask<void> Core::OmemoHandler::removeDevice(const QString& jid, uint32_t deviceId) {
|
||||||
|
LMDBAL::WriteTransaction txn = db.beginTransaction();
|
||||||
|
QHash<uint32_t, Device> devs = devices->getRecord(jid, txn);
|
||||||
|
devs.remove(deviceId);
|
||||||
|
if (devs.isEmpty())
|
||||||
|
devices->removeRecord(jid, txn);
|
||||||
|
else
|
||||||
|
devices->changeRecord(jid, devs, txn);
|
||||||
|
|
||||||
|
txn.commit();
|
||||||
|
return Core::makeReadyTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
QXmppTask<void> Core::OmemoHandler::removeDevices(const QString& jid) {
|
||||||
|
devices->removeRecord(jid);
|
||||||
|
return Core::makeReadyTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
QXmppTask<void> Core::OmemoHandler::removePreKeyPair(uint32_t keyId) {
|
||||||
|
try {
|
||||||
|
preKeyPairs->removeRecord(keyId);
|
||||||
|
} catch (const LMDBAL::NotFound& e) {
|
||||||
|
qDebug() << "Couldn't remove preKeyPair " << e.what();
|
||||||
|
}
|
||||||
|
return Core::makeReadyTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
QXmppTask<void> Core::OmemoHandler::removeSignedPreKeyPair(uint32_t keyId) {
|
||||||
|
try {
|
||||||
|
signedPreKeyPairs->removeRecord(keyId);
|
||||||
|
} catch (const LMDBAL::NotFound& e) {}
|
||||||
|
return Core::makeReadyTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
QXmppTask<void> Core::OmemoHandler::setOwnDevice(const std::optional<OwnDevice>& device) {
|
||||||
|
bool had = ownDevice.has_value();
|
||||||
|
ownDevice = device;
|
||||||
|
if (ownDevice.has_value()) {
|
||||||
|
if (had)
|
||||||
|
meta->changeRecord("ownDevice", QVariant::fromValue(ownDevice.value()));
|
||||||
|
else
|
||||||
|
meta->addRecord("ownDevice", QVariant::fromValue(ownDevice.value()));
|
||||||
|
} else if (had) {
|
||||||
|
meta->removeRecord("ownDevice");
|
||||||
|
}
|
||||||
|
return Core::makeReadyTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
QXmppTask<void> Core::OmemoHandler::resetAll() {
|
||||||
|
ownDevice = std::nullopt;
|
||||||
|
db.drop();
|
||||||
|
|
||||||
|
return Core::makeReadyTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::OmemoHandler::getDevices(const QString& jid, std::list<Shared::KeyInfo>& out) const {
|
||||||
|
QHash<uint32_t, Device> devs;
|
||||||
|
try {
|
||||||
|
devices->getRecord(jid, devs);
|
||||||
|
} catch (const LMDBAL::NotFound& error) {}
|
||||||
|
|
||||||
|
for (QHash<uint32_t, Device>::const_iterator itr = devs.begin(), end = devs.end(); itr != end; ++itr) {
|
||||||
|
const Device& dev = itr.value();
|
||||||
|
out.emplace_back(
|
||||||
|
itr.key(),
|
||||||
|
dev.keyId,
|
||||||
|
dev.label,
|
||||||
|
dev.removalFromDeviceListDate,
|
||||||
|
Shared::TrustLevel::undecided,
|
||||||
|
Shared::EncryptionProtocol::omemo2,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::OmemoHandler::requestBundles(const QString& jid) {
|
||||||
|
QXmppTask<void> task = acc->om->buildMissingSessions({jid});
|
||||||
|
Contact* cnt = acc->rh->getContact(jid);
|
||||||
|
if (cnt)
|
||||||
|
cnt->omemoBundles = Shared::Possible::discovering;
|
||||||
|
|
||||||
|
task.then(this, std::bind(&OmemoHandler::onBundlesReceived, this, jid));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::OmemoHandler::requestOwnBundles() {
|
||||||
|
QXmppTask<void> task = acc->om->buildMissingSessions({acc->getBareJid()});
|
||||||
|
task.then(this, std::bind(&OmemoHandler::onOwnBundlesReceived, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::OmemoHandler::onBundlesReceived(const QString& jid) {
|
||||||
|
std::list<Shared::KeyInfo> keys = readKeys(jid);
|
||||||
|
|
||||||
|
Contact* cnt = acc->rh->getContact(jid);
|
||||||
|
if (cnt)
|
||||||
|
cnt->omemoBundles = Shared::Possible::present;
|
||||||
|
|
||||||
|
acc->delay->receivedBundles(jid, keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::OmemoHandler::onOwnBundlesReceived() {
|
||||||
|
std::list<Shared::KeyInfo> keys = readKeys(acc->getBareJid());
|
||||||
|
if (ownDevice)
|
||||||
|
keys.emplace_front(
|
||||||
|
ownDevice->id,
|
||||||
|
ownDevice->publicIdentityKey,
|
||||||
|
ownDevice->label,
|
||||||
|
QDateTime::currentDateTime(),
|
||||||
|
Shared::TrustLevel::authenticated,
|
||||||
|
Shared::EncryptionProtocol::omemo2,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
acc->delay->receivedOwnBundles(keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<Shared::KeyInfo> Core::OmemoHandler::readKeys(const QString& jid) {
|
||||||
|
std::list<Shared::KeyInfo> keys;
|
||||||
|
getDevices(jid, keys);
|
||||||
|
std::map<QByteArray, Shared::TrustLevel> trustLevels = acc->th->getKeys(Shared::EncryptionProtocol::omemo2, jid);
|
||||||
|
|
||||||
|
for (Shared::KeyInfo& key : keys) {
|
||||||
|
std::map<QByteArray, Shared::TrustLevel>::const_iterator itr = trustLevels.find(key.fingerPrint);
|
||||||
|
if (itr != trustLevels.end())
|
||||||
|
key.trustLevel = itr->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::OmemoHandler::onOmemoDeviceAdded(const QString& jid, uint32_t id) {
|
||||||
|
SHARED_UNUSED(id);
|
||||||
|
qDebug() << "OMEMO device added for" << jid;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDataStream & operator >> (QDataStream& in, QXmppOmemoStorage::Device& device) {
|
||||||
|
in >> device.label;
|
||||||
|
in >> device.keyId;
|
||||||
|
in >> device.session;
|
||||||
|
in >> device.unrespondedSentStanzasCount;
|
||||||
|
in >> device.unrespondedReceivedStanzasCount;
|
||||||
|
in >> device.removalFromDeviceListDate;
|
||||||
|
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDataStream & operator << (QDataStream& out, const QXmppOmemoStorage::Device& device) {
|
||||||
|
out << device.label;
|
||||||
|
out << device.keyId;
|
||||||
|
out << device.session;
|
||||||
|
out << device.unrespondedSentStanzasCount;
|
||||||
|
out << device.unrespondedReceivedStanzasCount;
|
||||||
|
out << device.removalFromDeviceListDate;
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDataStream & operator >> (QDataStream& in, QXmppOmemoStorage::OwnDevice& device) {
|
||||||
|
in >> device.id;
|
||||||
|
in >> device.label;
|
||||||
|
in >> device.privateIdentityKey;
|
||||||
|
in >> device.publicIdentityKey;
|
||||||
|
in >> device.latestSignedPreKeyId;
|
||||||
|
in >> device.latestPreKeyId;
|
||||||
|
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDataStream & operator << (QDataStream& out, const QXmppOmemoStorage::OwnDevice& device) {
|
||||||
|
out << device.id;
|
||||||
|
out << device.label;
|
||||||
|
out << device.privateIdentityKey;
|
||||||
|
out << device.publicIdentityKey;
|
||||||
|
out << device.latestSignedPreKeyId;
|
||||||
|
out << device.latestPreKeyId;
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
90
core/handlers/omemohandler.h
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* 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 <map>
|
||||||
|
#include <list>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include <QXmppOmemoStorage.h>
|
||||||
|
#include <cache.h>
|
||||||
|
|
||||||
|
#include <shared/keyinfo.h>
|
||||||
|
#include <shared/enums.h>
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(QXmppOmemoStorage::OwnDevice);
|
||||||
|
Q_DECLARE_METATYPE(QXmppOmemoStorage::Device);
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class Account;
|
||||||
|
|
||||||
|
class OmemoHandler : public QObject, public QXmppOmemoStorage {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
typedef std::pair<QDateTime, QByteArray> SignedPreKeyPair;
|
||||||
|
|
||||||
|
OmemoHandler(Account* account);
|
||||||
|
~OmemoHandler() override;
|
||||||
|
|
||||||
|
virtual QXmppTask<OmemoData> allData() override;
|
||||||
|
|
||||||
|
virtual QXmppTask<void> setOwnDevice(const std::optional<OwnDevice> &device) override;
|
||||||
|
|
||||||
|
virtual QXmppTask<void> addSignedPreKeyPair(uint32_t keyId, const QXmppOmemoStorage::SignedPreKeyPair &keyPair) override;
|
||||||
|
virtual QXmppTask<void> removeSignedPreKeyPair(uint32_t keyId) override;
|
||||||
|
|
||||||
|
virtual QXmppTask<void> addPreKeyPairs(const QHash<uint32_t, QByteArray> &keyPairs) override;
|
||||||
|
virtual QXmppTask<void> removePreKeyPair(uint32_t keyId) override;
|
||||||
|
|
||||||
|
virtual QXmppTask<void> addDevice(const QString &jid, uint32_t deviceId, const Device &device) override;
|
||||||
|
virtual QXmppTask<void> removeDevice(const QString &jid, uint32_t deviceId) override;
|
||||||
|
virtual QXmppTask<void> removeDevices(const QString &jid) override;
|
||||||
|
|
||||||
|
virtual QXmppTask<void> resetAll() override;
|
||||||
|
|
||||||
|
bool hasOwnDevice();
|
||||||
|
|
||||||
|
void requestBundles(const QString& jid);
|
||||||
|
void requestOwnBundles();
|
||||||
|
void getDevices(const QString& jid, std::list<Shared::KeyInfo>& out) const;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void onOmemoDeviceAdded(const QString& jid, uint32_t id);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onBundlesReceived(const QString& jid);
|
||||||
|
void onOwnBundlesReceived();
|
||||||
|
std::list<Shared::KeyInfo> readKeys(const QString& jid);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Account* acc;
|
||||||
|
std::optional<OwnDevice> ownDevice;
|
||||||
|
LMDBAL::Base db;
|
||||||
|
LMDBAL::Cache<QString, QVariant>* meta;
|
||||||
|
LMDBAL::Cache<QString, QHash<uint32_t, Device>>* devices;
|
||||||
|
LMDBAL::Cache<uint32_t, QByteArray>* preKeyPairs;
|
||||||
|
LMDBAL::Cache<uint32_t, SignedPreKeyPair>* signedPreKeyPairs;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QDataStream& operator << (QDataStream &out, const QXmppOmemoStorage::Device& device);
|
||||||
|
QDataStream& operator >> (QDataStream &in, QXmppOmemoStorage::Device& device);
|
||||||
|
|
||||||
|
QDataStream& operator << (QDataStream &out, const QXmppOmemoStorage::OwnDevice& device);
|
||||||
|
QDataStream& operator >> (QDataStream &in, QXmppOmemoStorage::OwnDevice& device);
|
@ -26,9 +26,9 @@ Core::RosterHandler::RosterHandler(Core::Account* account):
|
|||||||
conferences(),
|
conferences(),
|
||||||
groups(),
|
groups(),
|
||||||
queuedContacts(),
|
queuedContacts(),
|
||||||
outOfRosterContacts(),
|
outOfRosterContacts() {}
|
||||||
pepSupport(false)
|
|
||||||
{
|
void Core::RosterHandler::initialize() {
|
||||||
connect(acc->rm, &QXmppRosterManager::rosterReceived, this, &RosterHandler::onRosterReceived);
|
connect(acc->rm, &QXmppRosterManager::rosterReceived, this, &RosterHandler::onRosterReceived);
|
||||||
connect(acc->rm, &QXmppRosterManager::itemAdded, this, &RosterHandler::onRosterItemAdded);
|
connect(acc->rm, &QXmppRosterManager::itemAdded, this, &RosterHandler::onRosterItemAdded);
|
||||||
connect(acc->rm, &QXmppRosterManager::itemRemoved, this, &RosterHandler::onRosterItemRemoved);
|
connect(acc->rm, &QXmppRosterManager::itemRemoved, this, &RosterHandler::onRosterItemRemoved);
|
||||||
@ -37,23 +37,30 @@ Core::RosterHandler::RosterHandler(Core::Account* account):
|
|||||||
|
|
||||||
connect(acc->mm, &QXmppMucManager::roomAdded, this, &RosterHandler::onMucRoomAdded);
|
connect(acc->mm, &QXmppMucManager::roomAdded, this, &RosterHandler::onMucRoomAdded);
|
||||||
connect(acc->bm, &QXmppBookmarkManager::bookmarksReceived, this, &RosterHandler::bookmarksReceived);
|
connect(acc->bm, &QXmppBookmarkManager::bookmarksReceived, this, &RosterHandler::bookmarksReceived);
|
||||||
|
|
||||||
|
connect(acc, &Account::pepSupportChanged, this, &RosterHandler::onPepSupportedChanged);
|
||||||
|
|
||||||
|
#if (QXMPP_VERSION) >= QT_VERSION_CHECK(1, 5, 0)
|
||||||
|
connect(acc->th, &TrustHandler::trustLevelsChanged, this, &RosterHandler::onTrustChanged);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::RosterHandler::~RosterHandler()
|
Core::RosterHandler::~RosterHandler() {
|
||||||
{
|
clear();
|
||||||
for (std::map<QString, Contact*>::const_iterator itr = contacts.begin(), end = contacts.end(); itr != end; ++itr) {
|
|
||||||
delete itr->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (std::map<QString, Conference*>::const_iterator itr = conferences.begin(), end = conferences.end(); itr != end; ++itr) {
|
|
||||||
delete itr->second;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterHandler::onRosterReceived()
|
void Core::RosterHandler::clear() {
|
||||||
{
|
for (const std::pair<const QString, Contact*>& pair : contacts)
|
||||||
acc->requestVCard(acc->getBareJid()); //TODO need to make sure server actually supports vCards
|
delete pair.second;
|
||||||
|
|
||||||
|
for (const std::pair<const QString, Conference*>& pair : conferences)
|
||||||
|
delete pair.second;
|
||||||
|
|
||||||
|
contacts.clear();
|
||||||
|
conferences.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::RosterHandler::onRosterReceived() {
|
||||||
QStringList bj = acc->rm->getRosterBareJids();
|
QStringList bj = acc->rm->getRosterBareJids();
|
||||||
for (int i = 0; i < bj.size(); ++i) {
|
for (int i = 0; i < bj.size(); ++i) {
|
||||||
const QString& jid = bj[i];
|
const QString& jid = bj[i];
|
||||||
@ -61,8 +68,7 @@ void Core::RosterHandler::onRosterReceived()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterHandler::onRosterItemAdded(const QString& bareJid)
|
void Core::RosterHandler::onRosterItemAdded(const QString& bareJid) {
|
||||||
{
|
|
||||||
QString lcJid = bareJid.toLower();
|
QString lcJid = bareJid.toLower();
|
||||||
addedAccount(lcJid);
|
addedAccount(lcJid);
|
||||||
std::map<QString, QString>::const_iterator itr = queuedContacts.find(lcJid);
|
std::map<QString, QString>::const_iterator itr = queuedContacts.find(lcJid);
|
||||||
@ -72,8 +78,7 @@ void Core::RosterHandler::onRosterItemAdded(const QString& bareJid)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterHandler::addedAccount(const QString& jid)
|
void Core::RosterHandler::addedAccount(const QString& jid) {
|
||||||
{
|
|
||||||
std::map<QString, Contact*>::const_iterator itr = contacts.find(jid);
|
std::map<QString, Contact*>::const_iterator itr = contacts.find(jid);
|
||||||
QXmppRosterIq::Item re = acc->rm->getRosterEntry(jid);
|
QXmppRosterIq::Item re = acc->rm->getRosterEntry(jid);
|
||||||
Contact* contact;
|
Contact* contact;
|
||||||
@ -82,7 +87,6 @@ void Core::RosterHandler::addedAccount(const QString& jid)
|
|||||||
newContact = true;
|
newContact = true;
|
||||||
contact = new Contact(jid, acc->name);
|
contact = new Contact(jid, acc->name);
|
||||||
contacts.insert(std::make_pair(jid, contact));
|
contacts.insert(std::make_pair(jid, contact));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
contact = itr->second;
|
contact = itr->second;
|
||||||
}
|
}
|
||||||
@ -94,70 +98,44 @@ void Core::RosterHandler::addedAccount(const QString& jid)
|
|||||||
contact->setName(re.name());
|
contact->setName(re.name());
|
||||||
|
|
||||||
if (newContact) {
|
if (newContact) {
|
||||||
QMap<QString, QVariant> cData({
|
handleNewContact(contact);
|
||||||
{"name", re.name()},
|
QMap<QString, QVariant> cData = contact->getInfo();
|
||||||
{"state", QVariant::fromValue(state)}
|
#if (QXMPP_VERSION) >= QT_VERSION_CHECK(1, 5, 0)
|
||||||
});
|
cData.insert("trust", QVariant::fromValue(acc->th->getSummary(jid)));
|
||||||
|
#endif
|
||||||
careAboutAvatar(contact, cData);
|
|
||||||
int grCount = 0;
|
int grCount = 0;
|
||||||
for (QSet<QString>::const_iterator itr = gr.begin(), end = gr.end(); itr != end; ++itr) {
|
for (const QString& groupName : gr) {
|
||||||
const QString& groupName = *itr;
|
|
||||||
addToGroup(jid, groupName);
|
addToGroup(jid, groupName);
|
||||||
emit acc->addContact(jid, groupName, cData);
|
emit acc->addContact(jid, groupName, cData);
|
||||||
grCount++;
|
grCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (grCount == 0) {
|
if (grCount == 0)
|
||||||
emit acc->addContact(jid, "", cData);
|
emit acc->addContact(jid, "", cData);
|
||||||
|
|
||||||
|
if (acc->pepSupport == Shared::Support::supported) {
|
||||||
|
acc->dm->requestInfo(jid);
|
||||||
|
//acc->dm->requestItems(jid);
|
||||||
}
|
}
|
||||||
handleNewContact(contact);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterHandler::addNewRoom(const QString& jid, const QString& nick, const QString& roomName, bool autoJoin)
|
void Core::RosterHandler::addNewRoom(const QString& jid, const QString& nick, const QString& roomName, bool autoJoin) {
|
||||||
{
|
|
||||||
QXmppMucRoom* room = acc->mm->addRoom(jid);
|
QXmppMucRoom* room = acc->mm->addRoom(jid);
|
||||||
QString lNick = nick;
|
QString lNick = nick;
|
||||||
if (lNick.size() == 0) {
|
if (lNick.size() == 0)
|
||||||
lNick = acc->getName();
|
lNick = acc->getName();
|
||||||
}
|
|
||||||
Conference* conf = new Conference(jid, acc->getName(), autoJoin, roomName, lNick, room);
|
Conference* conf = new Conference(jid, acc->getName(), autoJoin, roomName, lNick, room);
|
||||||
conferences.insert(std::make_pair(jid, conf));
|
conferences.insert(std::make_pair(jid, conf));
|
||||||
|
|
||||||
handleNewConference(conf);
|
handleNewConference(conf);
|
||||||
|
|
||||||
QMap<QString, QVariant> cData = {
|
QMap<QString, QVariant> cData = conf->getInfo();
|
||||||
{"autoJoin", conf->getAutoJoin()},
|
|
||||||
{"joined", conf->getJoined()},
|
|
||||||
{"nick", conf->getNick()},
|
|
||||||
{"name", conf->getName()},
|
|
||||||
{"avatars", conf->getAllAvatars()}
|
|
||||||
};
|
|
||||||
careAboutAvatar(conf, cData);
|
|
||||||
emit acc->addRoom(jid, cData);
|
emit acc->addRoom(jid, cData);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterHandler::careAboutAvatar(Core::RosterItem* item, QMap<QString, QVariant>& data)
|
void Core::RosterHandler::addContactRequest(const QString& jid, const QString& name, const QSet<QString>& groups) {
|
||||||
{
|
|
||||||
Archive::AvatarInfo info;
|
|
||||||
bool hasAvatar = item->readAvatarInfo(info);
|
|
||||||
if (hasAvatar) {
|
|
||||||
if (info.autogenerated) {
|
|
||||||
data.insert("avatarState", QVariant::fromValue(Shared::Avatar::autocreated));
|
|
||||||
} else {
|
|
||||||
data.insert("avatarState", QVariant::fromValue(Shared::Avatar::valid));
|
|
||||||
}
|
|
||||||
data.insert("avatarPath", item->avatarPath() + "." + info.type);
|
|
||||||
} else {
|
|
||||||
data.insert("avatarState", QVariant::fromValue(Shared::Avatar::empty));
|
|
||||||
data.insert("avatarPath", "");
|
|
||||||
acc->requestVCard(item->jid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::RosterHandler::addContactRequest(const QString& jid, const QString& name, const QSet<QString>& groups)
|
|
||||||
{
|
|
||||||
if (acc->state == Shared::ConnectionState::connected) {
|
if (acc->state == Shared::ConnectionState::connected) {
|
||||||
std::map<QString, QString>::const_iterator itr = queuedContacts.find(jid);
|
std::map<QString, QString>::const_iterator itr = queuedContacts.find(jid);
|
||||||
if (itr != queuedContacts.end()) {
|
if (itr != queuedContacts.end()) {
|
||||||
@ -171,8 +149,7 @@ void Core::RosterHandler::addContactRequest(const QString& jid, const QString& n
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterHandler::removeContactRequest(const QString& jid)
|
void Core::RosterHandler::removeContactRequest(const QString& jid) {
|
||||||
{
|
|
||||||
QString lcJid = jid.toLower();
|
QString lcJid = jid.toLower();
|
||||||
if (acc->state == Shared::ConnectionState::connected) {
|
if (acc->state == Shared::ConnectionState::connected) {
|
||||||
std::set<QString>::const_iterator itr = outOfRosterContacts.find(lcJid);
|
std::set<QString>::const_iterator itr = outOfRosterContacts.find(lcJid);
|
||||||
@ -187,25 +164,23 @@ void Core::RosterHandler::removeContactRequest(const QString& jid)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterHandler::handleNewRosterItem(Core::RosterItem* contact)
|
void Core::RosterHandler::handleNewRosterItem(Core::RosterItem* contact) {
|
||||||
{
|
|
||||||
connect(contact, &RosterItem::needHistory, this->acc, &Account::onContactNeedHistory);
|
connect(contact, &RosterItem::needHistory, this->acc, &Account::onContactNeedHistory);
|
||||||
connect(contact, &RosterItem::historyResponse, this->acc, &Account::onContactHistoryResponse);
|
connect(contact, &RosterItem::historyResponse, this->acc, &Account::onContactHistoryResponse);
|
||||||
connect(contact, &RosterItem::nameChanged, this, &RosterHandler::onContactNameChanged);
|
connect(contact, &RosterItem::nameChanged, this, &RosterHandler::onContactNameChanged);
|
||||||
connect(contact, &RosterItem::avatarChanged, this, &RosterHandler::onContactAvatarChanged);
|
connect(contact, &RosterItem::avatarChanged, this, &RosterHandler::onContactAvatarChanged);
|
||||||
connect(contact, &RosterItem::requestVCard, this->acc, &Account::requestVCard);
|
connect(contact, &RosterItem::encryptionChanged, this, &RosterHandler::onContactEncryptionChanged);
|
||||||
|
connect(contact, &RosterItem::requestVCard, acc->delay, &DelayManager::Manager::getVCard);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterHandler::handleNewContact(Core::Contact* contact)
|
void Core::RosterHandler::handleNewContact(Core::Contact* contact) {
|
||||||
{
|
|
||||||
handleNewRosterItem(contact);
|
handleNewRosterItem(contact);
|
||||||
connect(contact, &Contact::groupAdded, this, &RosterHandler::onContactGroupAdded);
|
connect(contact, &Contact::groupAdded, this, &RosterHandler::onContactGroupAdded);
|
||||||
connect(contact, &Contact::groupRemoved, this, &RosterHandler::onContactGroupRemoved);
|
connect(contact, &Contact::groupRemoved, this, &RosterHandler::onContactGroupRemoved);
|
||||||
connect(contact, &Contact::subscriptionStateChanged, this, &RosterHandler::onContactSubscriptionStateChanged);
|
connect(contact, &Contact::subscriptionStateChanged, this, &RosterHandler::onContactSubscriptionStateChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterHandler::handleNewConference(Core::Conference* contact)
|
void Core::RosterHandler::handleNewConference(Core::Conference* contact) {
|
||||||
{
|
|
||||||
handleNewRosterItem(contact);
|
handleNewRosterItem(contact);
|
||||||
connect(contact, &Conference::nickChanged, this, &RosterHandler::onMucNickNameChanged);
|
connect(contact, &Conference::nickChanged, this, &RosterHandler::onMucNickNameChanged);
|
||||||
connect(contact, &Conference::subjectChanged, this, &RosterHandler::onMucSubjectChanged);
|
connect(contact, &Conference::subjectChanged, this, &RosterHandler::onMucSubjectChanged);
|
||||||
@ -216,34 +191,27 @@ void Core::RosterHandler::handleNewConference(Core::Conference* contact)
|
|||||||
connect(contact, &Conference::removeParticipant, this, &RosterHandler::onMucRemoveParticipant);
|
connect(contact, &Conference::removeParticipant, this, &RosterHandler::onMucRemoveParticipant);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterHandler::onMucAddParticipant(const QString& nickName, const QMap<QString, QVariant>& data)
|
void Core::RosterHandler::onMucAddParticipant(const QString& nickName, const QMap<QString, QVariant>& data) {
|
||||||
{
|
|
||||||
Conference* room = static_cast<Conference*>(sender());
|
Conference* room = static_cast<Conference*>(sender());
|
||||||
emit acc->addRoomParticipant(room->jid, nickName, data);
|
emit acc->addRoomParticipant(room->jid, nickName, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterHandler::onMucChangeParticipant(const QString& nickName, const QMap<QString, QVariant>& data)
|
void Core::RosterHandler::onMucChangeParticipant(const QString& nickName, const QMap<QString, QVariant>& data) {
|
||||||
{
|
|
||||||
Conference* room = static_cast<Conference*>(sender());
|
Conference* room = static_cast<Conference*>(sender());
|
||||||
emit acc->changeRoomParticipant(room->jid, nickName, data);
|
emit acc->changeRoomParticipant(room->jid, nickName, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterHandler::onMucRemoveParticipant(const QString& nickName)
|
void Core::RosterHandler::onMucRemoveParticipant(const QString& nickName) {
|
||||||
{
|
|
||||||
Conference* room = static_cast<Conference*>(sender());
|
Conference* room = static_cast<Conference*>(sender());
|
||||||
emit acc->removeRoomParticipant(room->jid, nickName);
|
emit acc->removeRoomParticipant(room->jid, nickName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterHandler::onMucSubjectChanged(const QString& subject)
|
void Core::RosterHandler::onMucSubjectChanged(const QString& subject) {
|
||||||
{
|
|
||||||
Conference* room = static_cast<Conference*>(sender());
|
Conference* room = static_cast<Conference*>(sender());
|
||||||
emit acc->changeRoom(room->jid, {
|
emit acc->changeRoom(room->jid, {{"subject", subject}});
|
||||||
{"subject", subject}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterHandler::onContactGroupAdded(const QString& group)
|
void Core::RosterHandler::onContactGroupAdded(const QString& group) {
|
||||||
{
|
|
||||||
Contact* contact = static_cast<Contact*>(sender());
|
Contact* contact = static_cast<Contact*>(sender());
|
||||||
if (contact->groupsCount() == 1) {
|
if (contact->groupsCount() == 1) {
|
||||||
// not sure i need to handle it here, the situation with grouped and ungrouped contacts handled on the client anyway
|
// not sure i need to handle it here, the situation with grouped and ungrouped contacts handled on the client anyway
|
||||||
@ -251,14 +219,17 @@ void Core::RosterHandler::onContactGroupAdded(const QString& group)
|
|||||||
|
|
||||||
QMap<QString, QVariant> cData({
|
QMap<QString, QVariant> cData({
|
||||||
{"name", contact->getName()},
|
{"name", contact->getName()},
|
||||||
{"state", QVariant::fromValue(contact->getSubscriptionState())}
|
{"state", QVariant::fromValue(contact->getSubscriptionState())},
|
||||||
|
#if (QXMPP_VERSION) >= QT_VERSION_CHECK(1, 5, 0)
|
||||||
|
{"trust", QVariant::fromValue(acc->th->getSummary(contact->jid))},
|
||||||
|
#endif
|
||||||
|
{"encryption", QVariant::fromValue(contact->encryption())}
|
||||||
});
|
});
|
||||||
addToGroup(contact->jid, group);
|
addToGroup(contact->jid, group);
|
||||||
emit acc->addContact(contact->jid, group, cData);
|
emit acc->addContact(contact->jid, group, cData);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterHandler::onContactGroupRemoved(const QString& group)
|
void Core::RosterHandler::onContactGroupRemoved(const QString& group) {
|
||||||
{
|
|
||||||
Contact* contact = static_cast<Contact*>(sender());
|
Contact* contact = static_cast<Contact*>(sender());
|
||||||
if (contact->groupsCount() == 0) {
|
if (contact->groupsCount() == 0) {
|
||||||
// not sure i need to handle it here, the situation with grouped and ungrouped contacts handled on the client anyway
|
// not sure i need to handle it here, the situation with grouped and ungrouped contacts handled on the client anyway
|
||||||
@ -268,26 +239,26 @@ void Core::RosterHandler::onContactGroupRemoved(const QString& group)
|
|||||||
removeFromGroup(contact->jid, group);
|
removeFromGroup(contact->jid, group);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterHandler::onContactNameChanged(const QString& cname)
|
void Core::RosterHandler::onContactNameChanged(const QString& cname) {
|
||||||
{
|
RosterItem* contact = static_cast<RosterItem*>(sender());
|
||||||
Contact* contact = static_cast<Contact*>(sender());
|
emit acc->changeContact(contact->jid, {{"name", cname}});
|
||||||
QMap<QString, QVariant> cData({
|
|
||||||
{"name", cname},
|
|
||||||
});
|
|
||||||
emit acc->changeContact(contact->jid, cData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterHandler::onContactSubscriptionStateChanged(Shared::SubscriptionState cstate)
|
void Core::RosterHandler::onContactEncryptionChanged(Shared::EncryptionProtocol value) {
|
||||||
{
|
RosterItem* contact = static_cast<RosterItem*>(sender());
|
||||||
Contact* contact = static_cast<Contact*>(sender());
|
emit acc->changeContact(contact->jid, {{"encryption", QVariant::fromValue(value)}});
|
||||||
QMap<QString, QVariant> cData({
|
|
||||||
{"state", QVariant::fromValue(cstate)},
|
|
||||||
});
|
|
||||||
emit acc->changeContact(contact->jid, cData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterHandler::addToGroup(const QString& jid, const QString& group)
|
void Core::RosterHandler::onContactSubscriptionStateChanged(Shared::SubscriptionState cstate) {
|
||||||
{
|
Contact* contact = static_cast<Contact*>(sender());
|
||||||
|
emit acc->changeContact(contact->jid, {{"state", QVariant::fromValue(cstate)}});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::RosterHandler::onTrustChanged(const QString& jid, const Shared::TrustSummary& trust) {
|
||||||
|
emit acc->changeContact(jid, {{"trust", QVariant::fromValue(trust)}});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::RosterHandler::addToGroup(const QString& jid, const QString& group) {
|
||||||
std::map<QString, std::set<QString>>::iterator gItr = groups.find(group);
|
std::map<QString, std::set<QString>>::iterator gItr = groups.find(group);
|
||||||
if (gItr == groups.end()) {
|
if (gItr == groups.end()) {
|
||||||
gItr = groups.insert(std::make_pair(group, std::set<QString>())).first;
|
gItr = groups.insert(std::make_pair(group, std::set<QString>())).first;
|
||||||
@ -296,8 +267,7 @@ void Core::RosterHandler::addToGroup(const QString& jid, const QString& group)
|
|||||||
gItr->second.insert(jid.toLower());
|
gItr->second.insert(jid.toLower());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterHandler::removeFromGroup(const QString& jid, const QString& group)
|
void Core::RosterHandler::removeFromGroup(const QString& jid, const QString& group) {
|
||||||
{
|
|
||||||
QSet<QString> toRemove;
|
QSet<QString> toRemove;
|
||||||
std::map<QString, std::set<QString>>::iterator itr = groups.find(group);
|
std::map<QString, std::set<QString>>::iterator itr = groups.find(group);
|
||||||
if (itr == groups.end()) {
|
if (itr == groups.end()) {
|
||||||
@ -315,58 +285,53 @@ void Core::RosterHandler::removeFromGroup(const QString& jid, const QString& gro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::RosterItem * Core::RosterHandler::getRosterItem(const QString& jid)
|
Core::RosterItem* Core::RosterHandler::getRosterItem(const QString& jid) {
|
||||||
{
|
RosterItem* item = nullptr;
|
||||||
RosterItem* item = 0;
|
|
||||||
QString lcJid = jid.toLower();
|
QString lcJid = jid.toLower();
|
||||||
std::map<QString, Contact*>::const_iterator citr = contacts.find(lcJid);
|
std::map<QString, Contact*>::const_iterator citr = contacts.find(lcJid);
|
||||||
if (citr != contacts.end()) {
|
if (citr != contacts.end()) {
|
||||||
item = citr->second;
|
item = citr->second;
|
||||||
} else {
|
} else {
|
||||||
std::map<QString, Conference*>::const_iterator coitr = conferences.find(lcJid);
|
std::map<QString, Conference*>::const_iterator coitr = conferences.find(lcJid);
|
||||||
if (coitr != conferences.end()) {
|
if (coitr != conferences.end())
|
||||||
item = coitr->second;
|
item = coitr->second;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::Conference * Core::RosterHandler::getConference(const QString& jid)
|
Core::Conference* Core::RosterHandler::getConference(const QString& jid) {
|
||||||
{
|
|
||||||
Conference* item = 0;
|
Conference* item = 0;
|
||||||
std::map<QString, Conference*>::const_iterator coitr = conferences.find(jid.toLower());
|
std::map<QString, Conference*>::const_iterator coitr = conferences.find(jid.toLower());
|
||||||
if (coitr != conferences.end()) {
|
if (coitr != conferences.end())
|
||||||
item = coitr->second;
|
item = coitr->second;
|
||||||
}
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::Contact * Core::RosterHandler::getContact(const QString& jid)
|
Core::Contact* Core::RosterHandler::getContact(const QString& jid) {
|
||||||
{
|
|
||||||
Contact* item = 0;
|
Contact* item = 0;
|
||||||
std::map<QString, Contact*>::const_iterator citr = contacts.find(jid.toLower());
|
std::map<QString, Contact*>::const_iterator citr = contacts.find(jid.toLower());
|
||||||
if (citr != contacts.end()) {
|
if (citr != contacts.end())
|
||||||
item = citr->second;
|
item = citr->second;
|
||||||
}
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::Contact * Core::RosterHandler::addOutOfRosterContact(const QString& jid)
|
Core::Contact* Core::RosterHandler::addOutOfRosterContact(const QString& jid) {
|
||||||
{
|
|
||||||
QString lcJid = jid.toLower();
|
QString lcJid = jid.toLower();
|
||||||
Contact* cnt = new Contact(lcJid, acc->name);
|
Contact* cnt = new Contact(lcJid, acc->name);
|
||||||
contacts.insert(std::make_pair(lcJid, cnt));
|
contacts.insert(std::make_pair(lcJid, cnt));
|
||||||
outOfRosterContacts.insert(lcJid);
|
outOfRosterContacts.insert(lcJid);
|
||||||
cnt->setSubscriptionState(Shared::SubscriptionState::unknown);
|
cnt->setSubscriptionState(Shared::SubscriptionState::unknown);
|
||||||
emit acc->addContact(lcJid, "", QMap<QString, QVariant>({
|
emit acc->addContact(lcJid, "", QMap<QString, QVariant>({
|
||||||
{"state", QVariant::fromValue(Shared::SubscriptionState::unknown)}
|
{"state", QVariant::fromValue(Shared::SubscriptionState::unknown)},
|
||||||
|
{"encryption", QVariant::fromValue(Shared::EncryptionProtocol::none)}
|
||||||
}));
|
}));
|
||||||
handleNewContact(cnt);
|
handleNewContact(cnt);
|
||||||
return cnt;
|
return cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterHandler::onRosterItemChanged(const QString& bareJid)
|
void Core::RosterHandler::onRosterItemChanged(const QString& bareJid) {
|
||||||
{
|
|
||||||
QString lcJid = bareJid.toLower();
|
QString lcJid = bareJid.toLower();
|
||||||
std::map<QString, Contact*>::const_iterator itr = contacts.find(lcJid);
|
std::map<QString, Contact*>::const_iterator itr = contacts.find(lcJid);
|
||||||
if (itr == contacts.end()) {
|
if (itr == contacts.end()) {
|
||||||
@ -383,8 +348,7 @@ void Core::RosterHandler::onRosterItemChanged(const QString& bareJid)
|
|||||||
contact->setName(re.name());
|
contact->setName(re.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterHandler::onRosterItemRemoved(const QString& bareJid)
|
void Core::RosterHandler::onRosterItemRemoved(const QString& bareJid) {
|
||||||
{
|
|
||||||
QString lcJid = bareJid.toLower();
|
QString lcJid = bareJid.toLower();
|
||||||
std::map<QString, Contact*>::const_iterator itr = contacts.find(lcJid);
|
std::map<QString, Contact*>::const_iterator itr = contacts.find(lcJid);
|
||||||
if (itr == contacts.end()) {
|
if (itr == contacts.end()) {
|
||||||
@ -394,22 +358,20 @@ void Core::RosterHandler::onRosterItemRemoved(const QString& bareJid)
|
|||||||
Contact* contact = itr->second;
|
Contact* contact = itr->second;
|
||||||
contacts.erase(itr);
|
contacts.erase(itr);
|
||||||
QSet<QString> cGroups = contact->getGroups();
|
QSet<QString> cGroups = contact->getGroups();
|
||||||
for (QSet<QString>::const_iterator itr = cGroups.begin(), end = cGroups.end(); itr != end; ++itr) {
|
for (const QString& group : cGroups)
|
||||||
removeFromGroup(lcJid, *itr);
|
removeFromGroup(lcJid, group);
|
||||||
}
|
|
||||||
emit acc->removeContact(lcJid);
|
emit acc->removeContact(lcJid);
|
||||||
|
|
||||||
contact->deleteLater();
|
contact->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterHandler::onMucRoomAdded(QXmppMucRoom* room)
|
void Core::RosterHandler::onMucRoomAdded(QXmppMucRoom* room) {
|
||||||
{
|
|
||||||
qDebug() << "room" << room->jid() << "added with name" << room->name()
|
qDebug() << "room" << room->jid() << "added with name" << room->name()
|
||||||
<< ", account" << acc->getName() << "joined:" << room->isJoined();
|
<< ", account" << acc->getName() << "joined:" << room->isJoined();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterHandler::bookmarksReceived(const QXmppBookmarkSet& bookmarks)
|
void Core::RosterHandler::bookmarksReceived(const QXmppBookmarkSet& bookmarks) {
|
||||||
{
|
|
||||||
QList<QXmppBookmarkConference> confs = bookmarks.conferences();
|
QList<QXmppBookmarkConference> confs = bookmarks.conferences();
|
||||||
for (QList<QXmppBookmarkConference>::const_iterator itr = confs.begin(), end = confs.end(); itr != end; ++itr) {
|
for (QList<QXmppBookmarkConference>::const_iterator itr = confs.begin(), end = confs.end(); itr != end; ++itr) {
|
||||||
const QXmppBookmarkConference& c = *itr;
|
const QXmppBookmarkConference& c = *itr;
|
||||||
@ -419,54 +381,42 @@ void Core::RosterHandler::bookmarksReceived(const QXmppBookmarkSet& bookmarks)
|
|||||||
if (cItr == conferences.end()) {
|
if (cItr == conferences.end()) {
|
||||||
addNewRoom(jid, c.nickName(), c.name(), c.autoJoin());
|
addNewRoom(jid, c.nickName(), c.name(), c.autoJoin());
|
||||||
} else {
|
} else {
|
||||||
if (c.autoJoin()) {
|
if (c.autoJoin())
|
||||||
cItr->second->setJoined(true);
|
cItr->second->setJoined(true);
|
||||||
} else {
|
else
|
||||||
cItr->second->setAutoJoin(false);
|
cItr->second->setAutoJoin(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterHandler::onMucJoinedChanged(bool joined)
|
void Core::RosterHandler::onMucJoinedChanged(bool joined){
|
||||||
{
|
|
||||||
Conference* room = static_cast<Conference*>(sender());
|
Conference* room = static_cast<Conference*>(sender());
|
||||||
emit acc->changeRoom(room->jid, {
|
emit acc->changeRoom(room->jid, {{"joined", joined}});
|
||||||
{"joined", joined}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterHandler::onMucAutoJoinChanged(bool autoJoin)
|
void Core::RosterHandler::onMucAutoJoinChanged(bool autoJoin) {
|
||||||
{
|
|
||||||
storeConferences();
|
storeConferences();
|
||||||
Conference* room = static_cast<Conference*>(sender());
|
Conference* room = static_cast<Conference*>(sender());
|
||||||
emit acc->changeRoom(room->jid, {
|
emit acc->changeRoom(room->jid, {{"autoJoin", autoJoin}});
|
||||||
{"autoJoin", autoJoin}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterHandler::onMucNickNameChanged(const QString& nickName)
|
void Core::RosterHandler::onMucNickNameChanged(const QString& nickName){
|
||||||
{
|
|
||||||
storeConferences();
|
storeConferences();
|
||||||
Conference* room = static_cast<Conference*>(sender());
|
Conference* room = static_cast<Conference*>(sender());
|
||||||
emit acc->changeRoom(room->jid, {
|
emit acc->changeRoom(room->jid, {{"nick", nickName}});
|
||||||
{"nick", nickName}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Shared::SubscriptionState Core::RosterHandler::castSubscriptionState(QXmppRosterIq::Item::SubscriptionType qs)
|
Shared::SubscriptionState Core::RosterHandler::castSubscriptionState(QXmppRosterIq::Item::SubscriptionType qs){
|
||||||
{
|
|
||||||
Shared::SubscriptionState state;
|
Shared::SubscriptionState state;
|
||||||
if (qs == QXmppRosterIq::Item::NotSet) {
|
if (qs == QXmppRosterIq::Item::NotSet)
|
||||||
state = Shared::SubscriptionState::unknown;
|
state = Shared::SubscriptionState::unknown;
|
||||||
} else {
|
else
|
||||||
state = static_cast<Shared::SubscriptionState>(qs);
|
state = static_cast<Shared::SubscriptionState>(qs);
|
||||||
}
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterHandler::storeConferences()
|
void Core::RosterHandler::storeConferences() {
|
||||||
{
|
|
||||||
QXmppBookmarkSet bms = acc->bm->bookmarks();
|
QXmppBookmarkSet bms = acc->bm->bookmarks();
|
||||||
QList<QXmppBookmarkConference> confs;
|
QList<QXmppBookmarkConference> confs;
|
||||||
for (std::map<QString, Conference*>::const_iterator itr = conferences.begin(), end = conferences.end(); itr != end; ++itr) {
|
for (std::map<QString, Conference*>::const_iterator itr = conferences.begin(), end = conferences.end(); itr != end; ++itr) {
|
||||||
@ -482,8 +432,7 @@ void Core::RosterHandler::storeConferences()
|
|||||||
acc->bm->setBookmarks(bms);
|
acc->bm->setBookmarks(bms);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterHandler::clearConferences()
|
void Core::RosterHandler::clearConferences() {
|
||||||
{
|
|
||||||
for (std::map<QString, Conference*>::const_iterator itr = conferences.begin(), end = conferences.end(); itr != end; itr++) {
|
for (std::map<QString, Conference*>::const_iterator itr = conferences.begin(), end = conferences.end(); itr != end; itr++) {
|
||||||
itr->second->deleteLater();
|
itr->second->deleteLater();
|
||||||
emit acc->removeRoom(itr->first);
|
emit acc->removeRoom(itr->first);
|
||||||
@ -491,21 +440,20 @@ void Core::RosterHandler::clearConferences()
|
|||||||
conferences.clear();
|
conferences.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterHandler::removeRoomRequest(const QString& jid)
|
void Core::RosterHandler::removeRoomRequest(const QString& jid) {
|
||||||
{
|
|
||||||
QString lcJid = jid.toLower();
|
QString lcJid = jid.toLower();
|
||||||
std::map<QString, Conference*>::const_iterator itr = conferences.find(lcJid);
|
std::map<QString, Conference*>::const_iterator itr = conferences.find(lcJid);
|
||||||
if (itr == conferences.end()) {
|
if (itr == conferences.end())
|
||||||
qDebug() << "An attempt to remove non existing room" << lcJid << "from account" << acc->name << ", skipping";
|
qDebug() << "An attempt to remove non existing room" << lcJid << "from account" << acc->name << ", skipping";
|
||||||
}
|
|
||||||
itr->second->deleteLater();
|
itr->second->deleteLater();
|
||||||
conferences.erase(itr);
|
conferences.erase(itr);
|
||||||
emit acc->removeRoom(lcJid);
|
emit acc->removeRoom(lcJid);
|
||||||
storeConferences();
|
storeConferences();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterHandler::addRoomRequest(const QString& jid, const QString& nick, const QString& password, bool autoJoin)
|
void Core::RosterHandler::addRoomRequest(const QString& jid, const QString& nick, const QString& password, bool autoJoin) {
|
||||||
{
|
SHARED_UNUSED(password);
|
||||||
QString lcJid = jid.toLower();
|
QString lcJid = jid.toLower();
|
||||||
std::map<QString, Conference*>::const_iterator cItr = conferences.find(lcJid);
|
std::map<QString, Conference*>::const_iterator cItr = conferences.find(lcJid);
|
||||||
if (cItr == conferences.end()) {
|
if (cItr == conferences.end()) {
|
||||||
@ -516,8 +464,7 @@ void Core::RosterHandler::addRoomRequest(const QString& jid, const QString& nick
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterHandler::addContactToGroupRequest(const QString& jid, const QString& groupName)
|
void Core::RosterHandler::addContactToGroupRequest(const QString& jid, const QString& groupName) {
|
||||||
{
|
|
||||||
QString lcJid = jid.toLower();
|
QString lcJid = jid.toLower();
|
||||||
std::map<QString, Contact*>::const_iterator itr = contacts.find(lcJid);
|
std::map<QString, Contact*>::const_iterator itr = contacts.find(lcJid);
|
||||||
if (itr == contacts.end()) {
|
if (itr == contacts.end()) {
|
||||||
@ -541,14 +488,15 @@ void Core::RosterHandler::addContactToGroupRequest(const QString& jid, const QSt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterHandler::removeContactFromGroupRequest(const QString& jid, const QString& groupName)
|
void Core::RosterHandler::removeContactFromGroupRequest(const QString& jid, const QString& groupName) {
|
||||||
{
|
|
||||||
QString lcJid = jid.toLower();
|
QString lcJid = jid.toLower();
|
||||||
std::map<QString, Contact*>::const_iterator itr = contacts.find(lcJid);
|
std::map<QString, Contact*>::const_iterator itr = contacts.find(lcJid);
|
||||||
if (itr == contacts.end()) {
|
if (itr == contacts.end()) {
|
||||||
qDebug() << "An attempt to remove non existing contact" << lcJid << "of account"
|
qDebug() << "An attempt to remove non existing contact" << lcJid << "of account"
|
||||||
<< acc->name << "from the group" << groupName << ", skipping";
|
<< acc->name << "from the group" << groupName << ", skipping";
|
||||||
} else {
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QXmppRosterIq::Item item = acc->rm->getRosterEntry(lcJid);
|
QXmppRosterIq::Item item = acc->rm->getRosterEntry(lcJid);
|
||||||
QSet<QString> groups = item.groups();
|
QSet<QString> groups = item.groups();
|
||||||
QSet<QString>::const_iterator gItr = groups.find(groupName);
|
QSet<QString>::const_iterator gItr = groups.find(groupName);
|
||||||
@ -564,22 +512,19 @@ void Core::RosterHandler::removeContactFromGroupRequest(const QString& jid, cons
|
|||||||
qDebug() << "An attempt to remove contact" << lcJid << "of account"
|
qDebug() << "An attempt to remove contact" << lcJid << "of account"
|
||||||
<< acc->name << "from the group" << groupName << "but it's not in that group, skipping";
|
<< acc->name << "from the group" << groupName << "but it's not in that group, skipping";
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterHandler::onContactAvatarChanged(Shared::Avatar type, const QString& path)
|
void Core::RosterHandler::onContactAvatarChanged(Shared::Avatar type, const QString& path) {
|
||||||
{
|
|
||||||
RosterItem* item = static_cast<RosterItem*>(sender());
|
RosterItem* item = static_cast<RosterItem*>(sender());
|
||||||
QMap<QString, QVariant> cData({
|
QMap<QString, QVariant> cData({
|
||||||
{"avatarState", static_cast<uint>(type)},
|
{"avatarState", QVariant::fromValue(type)},
|
||||||
{"avatarPath", path}
|
{"avatarPath", path}
|
||||||
});
|
});
|
||||||
|
|
||||||
emit acc->changeContact(item->jid, cData);
|
emit acc->changeContact(item->jid, cData);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterHandler::handleOffline()
|
void Core::RosterHandler::handleOffline() {
|
||||||
{
|
|
||||||
for (const std::pair<const QString, Conference*>& pair : conferences) {
|
for (const std::pair<const QString, Conference*>& pair : conferences) {
|
||||||
pair.second->clearArchiveRequests();
|
pair.second->clearArchiveRequests();
|
||||||
pair.second->downgradeDatabaseState();
|
pair.second->downgradeDatabaseState();
|
||||||
@ -588,13 +533,13 @@ void Core::RosterHandler::handleOffline()
|
|||||||
pair.second->clearArchiveRequests();
|
pair.second->clearArchiveRequests();
|
||||||
pair.second->downgradeDatabaseState();
|
pair.second->downgradeDatabaseState();
|
||||||
}
|
}
|
||||||
setPepSupport(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Core::RosterHandler::onPepSupportedChanged(Shared::Support support) {
|
||||||
void Core::RosterHandler::setPepSupport(bool support)
|
if (support == Shared::Support::supported) {
|
||||||
{
|
for (const std::pair<const QString, Contact*>& pair : contacts) {
|
||||||
if (pepSupport != support) {
|
if (pair.second->getPepSupport() == Shared::Support::unknown)
|
||||||
pepSupport = support;
|
acc->dm->requestInfo(pair.first);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 CORE_ROSTERHANDLER_H
|
#pragma once
|
||||||
#define CORE_ROSTERHANDLER_H
|
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
@ -27,22 +26,24 @@
|
|||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
#include <QXmppBookmarkSet.h>
|
#include <QXmppBookmarkSet.h>
|
||||||
#include <QXmppMucManager.h>
|
#include <QXmppMucManager.h>
|
||||||
#include <QXmppRosterIq.h>
|
#include <QXmppRosterIq.h>
|
||||||
|
|
||||||
|
#include <shared/enums.h>
|
||||||
#include <shared/message.h>
|
#include <shared/message.h>
|
||||||
|
#include <shared/trustsummary.h>
|
||||||
|
|
||||||
#include <core/contact.h>
|
#include <core/contact.h>
|
||||||
#include <core/conference.h>
|
#include <core/conference.h>
|
||||||
|
#include <core/delayManager/manager.h>
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
|
|
||||||
class Account;
|
class Account;
|
||||||
|
|
||||||
class RosterHandler : public QObject
|
class RosterHandler : public QObject {
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
RosterHandler(Account* account);
|
RosterHandler(Account* account);
|
||||||
@ -64,13 +65,16 @@ public:
|
|||||||
|
|
||||||
void storeConferences();
|
void storeConferences();
|
||||||
void clearConferences();
|
void clearConferences();
|
||||||
void setPepSupport(bool support);
|
|
||||||
|
void initialize();
|
||||||
|
void clear();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onRosterReceived();
|
void onRosterReceived();
|
||||||
void onRosterItemAdded(const QString& bareJid);
|
void onRosterItemAdded(const QString& bareJid);
|
||||||
void onRosterItemChanged(const QString& bareJid);
|
void onRosterItemChanged(const QString& bareJid);
|
||||||
void onRosterItemRemoved(const QString& bareJid);
|
void onRosterItemRemoved(const QString& bareJid);
|
||||||
|
void onTrustChanged(const QString& jid, const Shared::TrustSummary& trust);
|
||||||
|
|
||||||
void onMucRoomAdded(QXmppMucRoom* room);
|
void onMucRoomAdded(QXmppMucRoom* room);
|
||||||
void onMucJoinedChanged(bool joined);
|
void onMucJoinedChanged(bool joined);
|
||||||
@ -88,6 +92,8 @@ private slots:
|
|||||||
void onContactNameChanged(const QString& name);
|
void onContactNameChanged(const QString& name);
|
||||||
void onContactSubscriptionStateChanged(Shared::SubscriptionState state);
|
void onContactSubscriptionStateChanged(Shared::SubscriptionState state);
|
||||||
void onContactAvatarChanged(Shared::Avatar, const QString& path);
|
void onContactAvatarChanged(Shared::Avatar, const QString& path);
|
||||||
|
void onContactEncryptionChanged(Shared::EncryptionProtocol value);
|
||||||
|
void onPepSupportedChanged(Shared::Support support);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void addNewRoom(const QString& jid, const QString& nick, const QString& roomName, bool autoJoin);
|
void addNewRoom(const QString& jid, const QString& nick, const QString& roomName, bool autoJoin);
|
||||||
@ -97,7 +103,6 @@ private:
|
|||||||
void handleNewRosterItem(Core::RosterItem* contact);
|
void handleNewRosterItem(Core::RosterItem* contact);
|
||||||
void handleNewContact(Core::Contact* contact);
|
void handleNewContact(Core::Contact* contact);
|
||||||
void handleNewConference(Core::Conference* contact);
|
void handleNewConference(Core::Conference* contact);
|
||||||
void careAboutAvatar(Core::RosterItem* item, QMap<QString, QVariant>& data);
|
|
||||||
|
|
||||||
static Shared::SubscriptionState castSubscriptionState(QXmppRosterIq::Item::SubscriptionType qs);
|
static Shared::SubscriptionState castSubscriptionState(QXmppRosterIq::Item::SubscriptionType qs);
|
||||||
|
|
||||||
@ -108,9 +113,6 @@ private:
|
|||||||
std::map<QString, std::set<QString>> groups;
|
std::map<QString, std::set<QString>> groups;
|
||||||
std::map<QString, QString> queuedContacts;
|
std::map<QString, QString> queuedContacts;
|
||||||
std::set<QString> outOfRosterContacts;
|
std::set<QString> outOfRosterContacts;
|
||||||
bool pepSupport;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // CORE_ROSTERHANDLER_H
|
|
||||||
|
463
core/handlers/trusthandler.cpp
Normal file
@ -0,0 +1,463 @@
|
|||||||
|
// 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 "trusthandler.h"
|
||||||
|
#include "core/account.h"
|
||||||
|
#include "core/adapterfunctions.h"
|
||||||
|
|
||||||
|
Core::TrustHandler::TrustHandler(Account* account):
|
||||||
|
QObject(),
|
||||||
|
QXmppTrustStorage(),
|
||||||
|
acc(account),
|
||||||
|
db(acc->getName() + "/trust"),
|
||||||
|
protocols(db.createDirectory() + "/protocols"),
|
||||||
|
securityPolicies(db.addCache<QString, uint8_t>("securityPolicies")),
|
||||||
|
ownKeys(db.addCache<QString, QByteArray>("ownKeys")),
|
||||||
|
keysByProtocol()
|
||||||
|
{
|
||||||
|
if (!protocols.open(QIODevice::ReadWrite | QIODevice::Text)) //never supposed to happen since I have just created a directory;
|
||||||
|
throw LMDBAL::Directory(protocols.fileName().toStdString());
|
||||||
|
|
||||||
|
QTextStream in(&protocols);
|
||||||
|
while(!in.atEnd()) {
|
||||||
|
QString protocol = in.readLine();
|
||||||
|
|
||||||
|
if (protocol.size() > 1) { //I'm afraid of reading some nonsence like separately standing \n or EF or BOM, so... let it be at least 2 chars long
|
||||||
|
KeyCache* cache = db.addCache<QString, Keys>(protocol.toStdString());
|
||||||
|
keysByProtocol.insert(std::make_pair(protocol, cache));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protocols.close();
|
||||||
|
db.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
Core::TrustHandler::~TrustHandler() {
|
||||||
|
protocols.close();
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
Core::TrustHandler::KeyCache * Core::TrustHandler::getCache(const QString& encryption) {
|
||||||
|
std::map<QString, KeyCache*>::iterator itr = keysByProtocol.find(encryption);
|
||||||
|
if (itr == keysByProtocol.end())
|
||||||
|
return createNewCache(encryption);
|
||||||
|
else
|
||||||
|
return itr->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
Core::TrustHandler::KeyCache * Core::TrustHandler::createNewCache(const QString& encryption) {
|
||||||
|
db.close();
|
||||||
|
KeyCache* cache = db.addCache<QString, Keys>(encryption.toStdString());
|
||||||
|
keysByProtocol.insert(std::make_pair(encryption, cache));
|
||||||
|
|
||||||
|
if (!protocols.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text))
|
||||||
|
throw LMDBAL::Directory(protocols.fileName().toStdString());
|
||||||
|
|
||||||
|
QTextStream out(&protocols);
|
||||||
|
out << encryption + "\n";
|
||||||
|
protocols.close();
|
||||||
|
|
||||||
|
db.open();
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
QXmppTask<void> Core::TrustHandler::resetAll(const QString& encryption) {
|
||||||
|
securityPolicies->removeRecord(encryption);
|
||||||
|
ownKeys->removeRecord(encryption);
|
||||||
|
std::map<QString, KeyCache*>::const_iterator itr = keysByProtocol.find(encryption);
|
||||||
|
if (itr == keysByProtocol.end())
|
||||||
|
return Core::makeReadyTask();
|
||||||
|
|
||||||
|
LMDBAL::WriteTransaction txn = db.beginTransaction();
|
||||||
|
KeyCache* cache = itr->second;
|
||||||
|
std::map<QString, Keys> keys = cache->readAll(txn);
|
||||||
|
cache->drop(txn);
|
||||||
|
|
||||||
|
txn.commit();
|
||||||
|
for (const std::pair<const QString, Keys>& pair : keys) {
|
||||||
|
bool empty = true;
|
||||||
|
for (const std::pair<const QByteArray, Shared::TrustLevel>& trust : pair.second) {
|
||||||
|
if (trust.second != Shared::TrustLevel::undecided) {
|
||||||
|
empty = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!empty)
|
||||||
|
emit trustLevelsChanged(pair.first, getSummary(pair.first));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Core::makeReadyTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
QXmppTask<QXmpp::TrustLevel> Core::TrustHandler::trustLevel(
|
||||||
|
const QString& encryption,
|
||||||
|
const QString& keyOwnerJid,
|
||||||
|
const QByteArray& keyId
|
||||||
|
) {
|
||||||
|
KeyCache* cache = getCache(encryption);
|
||||||
|
Shared::TrustLevel level = Shared::TrustLevel::undecided;
|
||||||
|
try {
|
||||||
|
Keys map = cache->getRecord(keyOwnerJid);
|
||||||
|
Keys::const_iterator itr = map.find(keyId);
|
||||||
|
if (itr != map.end())
|
||||||
|
level = itr->second;
|
||||||
|
} catch (const LMDBAL::NotFound& e) {}
|
||||||
|
return Core::makeReadyTask(std::move(convert(level)));
|
||||||
|
}
|
||||||
|
|
||||||
|
QXmppTask<QHash<QString, QMultiHash<QString, QByteArray>>> Core::TrustHandler::setTrustLevel(
|
||||||
|
const QString& encryption,
|
||||||
|
const QList<QString>& keyOwnerJids,
|
||||||
|
QXmpp::TrustLevel oldTrustLevel,
|
||||||
|
QXmpp::TrustLevel newTrustLevel
|
||||||
|
) {
|
||||||
|
QHash<QString, QMultiHash<QString, QByteArray>> modifiedKeys;
|
||||||
|
Shared::TrustLevel oldLevel = convert(oldTrustLevel);
|
||||||
|
Shared::TrustLevel newLevel = convert(newTrustLevel);
|
||||||
|
std::set<QString> modifiedJids;
|
||||||
|
KeyCache* cache = getCache(encryption);
|
||||||
|
|
||||||
|
LMDBAL::WriteTransaction txn = db.beginTransaction();
|
||||||
|
for (const QString& keyOwnerJid : keyOwnerJids) {
|
||||||
|
Keys map = cache->getRecord(keyOwnerJid, txn);
|
||||||
|
uint count = 0;
|
||||||
|
for (std::pair<const QByteArray, Shared::TrustLevel>& pair : map) {
|
||||||
|
Shared::TrustLevel& current = pair.second;
|
||||||
|
if (current == oldLevel) {
|
||||||
|
current = newLevel;
|
||||||
|
modifiedKeys[encryption].insert(keyOwnerJid, pair.first);
|
||||||
|
modifiedJids.insert(keyOwnerJid);
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (count > 0)
|
||||||
|
cache->changeRecord(keyOwnerJid, map, txn);
|
||||||
|
}
|
||||||
|
txn.commit();
|
||||||
|
for (const QString& jid : modifiedJids)
|
||||||
|
emit trustLevelsChanged(jid, getSummary(jid));
|
||||||
|
|
||||||
|
return Core::makeReadyTask(std::move(modifiedKeys));
|
||||||
|
}
|
||||||
|
|
||||||
|
QXmppTask<QHash<QString, QMultiHash<QString, QByteArray>>> Core::TrustHandler::setTrustLevel(
|
||||||
|
const QString& encryption,
|
||||||
|
const QMultiHash<QString, QByteArray>& keyIds,
|
||||||
|
QXmpp::TrustLevel trustLevel
|
||||||
|
) {
|
||||||
|
QHash<QString, QMultiHash<QString, QByteArray>> modifiedKeys;
|
||||||
|
Shared::TrustLevel level = convert(trustLevel);
|
||||||
|
std::set<QString> modifiedJids;
|
||||||
|
KeyCache* cache = getCache(encryption);
|
||||||
|
|
||||||
|
LMDBAL::WriteTransaction txn = db.beginTransaction();
|
||||||
|
for (MultySB::const_iterator itr = keyIds.begin(), end = keyIds.end(); itr != end; ++itr) {
|
||||||
|
const QString& keyOwnerJid = itr.key();
|
||||||
|
const QByteArray& keyId = itr.value();
|
||||||
|
try {
|
||||||
|
Keys map = cache->getRecord(keyOwnerJid, txn);
|
||||||
|
std::pair<Keys::iterator, bool> result = map.insert(std::make_pair(keyId, level));
|
||||||
|
bool changed = result.second;
|
||||||
|
if (!changed && result.first->second != level) {
|
||||||
|
result.first->second = level;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
if (changed) {
|
||||||
|
modifiedKeys[encryption].insert(keyOwnerJid, keyId);
|
||||||
|
modifiedJids.insert(keyOwnerJid);
|
||||||
|
cache->changeRecord(keyOwnerJid, map, txn);
|
||||||
|
}
|
||||||
|
} catch (const LMDBAL::NotFound& e) {
|
||||||
|
Keys map({{keyId, level}});
|
||||||
|
modifiedKeys[encryption].insert(keyOwnerJid, keyId);
|
||||||
|
modifiedJids.insert(keyOwnerJid);
|
||||||
|
cache->addRecord(keyOwnerJid, map, txn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
txn.commit();
|
||||||
|
|
||||||
|
for (const QString& jid : modifiedJids)
|
||||||
|
emit trustLevelsChanged(jid, getSummary(jid));
|
||||||
|
|
||||||
|
return Core::makeReadyTask(std::move(modifiedKeys));
|
||||||
|
}
|
||||||
|
|
||||||
|
QXmppTask<bool> Core::TrustHandler::hasKey(
|
||||||
|
const QString& encryption,
|
||||||
|
const QString& keyOwnerJid,
|
||||||
|
QXmpp::TrustLevels trustLevels
|
||||||
|
) {
|
||||||
|
KeyCache* cache = getCache(encryption);
|
||||||
|
bool found = false;
|
||||||
|
try {
|
||||||
|
Keys map = cache->getRecord(keyOwnerJid);
|
||||||
|
for (const std::pair<const QByteArray, Shared::TrustLevel>& pair : map) {
|
||||||
|
if (trustLevels.testFlag(convert(pair.second))) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (const LMDBAL::NotFound& e) {}
|
||||||
|
return Core::makeReadyTask(std::move(found));
|
||||||
|
}
|
||||||
|
|
||||||
|
QXmppTask<QHash<QString, QHash<QByteArray, QXmpp::TrustLevel>>> Core::TrustHandler::keys(
|
||||||
|
const QString& encryption,
|
||||||
|
const QList<QString>& keyOwnerJids,
|
||||||
|
QXmpp::TrustLevels trustLevels
|
||||||
|
) {
|
||||||
|
HSHBTL res;
|
||||||
|
|
||||||
|
KeyCache* cache = getCache(encryption);
|
||||||
|
for (const QString& keyOwnerJid : keyOwnerJids) {
|
||||||
|
try {
|
||||||
|
Keys map = cache->getRecord(keyOwnerJid);
|
||||||
|
QHash<QByteArray, QXmpp::TrustLevel>& pRes = res[keyOwnerJid];
|
||||||
|
for (const std::pair<const QByteArray, Shared::TrustLevel>& pair : map) {
|
||||||
|
QXmpp::TrustLevel level = convert(pair.second);
|
||||||
|
if (!trustLevels || trustLevels.testFlag(level)) {
|
||||||
|
pRes.insert(pair.first, level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (const LMDBAL::NotFound& e) {}
|
||||||
|
}
|
||||||
|
return Core::makeReadyTask(std::move(res));
|
||||||
|
}
|
||||||
|
|
||||||
|
QXmppTask<QHash<QXmpp::TrustLevel, QMultiHash<QString, QByteArray>>> Core::TrustHandler::keys(
|
||||||
|
const QString& encryption,
|
||||||
|
QXmpp::TrustLevels trustLevels
|
||||||
|
) {
|
||||||
|
QHash<TL, MultySB> res;
|
||||||
|
KeyCache* cache = getCache(encryption);
|
||||||
|
std::map<QString, Keys> storage = cache->readAll();
|
||||||
|
for (const std::pair<const QString, Keys>& value : storage) {
|
||||||
|
for (const std::pair<const QByteArray, Shared::TrustLevel>& pair : value.second) {
|
||||||
|
QXmpp::TrustLevel level = convert(pair.second);
|
||||||
|
if (!trustLevels || trustLevels.testFlag(level))
|
||||||
|
res[level].insert(value.first, pair.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Core::makeReadyTask(std::move(res));
|
||||||
|
}
|
||||||
|
|
||||||
|
QXmppTask<void> Core::TrustHandler::removeKeys(const QString& encryption) {
|
||||||
|
std::map<QString, KeyCache*>::const_iterator itr = keysByProtocol.find(encryption);
|
||||||
|
if (itr == keysByProtocol.end())
|
||||||
|
return Core::makeReadyTask();
|
||||||
|
|
||||||
|
LMDBAL::WriteTransaction txn = db.beginTransaction();
|
||||||
|
KeyCache* cache = itr->second;
|
||||||
|
std::map<QString, Keys> keys = cache->readAll(txn);
|
||||||
|
cache->drop(txn);
|
||||||
|
txn.commit();
|
||||||
|
|
||||||
|
for (const std::pair<const QString, Keys>& pair : keys) {
|
||||||
|
bool empty = true;
|
||||||
|
for (const std::pair<const QByteArray, Shared::TrustLevel>& trust : pair.second) {
|
||||||
|
if (trust.second != Shared::TrustLevel::undecided) {
|
||||||
|
empty = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!empty)
|
||||||
|
emit trustLevelsChanged(pair.first, getSummary(pair.first));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Core::makeReadyTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
QXmppTask<void> Core::TrustHandler::removeKeys(const QString& encryption, const QString& keyOwnerJid) {
|
||||||
|
std::map<QString, KeyCache*>::const_iterator itr = keysByProtocol.find(encryption);
|
||||||
|
if (itr == keysByProtocol.end())
|
||||||
|
return Core::makeReadyTask();
|
||||||
|
|
||||||
|
KeyCache* cache = itr->second;
|
||||||
|
try {
|
||||||
|
cache->removeRecord(keyOwnerJid);
|
||||||
|
emit trustLevelsChanged(keyOwnerJid, getSummary(keyOwnerJid)); //TODO there is a probability of notification without the actial change
|
||||||
|
} catch (const LMDBAL::NotFound& e) {} //if the movin entry was empty or if it consisted of Undecided keys
|
||||||
|
|
||||||
|
|
||||||
|
return Core::makeReadyTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
QXmppTask<void> Core::TrustHandler::removeKeys(const QString& encryption, const QList<QByteArray>& keyIds) {
|
||||||
|
std::set<QByteArray> set;
|
||||||
|
for (const QByteArray& keyId : keyIds)
|
||||||
|
set.insert(keyId);
|
||||||
|
|
||||||
|
LMDBAL::WriteTransaction txn = db.beginTransaction();
|
||||||
|
KeyCache* cache = getCache(encryption);
|
||||||
|
std::map<QString, Keys> data = cache->readAll(txn);
|
||||||
|
std::set<QString> modifiedJids;
|
||||||
|
|
||||||
|
for (std::map<QString, Keys>::iterator cItr = data.begin(), cEnd = data.end(); cItr != cEnd; /*no increment*/) {
|
||||||
|
Keys& byOwner = cItr->second;
|
||||||
|
for (Keys::const_iterator itr = byOwner.begin(), end = byOwner.end(); itr != end; /*no increment*/) {
|
||||||
|
const QByteArray& keyId = itr->first;
|
||||||
|
if (set.erase(keyId)) {
|
||||||
|
byOwner.erase(itr++);
|
||||||
|
modifiedJids.insert(cItr->first);
|
||||||
|
} else
|
||||||
|
++itr;
|
||||||
|
}
|
||||||
|
if (byOwner.size() > 0)
|
||||||
|
data.erase(cItr++);
|
||||||
|
else
|
||||||
|
++cItr;
|
||||||
|
}
|
||||||
|
if (modifiedJids.size() > 0)
|
||||||
|
cache->replaceAll(data, txn);
|
||||||
|
|
||||||
|
txn.commit();
|
||||||
|
for (const QString& jid : modifiedJids)
|
||||||
|
emit trustLevelsChanged(jid, getSummary(jid));
|
||||||
|
|
||||||
|
return Core::makeReadyTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
QXmppTask<void> Core::TrustHandler::addKeys(
|
||||||
|
const QString& encryption,
|
||||||
|
const QString& keyOwnerJid,
|
||||||
|
const QList<QByteArray>& keyIds,
|
||||||
|
QXmpp::TrustLevel trustLevel
|
||||||
|
) {
|
||||||
|
KeyCache* cache = getCache(encryption);
|
||||||
|
Shared::TrustLevel level = convert(trustLevel);
|
||||||
|
Keys data;
|
||||||
|
bool had = false;
|
||||||
|
LMDBAL::WriteTransaction txn = db.beginTransaction();
|
||||||
|
try {
|
||||||
|
data = cache->getRecord(keyOwnerJid, txn);
|
||||||
|
had = true;
|
||||||
|
} catch (const LMDBAL::NotFound& e) {}
|
||||||
|
for (const QByteArray& keyId : keyIds) {
|
||||||
|
std::pair<Keys::iterator, bool> result = data.insert(std::make_pair(keyId, level));
|
||||||
|
if (!result.second)
|
||||||
|
result.first->second = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (had)
|
||||||
|
cache->changeRecord(keyOwnerJid, data, txn);
|
||||||
|
else
|
||||||
|
cache->addRecord(keyOwnerJid, data, txn);
|
||||||
|
|
||||||
|
txn.commit();
|
||||||
|
emit trustLevelsChanged(keyOwnerJid, getSummary(keyOwnerJid));
|
||||||
|
|
||||||
|
return Core::makeReadyTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
QXmppTask<QByteArray> Core::TrustHandler::ownKey(const QString& encryption) {
|
||||||
|
QByteArray res;
|
||||||
|
try {
|
||||||
|
res = ownKeys->getRecord(encryption);
|
||||||
|
} catch (const LMDBAL::NotFound& e) {}
|
||||||
|
return Core::makeReadyTask(std::move(res));
|
||||||
|
}
|
||||||
|
|
||||||
|
QXmppTask<void> Core::TrustHandler::resetOwnKey(const QString& encryption) {
|
||||||
|
try {
|
||||||
|
ownKeys->removeRecord(encryption);
|
||||||
|
} catch (const LMDBAL::NotFound& e) {}
|
||||||
|
|
||||||
|
return Core::makeReadyTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
QXmppTask<void> Core::TrustHandler::setOwnKey(const QString& encryption, const QByteArray& keyId) {
|
||||||
|
ownKeys->forceRecord(encryption, keyId);
|
||||||
|
return Core::makeReadyTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
QXmppTask<QXmpp::TrustSecurityPolicy> Core::TrustHandler::securityPolicy(const QString& encryption) {
|
||||||
|
QXmpp::TrustSecurityPolicy res;
|
||||||
|
try {
|
||||||
|
res = static_cast<QXmpp::TrustSecurityPolicy>(securityPolicies->getRecord(encryption));
|
||||||
|
} catch (const LMDBAL::NotFound& e) {}
|
||||||
|
return Core::makeReadyTask(std::move(res));
|
||||||
|
}
|
||||||
|
|
||||||
|
QXmppTask<void> Core::TrustHandler::resetSecurityPolicy(const QString& encryption) {
|
||||||
|
try {
|
||||||
|
securityPolicies->removeRecord(encryption);
|
||||||
|
} catch (const LMDBAL::NotFound& e) {}
|
||||||
|
return Core::makeReadyTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
QXmppTask<void> Core::TrustHandler::setSecurityPolicy(
|
||||||
|
const QString& encryption,
|
||||||
|
QXmpp::TrustSecurityPolicy securityPolicy)
|
||||||
|
{
|
||||||
|
uint8_t pol = securityPolicy;
|
||||||
|
securityPolicies->forceRecord(encryption, pol);
|
||||||
|
|
||||||
|
return Core::makeReadyTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
Core::TrustHandler::Keys Core::TrustHandler::getKeys(Shared::EncryptionProtocol protocol, const QString& jid) const {
|
||||||
|
const QString& prt = Shared::TrustSummary::protocolKeys.at(protocol);
|
||||||
|
std::map<QString, KeyCache*>::const_iterator itr = keysByProtocol.find(prt);
|
||||||
|
if (itr != keysByProtocol.end()) {
|
||||||
|
try {
|
||||||
|
Keys map = itr->second->getRecord(jid);
|
||||||
|
return map;
|
||||||
|
} catch (const LMDBAL::NotFound& e) {
|
||||||
|
return Keys();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Keys();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Shared::TrustSummary Core::TrustHandler::getSummary(const QString& jid) const {
|
||||||
|
Shared::TrustSummary result;
|
||||||
|
for (const std::pair<const QString, KeyCache*>& pair : keysByProtocol) {
|
||||||
|
try {
|
||||||
|
Keys keys = pair.second->getRecord(jid);
|
||||||
|
Shared::EncryptionProtocol protocol = Shared::TrustSummary::protocolValues.at(pair.first);
|
||||||
|
for (const std::pair<const QByteArray, Shared::TrustLevel>& trust : keys)
|
||||||
|
result.increment(protocol, trust.second);
|
||||||
|
|
||||||
|
} catch (const LMDBAL::NotFound& e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Shared::TrustLevel Core::TrustHandler::convert(Core::TrustHandler::TL level) {
|
||||||
|
switch (level) {
|
||||||
|
case QXmpp::TrustLevel::Undecided: return Shared::TrustLevel::undecided;
|
||||||
|
case QXmpp::TrustLevel::AutomaticallyDistrusted: return Shared::TrustLevel::automaticallyDistrusted;
|
||||||
|
case QXmpp::TrustLevel::ManuallyDistrusted: return Shared::TrustLevel::manuallyDistrusted;
|
||||||
|
case QXmpp::TrustLevel::AutomaticallyTrusted: return Shared::TrustLevel::automaticallyTrusted;
|
||||||
|
case QXmpp::TrustLevel::ManuallyTrusted: return Shared::TrustLevel::manuallyTrusted;
|
||||||
|
case QXmpp::TrustLevel::Authenticated: return Shared::TrustLevel::authenticated;
|
||||||
|
default: throw 2413; //never supposed to get here, switch case if complete, this line is just to suppress a warning
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Core::TrustHandler::TL Core::TrustHandler::convert(Shared::TrustLevel level) {
|
||||||
|
switch (level) {
|
||||||
|
case Shared::TrustLevel::undecided: return QXmpp::TrustLevel::Undecided;
|
||||||
|
case Shared::TrustLevel::automaticallyDistrusted: return QXmpp::TrustLevel::AutomaticallyDistrusted;
|
||||||
|
case Shared::TrustLevel::manuallyDistrusted: return QXmpp::TrustLevel::ManuallyDistrusted;
|
||||||
|
case Shared::TrustLevel::automaticallyTrusted: return QXmpp::TrustLevel::AutomaticallyTrusted;
|
||||||
|
case Shared::TrustLevel::manuallyTrusted: return QXmpp::TrustLevel::ManuallyTrusted;
|
||||||
|
case Shared::TrustLevel::authenticated: return QXmpp::TrustLevel::Authenticated;
|
||||||
|
default: throw 2413; //never supposed to get here, switch case if complete, this line is just to suppress a warning
|
||||||
|
}
|
||||||
|
}
|
89
core/handlers/trusthandler.h
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
#ifndef CORE_TRUSTHANDLER_H
|
||||||
|
#define CORE_TRUSTHANDLER_H
|
||||||
|
|
||||||
|
#include <shared/enums.h>
|
||||||
|
#include <shared/trustsummary.h>
|
||||||
|
|
||||||
|
#include <QXmppTrustStorage.h>
|
||||||
|
#include <cache.h>
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class Account;
|
||||||
|
|
||||||
|
class TrustHandler : public QObject, public QXmppTrustStorage {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
TrustHandler(Account* account);
|
||||||
|
~TrustHandler();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void trustLevelsChanged(const QString& jid, const Shared::TrustSummary& summary) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef QMultiHash<QString, QByteArray> MultySB;
|
||||||
|
typedef QHash<QString, MultySB> HashSM;
|
||||||
|
typedef const QList<QString>& CLSR;
|
||||||
|
typedef const QList<QByteArray>& CLBAR;
|
||||||
|
typedef const QString& CSR;
|
||||||
|
typedef QXmpp::TrustLevel TL;
|
||||||
|
typedef QHash<QString, QHash<QByteArray, TL>> HSHBTL;
|
||||||
|
|
||||||
|
typedef std::map<QByteArray, Shared::TrustLevel> Keys;
|
||||||
|
typedef LMDBAL::Cache<QString, Keys> KeyCache;
|
||||||
|
|
||||||
|
virtual QXmppTask<void> resetAll(CSR encryption) override;
|
||||||
|
virtual QXmppTask<TL> trustLevel(CSR encryption, CSR keyOwnerJid, const QByteArray& keyId) override;
|
||||||
|
virtual QXmppTask<HashSM> setTrustLevel(CSR encryption, CLSR keyOwnerJids, TL oldTrustLevel, TL newTrustLevel) override;
|
||||||
|
virtual QXmppTask<HashSM> setTrustLevel(CSR encryption, const MultySB& keyIds, TL trustLevel) override;
|
||||||
|
virtual QXmppTask<bool> hasKey(CSR encryption, CSR keyOwnerJid, QXmpp::TrustLevels trustLevels) override;
|
||||||
|
virtual QXmppTask<HSHBTL> keys(CSR encryption, CLSR keyOwnerJids, QXmpp::TrustLevels trustLevels) override;
|
||||||
|
virtual QXmppTask<QHash<TL, MultySB>> keys(CSR encryption, QXmpp::TrustLevels trustLevels) override;
|
||||||
|
virtual QXmppTask<void> removeKeys(CSR encryption) override;
|
||||||
|
virtual QXmppTask<void> removeKeys(CSR encryption, CSR keyOwnerJid) override;
|
||||||
|
virtual QXmppTask<void> removeKeys(CSR encryption, CLBAR keyIds) override;
|
||||||
|
virtual QXmppTask<void> addKeys(CSR encryption, CSR keyOwnerJid, CLBAR keyIds, TL trustLevel) override;
|
||||||
|
virtual QXmppTask<QByteArray> ownKey(CSR encryption) override;
|
||||||
|
virtual QXmppTask<void> resetOwnKey(CSR encryption) override;
|
||||||
|
virtual QXmppTask<void> setOwnKey(CSR encryption, const QByteArray& keyId) override;
|
||||||
|
virtual QXmppTask<QXmpp::TrustSecurityPolicy> securityPolicy(CSR encryption) override;
|
||||||
|
virtual QXmppTask<void> resetSecurityPolicy(CSR encryption) override;
|
||||||
|
virtual QXmppTask<void> setSecurityPolicy(const QString& encryption, QXmpp::TrustSecurityPolicy securityPolicy) override;
|
||||||
|
|
||||||
|
static TL convert(Shared::TrustLevel level);
|
||||||
|
static Shared::TrustLevel convert(TL level);
|
||||||
|
|
||||||
|
Keys getKeys(Shared::EncryptionProtocol protocol, const QString& jid) const;
|
||||||
|
Shared::TrustSummary getSummary(const QString& jid) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
KeyCache* createNewCache(const QString& encryption);
|
||||||
|
KeyCache* getCache(const QString& encryption);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Account* acc;
|
||||||
|
LMDBAL::Base db;
|
||||||
|
QFile protocols;
|
||||||
|
LMDBAL::Cache<QString, uint8_t>* securityPolicies;
|
||||||
|
LMDBAL::Cache<QString, QByteArray>* ownKeys;
|
||||||
|
std::map<QString, KeyCache*> keysByProtocol;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CORE_TRUSTHANDLER_H
|
@ -20,15 +20,9 @@
|
|||||||
Core::VCardHandler::VCardHandler(Account* account):
|
Core::VCardHandler::VCardHandler(Account* account):
|
||||||
QObject(),
|
QObject(),
|
||||||
acc(account),
|
acc(account),
|
||||||
ownVCardRequestInProgress(false),
|
|
||||||
pendingVCardRequests(),
|
|
||||||
avatarHash(),
|
avatarHash(),
|
||||||
avatarType()
|
avatarType()
|
||||||
{
|
{
|
||||||
connect(acc->vm, &QXmppVCardManager::vCardReceived, this, &VCardHandler::onVCardReceived);
|
|
||||||
//for some reason it doesn't work, launching from common handler
|
|
||||||
//connect(acc->vm, &QXmppVCardManager::clientVCardReceived, this, &VCardHandler::onOwnVCardReceived);
|
|
||||||
|
|
||||||
QString path(QStandardPaths::writableLocation(QStandardPaths::CacheLocation));
|
QString path(QStandardPaths::writableLocation(QStandardPaths::CacheLocation));
|
||||||
path += "/" + acc->name;
|
path += "/" + acc->name;
|
||||||
QDir dir(path);
|
QDir dir(path);
|
||||||
@ -67,6 +61,15 @@ Core::VCardHandler::VCardHandler(Account* account):
|
|||||||
avatarType = type;
|
avatarType = type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Core::VCardHandler::~VCardHandler() {}
|
||||||
|
|
||||||
|
void Core::VCardHandler::initialize() {
|
||||||
|
connect(acc->vm, &QXmppVCardManager::vCardReceived, this, &VCardHandler::onVCardReceived);
|
||||||
|
//for some reason it doesn't work, launching from common handler
|
||||||
|
//connect(acc->vm, &QXmppVCardManager::clientVCardReceived, this, &VCardHandler::onOwnVCardReceived);
|
||||||
|
|
||||||
if (avatarType.size() != 0) {
|
if (avatarType.size() != 0) {
|
||||||
acc->presence.setVCardUpdateType(QXmppPresence::VCardUpdateValidPhoto);
|
acc->presence.setVCardUpdateType(QXmppPresence::VCardUpdateValidPhoto);
|
||||||
acc->presence.setPhotoHash(avatarHash.toUtf8());
|
acc->presence.setPhotoHash(avatarHash.toUtf8());
|
||||||
@ -75,13 +78,7 @@ Core::VCardHandler::VCardHandler(Account* account):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::VCardHandler::~VCardHandler()
|
void Core::VCardHandler::onVCardReceived(const QXmppVCardIq& card) {
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::VCardHandler::onVCardReceived(const QXmppVCardIq& card)
|
|
||||||
{
|
|
||||||
QString id = card.from();
|
QString id = card.from();
|
||||||
QStringList comps = id.split("/");
|
QStringList comps = id.split("/");
|
||||||
QString jid = comps.front().toLower();
|
QString jid = comps.front().toLower();
|
||||||
@ -89,25 +86,23 @@ void Core::VCardHandler::onVCardReceived(const QXmppVCardIq& card)
|
|||||||
if (comps.size() > 1) {
|
if (comps.size() > 1) {
|
||||||
resource = comps.back();
|
resource = comps.back();
|
||||||
}
|
}
|
||||||
pendingVCardRequests.erase(id);
|
|
||||||
RosterItem* item = acc->rh->getRosterItem(jid);
|
RosterItem* item = acc->rh->getRosterItem(jid);
|
||||||
|
|
||||||
if (item == 0) {
|
if (item == nullptr) {
|
||||||
if (jid == acc->getBareJid()) {
|
if (jid == acc->getBareJid())
|
||||||
onOwnVCardReceived(card);
|
onOwnVCardReceived(card);
|
||||||
} else {
|
else
|
||||||
qDebug() << "received vCard" << jid << "doesn't belong to any of known contacts or conferences, skipping";
|
qDebug() << "received vCard" << jid << "doesn't belong to any of known contacts or conferences, skipping";
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Shared::VCard vCard = item->handleResponseVCard(card, resource);
|
Shared::VCard vCard;
|
||||||
|
item->handleResponseVCard(card, resource, vCard);
|
||||||
emit acc->receivedVCard(jid, vCard);
|
acc->delay->receivedVCard(id, vCard);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::VCardHandler::onOwnVCardReceived(const QXmppVCardIq& card)
|
void Core::VCardHandler::onOwnVCardReceived(const QXmppVCardIq& card) {
|
||||||
{
|
|
||||||
QByteArray ava = card.photo();
|
QByteArray ava = card.photo();
|
||||||
bool avaChanged = false;
|
bool avaChanged = false;
|
||||||
QString path = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/" + acc->name + "/";
|
QString path = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/" + acc->name + "/";
|
||||||
@ -186,8 +181,6 @@ void Core::VCardHandler::onOwnVCardReceived(const QXmppVCardIq& card)
|
|||||||
emit acc->changed(change);
|
emit acc->changed(change);
|
||||||
}
|
}
|
||||||
|
|
||||||
ownVCardRequestInProgress = false;
|
|
||||||
|
|
||||||
Shared::VCard vCard;
|
Shared::VCard vCard;
|
||||||
initializeVCard(vCard, card);
|
initializeVCard(vCard, card);
|
||||||
|
|
||||||
@ -198,62 +191,30 @@ void Core::VCardHandler::onOwnVCardReceived(const QXmppVCardIq& card)
|
|||||||
vCard.setAvatarType(Shared::Avatar::empty);
|
vCard.setAvatarType(Shared::Avatar::empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit acc->receivedVCard(acc->getBareJid(), vCard);
|
if (acc->delay->isOwnVCardPending())
|
||||||
|
acc->delay->receivedOwnVCard(vCard);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::VCardHandler::handleOffline()
|
void Core::VCardHandler::handlePresenceOfMyAccountChange(const QXmppPresence& p_presence) {
|
||||||
{
|
if (!acc->delay->isOwnVCardPending()) {
|
||||||
pendingVCardRequests.clear();
|
|
||||||
Shared::VCard vCard; //just to show, that there is now more pending request
|
|
||||||
for (const QString& jid : pendingVCardRequests) {
|
|
||||||
emit acc->receivedVCard(jid, vCard); //need to show it better in the future, like with an error
|
|
||||||
}
|
|
||||||
pendingVCardRequests.clear();
|
|
||||||
ownVCardRequestInProgress = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::VCardHandler::requestVCard(const QString& jid)
|
|
||||||
{
|
|
||||||
if (pendingVCardRequests.find(jid) == pendingVCardRequests.end()) {
|
|
||||||
qDebug() << "requesting vCard" << jid;
|
|
||||||
if (jid == acc->getBareJid()) {
|
|
||||||
if (!ownVCardRequestInProgress) {
|
|
||||||
acc->vm->requestClientVCard();
|
|
||||||
ownVCardRequestInProgress = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
acc->vm->requestVCard(jid);
|
|
||||||
pendingVCardRequests.insert(jid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::VCardHandler::handleOtherPresenceOfMyAccountChange(const QXmppPresence& p_presence)
|
|
||||||
{
|
|
||||||
if (!ownVCardRequestInProgress) {
|
|
||||||
switch (p_presence.vCardUpdateType()) {
|
switch (p_presence.vCardUpdateType()) {
|
||||||
case QXmppPresence::VCardUpdateNone: //this presence has nothing to do with photo
|
case QXmppPresence::VCardUpdateNone: //this presence has nothing to do with photo
|
||||||
break;
|
break;
|
||||||
case QXmppPresence::VCardUpdateNotReady: //let's say the photo didn't change here
|
case QXmppPresence::VCardUpdateNotReady: //let's say the photo didn't change here
|
||||||
break;
|
break;
|
||||||
case QXmppPresence::VCardUpdateNoPhoto: //there is no photo, need to drop if any
|
case QXmppPresence::VCardUpdateNoPhoto: //there is no photo, need to drop if any
|
||||||
if (avatarType.size() > 0) {
|
if (avatarType.size() > 0)
|
||||||
acc->vm->requestClientVCard();
|
acc->delay->getOwnVCard();
|
||||||
ownVCardRequestInProgress = true;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case QXmppPresence::VCardUpdateValidPhoto: //there is a photo, need to load
|
case QXmppPresence::VCardUpdateValidPhoto: //there is a photo, need to load
|
||||||
if (avatarHash != p_presence.photoHash()) {
|
if (avatarHash != p_presence.photoHash())
|
||||||
acc->vm->requestClientVCard();
|
acc->delay->getOwnVCard();
|
||||||
ownVCardRequestInProgress = true;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::VCardHandler::uploadVCard(const Shared::VCard& card)
|
void Core::VCardHandler::uploadVCard(const Shared::VCard& card) {
|
||||||
{
|
|
||||||
QXmppVCardIq iq;
|
QXmppVCardIq iq;
|
||||||
initializeQXmppVCard(iq, card);
|
initializeQXmppVCard(iq, card);
|
||||||
|
|
||||||
@ -282,13 +243,12 @@ void Core::VCardHandler::uploadVCard(const Shared::VCard& card)
|
|||||||
} else {
|
} else {
|
||||||
if (avatarType.size() > 0) {
|
if (avatarType.size() > 0) {
|
||||||
QFile oA(oldPath);
|
QFile oA(oldPath);
|
||||||
if (!oA.open(QFile::ReadOnly)) {
|
if (!oA.open(QFile::ReadOnly))
|
||||||
qDebug() << "Couldn't read old avatar of account" << acc->name << ", uploading empty avatar";
|
qDebug() << "Couldn't read old avatar of account" << acc->name << ", uploading empty avatar";
|
||||||
} else {
|
else
|
||||||
data = oA.readAll();
|
data = oA.readAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (data.size() > 0) {
|
if (data.size() > 0) {
|
||||||
QMimeDatabase db;
|
QMimeDatabase db;
|
||||||
@ -302,11 +262,9 @@ void Core::VCardHandler::uploadVCard(const Shared::VCard& card)
|
|||||||
onOwnVCardReceived(iq);
|
onOwnVCardReceived(iq);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Core::VCardHandler::getAvatarPath() const
|
QString Core::VCardHandler::getAvatarPath() const {
|
||||||
{
|
if (avatarType.size() == 0)
|
||||||
if (avatarType.size() == 0) {
|
|
||||||
return "";
|
return "";
|
||||||
} else {
|
else
|
||||||
return QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/" + acc->name + "/" + "avatar." + avatarType;
|
return QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/" + acc->name + "/" + "avatar." + avatarType;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -42,12 +42,12 @@ public:
|
|||||||
VCardHandler(Account* account);
|
VCardHandler(Account* account);
|
||||||
~VCardHandler();
|
~VCardHandler();
|
||||||
|
|
||||||
void handleOffline();
|
void handlePresenceOfMyAccountChange(const QXmppPresence& p_presence);
|
||||||
void requestVCard(const QString& jid);
|
|
||||||
void handleOtherPresenceOfMyAccountChange(const QXmppPresence& p_presence);
|
|
||||||
void uploadVCard(const Shared::VCard& card);
|
void uploadVCard(const Shared::VCard& card);
|
||||||
QString getAvatarPath() const;
|
QString getAvatarPath() const;
|
||||||
|
|
||||||
|
void initialize();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onVCardReceived(const QXmppVCardIq& card);
|
void onVCardReceived(const QXmppVCardIq& card);
|
||||||
void onOwnVCardReceived(const QXmppVCardIq& card);
|
void onOwnVCardReceived(const QXmppVCardIq& card);
|
||||||
@ -55,8 +55,6 @@ private slots:
|
|||||||
private:
|
private:
|
||||||
Account* acc;
|
Account* acc;
|
||||||
|
|
||||||
bool ownVCardRequestInProgress;
|
|
||||||
std::set<QString> pendingVCardRequests;
|
|
||||||
QString avatarHash;
|
QString avatarHash;
|
||||||
QString avatarType;
|
QString avatarType;
|
||||||
};
|
};
|
||||||
|
@ -27,7 +27,7 @@ Core::RosterItem::RosterItem(const QString& pJid, const QString& pAccount, QObje
|
|||||||
account(pAccount),
|
account(pAccount),
|
||||||
name(),
|
name(),
|
||||||
archiveState(empty),
|
archiveState(empty),
|
||||||
archive(new Archive(jid)),
|
archive(new Archive(account, jid)),
|
||||||
syncronizing(false),
|
syncronizing(false),
|
||||||
requestedCount(0),
|
requestedCount(0),
|
||||||
requestedBefore(),
|
requestedBefore(),
|
||||||
@ -38,42 +38,36 @@ Core::RosterItem::RosterItem(const QString& pJid, const QString& pAccount, QObje
|
|||||||
toCorrect(),
|
toCorrect(),
|
||||||
muc(false)
|
muc(false)
|
||||||
{
|
{
|
||||||
archive->open(account);
|
archive->open();
|
||||||
|
|
||||||
if (archive->size() != 0) {
|
if (archive->size() != 0) {
|
||||||
if (archive->isFromTheBeginning()) {
|
if (archive->isFromTheBeginning())
|
||||||
archiveState = beginning;
|
archiveState = beginning;
|
||||||
} else {
|
else
|
||||||
archiveState = chunk;
|
archiveState = chunk;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::RosterItem::~RosterItem()
|
Core::RosterItem::~RosterItem() {
|
||||||
{
|
|
||||||
delete archive;
|
delete archive;
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::RosterItem::ArchiveState Core::RosterItem::getArchiveState() const
|
Core::RosterItem::ArchiveState Core::RosterItem::getArchiveState() const {
|
||||||
{
|
|
||||||
return archiveState;
|
return archiveState;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Core::RosterItem::getName() const
|
QString Core::RosterItem::getName() const {
|
||||||
{
|
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterItem::setName(const QString& n)
|
void Core::RosterItem::setName(const QString& n) {
|
||||||
{
|
|
||||||
if (name != n) {
|
if (name != n) {
|
||||||
name = n;
|
name = n;
|
||||||
emit nameChanged(name);
|
emit nameChanged(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterItem::addMessageToArchive(const Shared::Message& msg)
|
void Core::RosterItem::addMessageToArchive(const Shared::Message& msg) {
|
||||||
{
|
|
||||||
if (msg.storable()) {
|
if (msg.storable()) {
|
||||||
hisoryCache.push_back(msg);
|
hisoryCache.push_back(msg);
|
||||||
std::map<QString, Shared::Message>::iterator itr = toCorrect.find(msg.getId());
|
std::map<QString, Shared::Message>::iterator itr = toCorrect.find(msg.getId());
|
||||||
@ -87,8 +81,7 @@ void Core::RosterItem::addMessageToArchive(const Shared::Message& msg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterItem::correctMessageInArchive(const QString& originalId, const Shared::Message& msg)
|
void Core::RosterItem::correctMessageInArchive(const QString& originalId, const Shared::Message& msg) {
|
||||||
{
|
|
||||||
if (msg.storable()) {
|
if (msg.storable()) {
|
||||||
QDateTime thisTime = msg.getTime();
|
QDateTime thisTime = msg.getTime();
|
||||||
std::map<QString, Shared::Message>::iterator itr = toCorrect.find(originalId);
|
std::map<QString, Shared::Message>::iterator itr = toCorrect.find(originalId);
|
||||||
@ -109,8 +102,7 @@ void Core::RosterItem::correctMessageInArchive(const QString& originalId, const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterItem::requestHistory(int count, const QString& before)
|
void Core::RosterItem::requestHistory(int count, const QString& before) {
|
||||||
{
|
|
||||||
if (syncronizing) {
|
if (syncronizing) {
|
||||||
requestCache.emplace_back(count, before);
|
requestCache.emplace_back(count, before);
|
||||||
} else {
|
} else {
|
||||||
@ -118,8 +110,7 @@ void Core::RosterItem::requestHistory(int count, const QString& before)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterItem::nextRequest()
|
void Core::RosterItem::nextRequest() {
|
||||||
{
|
|
||||||
if (syncronizing) {
|
if (syncronizing) {
|
||||||
if (requestedCount != -1) {
|
if (requestedCount != -1) {
|
||||||
bool last = false;
|
bool last = false;
|
||||||
@ -135,7 +126,8 @@ void Core::RosterItem::nextRequest()
|
|||||||
last = true;
|
last = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (const Archive::Empty& e) {
|
//} catch (const Archive::Empty& e) {
|
||||||
|
} catch (const LMDBAL::NotFound& e) {
|
||||||
last = true;
|
last = true;
|
||||||
}
|
}
|
||||||
} else if (archiveState == empty && responseCache.size() == 0) {
|
} else if (archiveState == empty && responseCache.size() == 0) {
|
||||||
@ -157,8 +149,7 @@ void Core::RosterItem::nextRequest()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterItem::performRequest(int count, const QString& before)
|
void Core::RosterItem::performRequest(int count, const QString& before) {
|
||||||
{
|
|
||||||
syncronizing = true;
|
syncronizing = true;
|
||||||
requestedCount = count;
|
requestedCount = count;
|
||||||
requestedBefore = before;
|
requestedBefore = before;
|
||||||
@ -178,7 +169,8 @@ void Core::RosterItem::performRequest(int count, const QString& before)
|
|||||||
try {
|
try {
|
||||||
Shared::Message msg = archive->newest();
|
Shared::Message msg = archive->newest();
|
||||||
emit needHistory("", getId(msg), msg.getTime());
|
emit needHistory("", getId(msg), msg.getTime());
|
||||||
} catch (const Archive::Empty& e) { //this can happen when the only message in archive is not server stored (error, for example)
|
//} catch (const Archive::Empty& e) {
|
||||||
|
} catch (const LMDBAL::NotFound& e) { //this can happen when the only message in archive is not server stored (error, for example)
|
||||||
emit needHistory(before, "");
|
emit needHistory(before, "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -196,14 +188,14 @@ void Core::RosterItem::performRequest(int count, const QString& before)
|
|||||||
std::list<Shared::Message> arc = archive->getBefore(requestedCount - responseCache.size(), lBefore);
|
std::list<Shared::Message> arc = archive->getBefore(requestedCount - responseCache.size(), lBefore);
|
||||||
responseCache.insert(responseCache.begin(), arc.begin(), arc.end());
|
responseCache.insert(responseCache.begin(), arc.begin(), arc.end());
|
||||||
found = true;
|
found = true;
|
||||||
} catch (const Archive::NotFound& e) {
|
} catch (const LMDBAL::NotFound& e) {
|
||||||
requestCache.emplace_back(requestedCount, before);
|
|
||||||
requestedCount = -1;
|
|
||||||
emit needHistory(getId(archive->oldest()), "");
|
|
||||||
} catch (const Archive::Empty& e) {
|
|
||||||
requestCache.emplace_back(requestedCount, before);
|
requestCache.emplace_back(requestedCount, before);
|
||||||
requestedCount = -1;
|
requestedCount = -1;
|
||||||
emit needHistory(getId(archive->oldest()), "");
|
emit needHistory(getId(archive->oldest()), "");
|
||||||
|
// } catch (const Archive::Empty& e) {
|
||||||
|
// requestCache.emplace_back(requestedCount, before);
|
||||||
|
// requestedCount = -1;
|
||||||
|
// emit needHistory(getId(archive->oldest()), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (found) {
|
if (found) {
|
||||||
@ -236,18 +228,17 @@ void Core::RosterItem::performRequest(int count, const QString& before)
|
|||||||
try {
|
try {
|
||||||
std::list<Shared::Message> arc = archive->getBefore(requestedCount - responseCache.size(), before);
|
std::list<Shared::Message> arc = archive->getBefore(requestedCount - responseCache.size(), before);
|
||||||
responseCache.insert(responseCache.begin(), arc.begin(), arc.end());
|
responseCache.insert(responseCache.begin(), arc.begin(), arc.end());
|
||||||
} catch (const Archive::NotFound& e) {
|
} catch (const LMDBAL::NotFound& e) {
|
||||||
qDebug("requesting id hasn't been found in archive, skipping");
|
|
||||||
} catch (const Archive::Empty& e) {
|
|
||||||
qDebug("requesting id hasn't been found in archive, skipping");
|
qDebug("requesting id hasn't been found in archive, skipping");
|
||||||
|
// } catch (const Archive::Empty& e) {
|
||||||
|
// qDebug("requesting id hasn't been found in archive, skipping");
|
||||||
}
|
}
|
||||||
nextRequest();
|
nextRequest();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Core::RosterItem::getId(const Shared::Message& msg)
|
QString Core::RosterItem::getId(const Shared::Message& msg) {
|
||||||
{
|
|
||||||
QString id;
|
QString id;
|
||||||
if (muc) {
|
if (muc) {
|
||||||
id = msg.getStanzaId();
|
id = msg.getStanzaId();
|
||||||
@ -257,8 +248,7 @@ QString Core::RosterItem::getId(const Shared::Message& msg)
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterItem::appendMessageToArchive(const Shared::Message& msg)
|
void Core::RosterItem::appendMessageToArchive(const Shared::Message& msg) {
|
||||||
{
|
|
||||||
if (msg.getId().size() > 0) {
|
if (msg.getId().size() > 0) {
|
||||||
if (msg.storable()) {
|
if (msg.storable()) {
|
||||||
switch (archiveState) {
|
switch (archiveState) {
|
||||||
@ -299,8 +289,7 @@ void Core::RosterItem::appendMessageToArchive(const Shared::Message& msg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Core::RosterItem::changeMessage(const QString& id, const QMap<QString, QVariant>& data)
|
bool Core::RosterItem::changeMessage(const QString& id, const QMap<QString, QVariant>& data) {
|
||||||
{
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (Shared::Message& msg : appendCache) {
|
for (Shared::Message& msg : appendCache) {
|
||||||
if (msg.getId() == id) {
|
if (msg.getId() == id) {
|
||||||
@ -324,7 +313,7 @@ bool Core::RosterItem::changeMessage(const QString& id, const QMap<QString, QVar
|
|||||||
try {
|
try {
|
||||||
archive->changeMessage(id, data);
|
archive->changeMessage(id, data);
|
||||||
found = true;
|
found = true;
|
||||||
} catch (const Archive::NotFound& e) {
|
} catch (const LMDBAL::NotFound& e) {
|
||||||
qDebug() << "An attempt to change state to the message" << id << "but it couldn't be found";
|
qDebug() << "An attempt to change state to the message" << id << "but it couldn't be found";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -341,8 +330,7 @@ bool Core::RosterItem::changeMessage(const QString& id, const QMap<QString, QVar
|
|||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterItem::flushMessagesToArchive(bool finished, const QString& firstId, const QString& lastId)
|
void Core::RosterItem::flushMessagesToArchive(bool finished, const QString& firstId, const QString& lastId) {
|
||||||
{
|
|
||||||
unsigned int added(0);
|
unsigned int added(0);
|
||||||
if (hisoryCache.size() > 0) {
|
if (hisoryCache.size() > 0) {
|
||||||
added = archive->addElements(hisoryCache);
|
added = archive->addElements(hisoryCache);
|
||||||
@ -401,10 +389,8 @@ void Core::RosterItem::flushMessagesToArchive(bool finished, const QString& firs
|
|||||||
std::list<Shared::Message> arc = archive->getBefore(requestedCount - responseCache.size(), before);
|
std::list<Shared::Message> arc = archive->getBefore(requestedCount - responseCache.size(), before);
|
||||||
responseCache.insert(responseCache.begin(), arc.begin(), arc.end());
|
responseCache.insert(responseCache.begin(), arc.begin(), arc.end());
|
||||||
found = true;
|
found = true;
|
||||||
} catch (const Archive::NotFound& e) {
|
} catch (const LMDBAL::NotFound& e) {
|
||||||
|
// } catch (const Archive::Empty& e) {
|
||||||
} catch (const Archive::Empty& e) {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
if (!found || requestedCount > int(responseCache.size())) {
|
if (!found || requestedCount > int(responseCache.size())) {
|
||||||
if (archiveState == complete) {
|
if (archiveState == complete) {
|
||||||
@ -429,51 +415,43 @@ void Core::RosterItem::flushMessagesToArchive(bool finished, const QString& firs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Core::RosterItem::getServer() const
|
QString Core::RosterItem::getServer() const {
|
||||||
{
|
|
||||||
QStringList lst = jid.split("@");
|
QStringList lst = jid.split("@");
|
||||||
return lst.back();
|
return lst.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Core::RosterItem::isMuc() const
|
bool Core::RosterItem::isMuc() const {
|
||||||
{
|
|
||||||
return muc;
|
return muc;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Core::RosterItem::avatarPath(const QString& resource) const
|
QString Core::RosterItem::avatarPath(const QString& resource) const {
|
||||||
{
|
|
||||||
QString path = folderPath() + "/" + (resource.size() == 0 ? jid : resource);
|
QString path = folderPath() + "/" + (resource.size() == 0 ? jid : resource);
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Core::RosterItem::folderPath() const
|
QString Core::RosterItem::folderPath() const {
|
||||||
{
|
|
||||||
QString path(QStandardPaths::writableLocation(QStandardPaths::CacheLocation));
|
QString path(QStandardPaths::writableLocation(QStandardPaths::CacheLocation));
|
||||||
path += "/" + account + "/" + jid;
|
path += "/" + account + "/" + jid;
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Core::RosterItem::setAvatar(const QByteArray& data, Archive::AvatarInfo& info, const QString& resource)
|
bool Core::RosterItem::setAvatar(const QByteArray& data, Archive::AvatarInfo& info, const QString& resource) {
|
||||||
{
|
|
||||||
bool result = archive->setAvatar(data, info, false, resource);
|
bool result = archive->setAvatar(data, info, false, resource);
|
||||||
if (resource.size() == 0 && result) {
|
if (resource.size() == 0 && result) {
|
||||||
if (data.size() == 0) {
|
if (data.size() == 0)
|
||||||
emit avatarChanged(Shared::Avatar::empty, "");
|
emit avatarChanged(Shared::Avatar::empty, "");
|
||||||
} else {
|
else
|
||||||
emit avatarChanged(Shared::Avatar::valid, avatarPath(resource) + "." + info.type);
|
emit avatarChanged(Shared::Avatar::valid, avatarPath(resource) + "." + info.type);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Core::RosterItem::setAutoGeneratedAvatar(const QString& resource)
|
bool Core::RosterItem::setAutoGeneratedAvatar(const QString& resource) {
|
||||||
{
|
|
||||||
Archive::AvatarInfo info;
|
Archive::AvatarInfo info;
|
||||||
return setAutoGeneratedAvatar(info, resource);
|
return setAutoGeneratedAvatar(info, resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Core::RosterItem::setAutoGeneratedAvatar(Archive::AvatarInfo& info, const QString& resource)
|
bool Core::RosterItem::setAutoGeneratedAvatar(Archive::AvatarInfo& info, const QString& resource) {
|
||||||
{
|
|
||||||
QImage image(96, 96, QImage::Format_ARGB32_Premultiplied);
|
QImage image(96, 96, QImage::Format_ARGB32_Premultiplied);
|
||||||
QPainter painter(&image);
|
QPainter painter(&image);
|
||||||
quint8 colorIndex = rand() % Shared::colorPalette.size();
|
quint8 colorIndex = rand() % Shared::colorPalette.size();
|
||||||
@ -483,11 +461,11 @@ bool Core::RosterItem::setAutoGeneratedAvatar(Archive::AvatarInfo& info, const Q
|
|||||||
f.setBold(true);
|
f.setBold(true);
|
||||||
f.setPixelSize(72);
|
f.setPixelSize(72);
|
||||||
painter.setFont(f);
|
painter.setFont(f);
|
||||||
if (bg.lightnessF() > 0.5) {
|
if (bg.lightnessF() > 0.5)
|
||||||
painter.setPen(Qt::black);
|
painter.setPen(Qt::black);
|
||||||
} else {
|
else
|
||||||
painter.setPen(Qt::white);
|
painter.setPen(Qt::white);
|
||||||
}
|
|
||||||
painter.drawText(image.rect(), Qt::AlignCenter | Qt::AlignVCenter, resource.size() == 0 ? jid.at(0).toUpper() : resource.at(0).toUpper());
|
painter.drawText(image.rect(), Qt::AlignCenter | Qt::AlignVCenter, resource.size() == 0 ? jid.at(0).toUpper() : resource.at(0).toUpper());
|
||||||
QByteArray arr;
|
QByteArray arr;
|
||||||
QBuffer stream(&arr);
|
QBuffer stream(&arr);
|
||||||
@ -495,25 +473,22 @@ bool Core::RosterItem::setAutoGeneratedAvatar(Archive::AvatarInfo& info, const Q
|
|||||||
image.save(&stream, "PNG");
|
image.save(&stream, "PNG");
|
||||||
stream.close();
|
stream.close();
|
||||||
bool result = archive->setAvatar(arr, info, true, resource);
|
bool result = archive->setAvatar(arr, info, true, resource);
|
||||||
if (resource.size() == 0 && result) {
|
if (resource.size() == 0 && result)
|
||||||
emit avatarChanged(Shared::Avatar::autocreated, avatarPath(resource) + ".png");
|
emit avatarChanged(Shared::Avatar::autocreated, avatarPath(resource) + ".png");
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Core::RosterItem::readAvatarInfo(Archive::AvatarInfo& target, const QString& resource) const
|
bool Core::RosterItem::readAvatarInfo(Archive::AvatarInfo& target, const QString& resource) const {
|
||||||
{
|
|
||||||
return archive->readAvatarInfo(target, resource);
|
return archive->readAvatarInfo(target, resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
Shared::VCard Core::RosterItem::handleResponseVCard(const QXmppVCardIq& card, const QString& resource)
|
void Core::RosterItem::handleResponseVCard(const QXmppVCardIq& card, const QString& resource, Shared::VCard& vCard) {
|
||||||
{
|
|
||||||
Archive::AvatarInfo info;
|
Archive::AvatarInfo info;
|
||||||
Archive::AvatarInfo newInfo;
|
Archive::AvatarInfo newInfo;
|
||||||
bool hasAvatar = readAvatarInfo(info, resource);
|
bool hasAvatar = readAvatarInfo(info, resource);
|
||||||
|
|
||||||
QByteArray ava = card.photo();
|
QByteArray ava = card.photo();
|
||||||
Shared::VCard vCard;
|
|
||||||
initializeVCard(vCard, card);
|
initializeVCard(vCard, card);
|
||||||
Shared::Avatar type = Shared::Avatar::empty;
|
Shared::Avatar type = Shared::Avatar::empty;
|
||||||
QString path = "";
|
QString path = "";
|
||||||
@ -533,9 +508,9 @@ Shared::VCard Core::RosterItem::handleResponseVCard(const QXmppVCardIq& card, co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!hasAvatar || !info.autogenerated) {
|
if (!hasAvatar || !info.autogenerated)
|
||||||
setAutoGeneratedAvatar(resource);
|
setAutoGeneratedAvatar(resource);
|
||||||
}
|
|
||||||
type = Shared::Avatar::autocreated;
|
type = Shared::Avatar::autocreated;
|
||||||
path = avatarPath(resource) + ".png";
|
path = avatarPath(resource) + ".png";
|
||||||
}
|
}
|
||||||
@ -543,15 +518,11 @@ Shared::VCard Core::RosterItem::handleResponseVCard(const QXmppVCardIq& card, co
|
|||||||
vCard.setAvatarType(type);
|
vCard.setAvatarType(type);
|
||||||
vCard.setAvatarPath(path);
|
vCard.setAvatarPath(path);
|
||||||
|
|
||||||
if (resource.size() == 0) {
|
if (resource.size() == 0)
|
||||||
emit avatarChanged(vCard.getAvatarType(), vCard.getAvatarPath());
|
emit avatarChanged(vCard.getAvatarType(), vCard.getAvatarPath());
|
||||||
}
|
|
||||||
|
|
||||||
return vCard;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterItem::clearArchiveRequests()
|
void Core::RosterItem::clearArchiveRequests() {
|
||||||
{
|
|
||||||
syncronizing = false;
|
syncronizing = false;
|
||||||
requestedCount = 0;
|
requestedCount = 0;
|
||||||
requestedBefore = "";
|
requestedBefore = "";
|
||||||
@ -567,30 +538,72 @@ void Core::RosterItem::clearArchiveRequests()
|
|||||||
requestCache.clear();
|
requestCache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RosterItem::downgradeDatabaseState()
|
void Core::RosterItem::downgradeDatabaseState() {
|
||||||
{
|
if (archiveState == ArchiveState::complete)
|
||||||
if (archiveState == ArchiveState::complete) {
|
|
||||||
archiveState = ArchiveState::beginning;
|
archiveState = ArchiveState::beginning;
|
||||||
}
|
|
||||||
|
|
||||||
if (archiveState == ArchiveState::end) {
|
|
||||||
|
if (archiveState == ArchiveState::end)
|
||||||
archiveState = ArchiveState::chunk;
|
archiveState = ArchiveState::chunk;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Shared::Message Core::RosterItem::getMessage(const QString& id)
|
Shared::Message Core::RosterItem::getMessage(const QString& id) {
|
||||||
{
|
|
||||||
for (const Shared::Message& msg : appendCache) {
|
for (const Shared::Message& msg : appendCache) {
|
||||||
if (msg.getId() == id) {
|
if (msg.getId() == id)
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (Shared::Message& msg : hisoryCache) {
|
for (Shared::Message& msg : hisoryCache) {
|
||||||
if (msg.getId() == id) {
|
if (msg.getId() == id)
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return archive->getElement(id);
|
return archive->getElement(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Shared::EncryptionProtocol Core::RosterItem::encryption() const {
|
||||||
|
return archive->encryption();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::RosterItem::setEncryption(Shared::EncryptionProtocol value) {
|
||||||
|
bool changed = archive->setEncryption(value);
|
||||||
|
if (changed)
|
||||||
|
emit encryptionChanged(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
QMap<QString, QVariant> Core::RosterItem::getInfo() const {
|
||||||
|
QMap<QString, QVariant> result({
|
||||||
|
{"name", name},
|
||||||
|
{"encryption", QVariant::fromValue(encryption())},
|
||||||
|
});
|
||||||
|
Archive::AvatarInfo info;
|
||||||
|
bool hasAvatar = readAvatarInfo(info);
|
||||||
|
careAboutAvatar(hasAvatar, info, result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Core::RosterItem::careAboutAvatar (
|
||||||
|
bool hasAvatar,
|
||||||
|
const Archive::AvatarInfo& info,
|
||||||
|
QMap<QString, QVariant>& output,
|
||||||
|
const QString& resource,
|
||||||
|
const QString& subject
|
||||||
|
) const {
|
||||||
|
if (hasAvatar) {
|
||||||
|
if (info.autogenerated)
|
||||||
|
output.insert("avatarState", QVariant::fromValue(Shared::Avatar::autocreated));
|
||||||
|
else
|
||||||
|
output.insert("avatarState", QVariant::fromValue(Shared::Avatar::valid));
|
||||||
|
|
||||||
|
output.insert("avatarPath", avatarPath(resource) + "." + info.type);
|
||||||
|
} else {
|
||||||
|
output.insert("avatarState", QVariant::fromValue(Shared::Avatar::empty));
|
||||||
|
output.insert("avatarPath", "");
|
||||||
|
if (subject.size() == 0)
|
||||||
|
emit requestVCard(jid);
|
||||||
|
else
|
||||||
|
emit requestVCard(subject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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 CORE_ROSTERITEM_H
|
#pragma once
|
||||||
#define CORE_ROSTERITEM_H
|
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
@ -34,7 +33,7 @@
|
|||||||
#include "shared/enums.h"
|
#include "shared/enums.h"
|
||||||
#include "shared/message.h"
|
#include "shared/message.h"
|
||||||
#include "shared/vcard.h"
|
#include "shared/vcard.h"
|
||||||
#include "storage/archive.h"
|
#include "components/archive.h"
|
||||||
#include "adapterfunctions.h"
|
#include "adapterfunctions.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
@ -62,6 +61,8 @@ public:
|
|||||||
void setName(const QString& n);
|
void setName(const QString& n);
|
||||||
QString getServer() const;
|
QString getServer() const;
|
||||||
bool isMuc() const;
|
bool isMuc() const;
|
||||||
|
Shared::EncryptionProtocol encryption() const;
|
||||||
|
void setEncryption(Shared::EncryptionProtocol value);
|
||||||
|
|
||||||
void addMessageToArchive(const Shared::Message& msg);
|
void addMessageToArchive(const Shared::Message& msg);
|
||||||
void correctMessageInArchive(const QString& originalId, const Shared::Message& msg);
|
void correctMessageInArchive(const QString& originalId, const Shared::Message& msg);
|
||||||
@ -72,22 +73,24 @@ public:
|
|||||||
QString folderPath() const;
|
QString folderPath() const;
|
||||||
bool readAvatarInfo(Archive::AvatarInfo& target, const QString& resource = "") const;
|
bool readAvatarInfo(Archive::AvatarInfo& target, const QString& resource = "") const;
|
||||||
virtual bool setAutoGeneratedAvatar(const QString& resource = "");
|
virtual bool setAutoGeneratedAvatar(const QString& resource = "");
|
||||||
virtual Shared::VCard handleResponseVCard(const QXmppVCardIq& card, const QString& resource);
|
virtual void handleResponseVCard(const QXmppVCardIq& card, const QString& resource, Shared::VCard& out);
|
||||||
virtual void handlePresence(const QXmppPresence& pres) = 0;
|
virtual void handlePresence(const QXmppPresence& pres) = 0;
|
||||||
|
|
||||||
bool changeMessage(const QString& id, const QMap<QString, QVariant>& data);
|
bool changeMessage(const QString& id, const QMap<QString, QVariant>& data);
|
||||||
void clearArchiveRequests();
|
void clearArchiveRequests();
|
||||||
void downgradeDatabaseState();
|
void downgradeDatabaseState();
|
||||||
|
virtual QMap<QString, QVariant> getInfo() const;
|
||||||
|
|
||||||
Shared::Message getMessage(const QString& id);
|
Shared::Message getMessage(const QString& id);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void nameChanged(const QString& name);
|
void nameChanged(const QString& name) const;
|
||||||
void subscriptionStateChanged(Shared::SubscriptionState state);
|
void subscriptionStateChanged(Shared::SubscriptionState state) const;
|
||||||
void historyResponse(const std::list<Shared::Message>& messages, bool last);
|
void historyResponse(const std::list<Shared::Message>& messages, bool last) const;
|
||||||
void needHistory(const QString& before, const QString& after, const QDateTime& afterTime = QDateTime());
|
void needHistory(const QString& before, const QString& after, const QDateTime& afterTime = QDateTime()) const;
|
||||||
void avatarChanged(Shared::Avatar, const QString& path);
|
void avatarChanged(Shared::Avatar, const QString& path) const;
|
||||||
void requestVCard(const QString& jid);
|
void requestVCard(const QString& jid) const;
|
||||||
|
void encryptionChanged(Shared::EncryptionProtocol value) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const QString jid;
|
const QString jid;
|
||||||
@ -96,6 +99,13 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
virtual bool setAvatar(const QByteArray& data, Archive::AvatarInfo& info, const QString& resource = "");
|
virtual bool setAvatar(const QByteArray& data, Archive::AvatarInfo& info, const QString& resource = "");
|
||||||
virtual bool setAutoGeneratedAvatar(Archive::AvatarInfo& info, const QString& resource = "");
|
virtual bool setAutoGeneratedAvatar(Archive::AvatarInfo& info, const QString& resource = "");
|
||||||
|
void careAboutAvatar(
|
||||||
|
bool hasAvatar,
|
||||||
|
const Archive::AvatarInfo& info,
|
||||||
|
QMap<QString, QVariant>& output,
|
||||||
|
const QString& resource = "",
|
||||||
|
const QString& subject = ""
|
||||||
|
) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QString name;
|
QString name;
|
||||||
@ -119,5 +129,3 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // CORE_ROSTERITEM_H
|
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "shared/defines.h"
|
||||||
|
|
||||||
int SignalCatcher::sigintFd[2] = {0,0};
|
int SignalCatcher::sigintFd[2] = {0,0};
|
||||||
|
|
||||||
SignalCatcher::SignalCatcher(QCoreApplication *p_app, QObject *parent):
|
SignalCatcher::SignalCatcher(QCoreApplication *p_app, QObject *parent):
|
||||||
@ -28,14 +30,10 @@ SignalCatcher::SignalCatcher(QCoreApplication *p_app, QObject *parent):
|
|||||||
app(p_app)
|
app(p_app)
|
||||||
{
|
{
|
||||||
if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigintFd))
|
if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigintFd))
|
||||||
{
|
|
||||||
qFatal("Couldn't create INT socketpair");
|
qFatal("Couldn't create INT socketpair");
|
||||||
}
|
|
||||||
|
|
||||||
if (setup_unix_signal_handlers() != 0)
|
if (setup_unix_signal_handlers() != 0)
|
||||||
{
|
|
||||||
qFatal("Couldn't install unix handlers");
|
qFatal("Couldn't install unix handlers");
|
||||||
}
|
|
||||||
|
|
||||||
snInt = new QSocketNotifier(sigintFd[1], QSocketNotifier::Read, this);
|
snInt = new QSocketNotifier(sigintFd[1], QSocketNotifier::Read, this);
|
||||||
connect(snInt, &QSocketNotifier::activated, this, &SignalCatcher::handleSigInt);
|
connect(snInt, &QSocketNotifier::activated, this, &SignalCatcher::handleSigInt);
|
||||||
@ -44,25 +42,25 @@ SignalCatcher::SignalCatcher(QCoreApplication *p_app, QObject *parent):
|
|||||||
SignalCatcher::~SignalCatcher()
|
SignalCatcher::~SignalCatcher()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void SignalCatcher::handleSigInt()
|
void SignalCatcher::handleSigInt() {
|
||||||
{
|
|
||||||
snInt->setEnabled(false);
|
snInt->setEnabled(false);
|
||||||
char tmp;
|
char tmp;
|
||||||
ssize_t s = ::read(sigintFd[1], &tmp, sizeof(tmp));
|
ssize_t s = ::read(sigintFd[1], &tmp, sizeof(tmp));
|
||||||
|
SHARED_UNUSED(s);
|
||||||
|
|
||||||
emit interrupt();
|
emit interrupt();
|
||||||
|
|
||||||
snInt->setEnabled(true);
|
snInt->setEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SignalCatcher::intSignalHandler(int unused)
|
void SignalCatcher::intSignalHandler(int unused) {
|
||||||
{
|
|
||||||
char a = 1;
|
char a = 1;
|
||||||
ssize_t s = ::write(sigintFd[0], &a, sizeof(a));
|
ssize_t s = ::write(sigintFd[0], &a, sizeof(a));
|
||||||
|
SHARED_UNUSED(s);
|
||||||
|
SHARED_UNUSED(unused);
|
||||||
}
|
}
|
||||||
|
|
||||||
int SignalCatcher::setup_unix_signal_handlers()
|
int SignalCatcher::setup_unix_signal_handlers() {
|
||||||
{
|
|
||||||
struct sigaction s_int;
|
struct sigaction s_int;
|
||||||
|
|
||||||
s_int.sa_handler = SignalCatcher::intSignalHandler;
|
s_int.sa_handler = SignalCatcher::intSignalHandler;
|
||||||
|
274
core/squawk.cpp
@ -28,9 +28,10 @@ Core::Squawk::Squawk(QObject* parent):
|
|||||||
amap(),
|
amap(),
|
||||||
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
|
||||||
{
|
{
|
||||||
connect(&network, &NetworkAccess::loadFileProgress, this, &Squawk::fileProgress);
|
connect(&network, &NetworkAccess::loadFileProgress, this, &Squawk::fileProgress);
|
||||||
@ -49,8 +50,7 @@ Core::Squawk::Squawk(QObject* parent):
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::Squawk::~Squawk()
|
Core::Squawk::~Squawk() {
|
||||||
{
|
|
||||||
Accounts::const_iterator itr = accounts.begin();
|
Accounts::const_iterator itr = accounts.begin();
|
||||||
Accounts::const_iterator end = accounts.end();
|
Accounts::const_iterator end = accounts.end();
|
||||||
for (; itr != end; ++itr) {
|
for (; itr != end; ++itr) {
|
||||||
@ -58,15 +58,14 @@ Core::Squawk::~Squawk()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::onWalletOpened(bool success)
|
void Core::Squawk::onWalletOpened(bool success) {
|
||||||
{
|
|
||||||
qDebug() << "KWallet opened: " << success;
|
qDebug() << "KWallet opened: " << success;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::stop()
|
void Core::Squawk::stop() {
|
||||||
{
|
|
||||||
qDebug("Stopping squawk core..");
|
qDebug("Stopping squawk core..");
|
||||||
network.stop();
|
network.stop();
|
||||||
|
clientCache.close();
|
||||||
|
|
||||||
if (isInitialized) {
|
if (isInitialized) {
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
@ -108,17 +107,16 @@ void Core::Squawk::stop()
|
|||||||
emit quit();
|
emit quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::start()
|
void Core::Squawk::start() {
|
||||||
{
|
|
||||||
qDebug("Starting squawk core..");
|
qDebug("Starting squawk core..");
|
||||||
|
|
||||||
readSettings();
|
readSettings();
|
||||||
isInitialized = true;
|
isInitialized = true;
|
||||||
network.start();
|
network.start();
|
||||||
|
clientCache.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::newAccountRequest(const QMap<QString, QVariant>& map)
|
void Core::Squawk::newAccountRequest(const QMap<QString, QVariant>& map) {
|
||||||
{
|
|
||||||
QString name = map.value("name").toString();
|
QString name = map.value("name").toString();
|
||||||
QString login = map.value("login").toString();
|
QString login = map.value("login").toString();
|
||||||
QString server = map.value("server").toString();
|
QString server = map.value("server").toString();
|
||||||
@ -177,10 +175,12 @@ void Core::Squawk::addAccount(
|
|||||||
connect(acc, &Account::changeRoomParticipant, this, &Squawk::onAccountChangeRoomPresence);
|
connect(acc, &Account::changeRoomParticipant, this, &Squawk::onAccountChangeRoomPresence);
|
||||||
connect(acc, &Account::removeRoomParticipant, this, &Squawk::onAccountRemoveRoomPresence);
|
connect(acc, &Account::removeRoomParticipant, this, &Squawk::onAccountRemoveRoomPresence);
|
||||||
|
|
||||||
connect(acc, &Account::receivedVCard, this, &Squawk::responseVCard);
|
connect(acc, &Account::infoReady, this, &Squawk::responseInfo);
|
||||||
|
|
||||||
connect(acc, &Account::uploadFileError, this, &Squawk::onAccountUploadFileError);
|
connect(acc, &Account::uploadFileError, this, &Squawk::onAccountUploadFileError);
|
||||||
|
|
||||||
|
connect(acc, &Account::infoDiscovered, this, &Squawk::onAccountInfoDiscovered);
|
||||||
|
|
||||||
QMap<QString, QVariant> map = {
|
QMap<QString, QVariant> map = {
|
||||||
{"login", login},
|
{"login", login},
|
||||||
{"server", server},
|
{"server", server},
|
||||||
@ -200,53 +200,47 @@ void Core::Squawk::addAccount(
|
|||||||
switch (passwordType) {
|
switch (passwordType) {
|
||||||
case Shared::AccountPassword::alwaysAsk:
|
case Shared::AccountPassword::alwaysAsk:
|
||||||
case Shared::AccountPassword::kwallet:
|
case Shared::AccountPassword::kwallet:
|
||||||
if (password == "") {
|
if (password == "")
|
||||||
acc->invalidatePassword();
|
acc->invalidatePassword();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state != Shared::Availability::offline) {
|
if (state != Shared::Availability::offline) {
|
||||||
acc->setAvailability(state);
|
acc->setAvailability(state);
|
||||||
if (acc->getActive()) {
|
if (acc->getActive())
|
||||||
acc->connect();
|
acc->connect();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::changeState(Shared::Availability p_state)
|
void Core::Squawk::changeState(Shared::Availability p_state) {
|
||||||
{
|
|
||||||
if (state != p_state) {
|
if (state != p_state) {
|
||||||
for (std::deque<Account*>::iterator itr = accounts.begin(), end = accounts.end(); itr != end; ++itr) {
|
for (std::deque<Account*>::iterator itr = accounts.begin(), end = accounts.end(); itr != end; ++itr) {
|
||||||
Account* acc = *itr;
|
Account* acc = *itr;
|
||||||
acc->setAvailability(p_state);
|
acc->setAvailability(p_state);
|
||||||
if (state == Shared::Availability::offline && acc->getActive()) {
|
if (state == Shared::Availability::offline && acc->getActive())
|
||||||
acc->connect();
|
acc->connect();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
state = p_state;
|
state = p_state;
|
||||||
|
|
||||||
emit stateChanged(p_state);
|
emit stateChanged(p_state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::connectAccount(const QString& account)
|
void Core::Squawk::connectAccount(const QString& account) {
|
||||||
{
|
|
||||||
AccountsMap::const_iterator itr = amap.find(account);
|
AccountsMap::const_iterator itr = amap.find(account);
|
||||||
if (itr == amap.end()) {
|
if (itr == amap.end()) {
|
||||||
qDebug("An attempt to connect non existing account, skipping");
|
qDebug("An attempt to connect non existing account, skipping");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
itr->second->setActive(true);
|
itr->second->setActive(true);
|
||||||
if (state != Shared::Availability::offline) {
|
if (state != Shared::Availability::offline)
|
||||||
itr->second->connect();
|
itr->second->connect();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::disconnectAccount(const QString& account)
|
void Core::Squawk::disconnectAccount(const QString& account) {
|
||||||
{
|
|
||||||
AccountsMap::const_iterator itr = amap.find(account);
|
AccountsMap::const_iterator itr = amap.find(account);
|
||||||
if (itr == amap.end()) {
|
if (itr == amap.end()) {
|
||||||
qDebug("An attempt to connect non existing account, skipping");
|
qDebug("An attempt to connect non existing account, skipping");
|
||||||
@ -257,13 +251,15 @@ void Core::Squawk::disconnectAccount(const QString& account)
|
|||||||
itr->second->disconnect();
|
itr->second->disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::onAccountConnectionStateChanged(Shared::ConnectionState p_state)
|
void Core::Squawk::onAccountConnectionStateChanged(Shared::ConnectionState p_state) {
|
||||||
{
|
|
||||||
Account* acc = static_cast<Account*>(sender());
|
Account* acc = static_cast<Account*>(sender());
|
||||||
emit changeAccount(acc->getName(), {
|
QMap<QString, QVariant> changes = {
|
||||||
{"state", QVariant::fromValue(p_state)},
|
{"state", QVariant::fromValue(p_state)}
|
||||||
{"error", ""}
|
};
|
||||||
});
|
if (acc->getLastError() == Account::Error::none)
|
||||||
|
changes.insert("error", "");
|
||||||
|
|
||||||
|
emit changeAccount(acc->getName(), changes);
|
||||||
|
|
||||||
#ifdef WITH_KWALLET
|
#ifdef WITH_KWALLET
|
||||||
if (p_state == Shared::ConnectionState::connected) {
|
if (p_state == Shared::ConnectionState::connected) {
|
||||||
@ -274,74 +270,85 @@ void Core::Squawk::onAccountConnectionStateChanged(Shared::ConnectionState p_sta
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::onAccountAddContact(const QString& jid, const QString& group, const QMap<QString, QVariant>& data)
|
void Core::Squawk::onAccountAddContact(const QString& jid, const QString& group, const QMap<QString, QVariant>& data) {
|
||||||
{
|
|
||||||
Account* acc = static_cast<Account*>(sender());
|
Account* acc = static_cast<Account*>(sender());
|
||||||
emit addContact(acc->getName(), jid, group, data);
|
emit addContact(acc->getName(), jid, group, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::onAccountAddGroup(const QString& name)
|
void Core::Squawk::onAccountAddGroup(const QString& name) {
|
||||||
{
|
|
||||||
Account* acc = static_cast<Account*>(sender());
|
Account* acc = static_cast<Account*>(sender());
|
||||||
emit addGroup(acc->getName(), name);
|
emit addGroup(acc->getName(), name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::onAccountRemoveGroup(const QString& name)
|
void Core::Squawk::onAccountRemoveGroup(const QString& name) {
|
||||||
{
|
|
||||||
Account* acc = static_cast<Account*>(sender());
|
Account* acc = static_cast<Account*>(sender());
|
||||||
emit removeGroup(acc->getName(), name);
|
emit removeGroup(acc->getName(), name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::onAccountChangeContact(const QString& jid, const QMap<QString, QVariant>& data)
|
void Core::Squawk::onAccountChangeContact(const QString& jid, const QMap<QString, QVariant>& data) {
|
||||||
{
|
|
||||||
Account* acc = static_cast<Account*>(sender());
|
Account* acc = static_cast<Account*>(sender());
|
||||||
emit changeContact(acc->getName(), jid, data);
|
emit changeContact(acc->getName(), jid, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::onAccountRemoveContact(const QString& jid)
|
void Core::Squawk::onAccountRemoveContact(const QString& jid) {
|
||||||
{
|
|
||||||
Account* acc = static_cast<Account*>(sender());
|
Account* acc = static_cast<Account*>(sender());
|
||||||
emit removeContact(acc->getName(), jid);
|
emit removeContact(acc->getName(), jid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::onAccountRemoveContact(const QString& jid, const QString& group)
|
void Core::Squawk::onAccountRemoveContact(const QString& jid, const QString& group) {
|
||||||
{
|
|
||||||
Account* acc = static_cast<Account*>(sender());
|
Account* acc = static_cast<Account*>(sender());
|
||||||
emit removeContact(acc->getName(), jid, group);
|
emit removeContact(acc->getName(), jid, group);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::onAccountAddPresence(const QString& jid, const QString& name, const QMap<QString, QVariant>& data)
|
void Core::Squawk::onAccountAddPresence(const QString& jid, const QString& name, const QMap<QString, QVariant>& data) {
|
||||||
{
|
|
||||||
Account* acc = static_cast<Account*>(sender());
|
Account* acc = static_cast<Account*>(sender());
|
||||||
emit addPresence(acc->getName(), jid, name, data);
|
emit addPresence(acc->getName(), jid, name, data);
|
||||||
|
|
||||||
|
//it's equal if a MUC sends its status with presence of the same jid (ex: muc@srv.im/muc@srv.im), it's not a client, so, no need to request
|
||||||
|
if (jid != name) {
|
||||||
|
const Shared::ClientId& id = data["client"].value<Shared::ClientId>();
|
||||||
|
if (!id.valid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!clientCache.checkClient(id))
|
||||||
|
acc->discoverInfo(jid + "/" + name, id.getId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::onAccountRemovePresence(const QString& jid, const QString& name)
|
void Core::Squawk::onAccountInfoDiscovered(
|
||||||
|
const QString& address,
|
||||||
|
const QString& node,
|
||||||
|
const std::set<Shared::Identity>& identities,
|
||||||
|
const std::set<QString>& features)
|
||||||
{
|
{
|
||||||
Account* acc = static_cast<Account*>(sender());
|
Account* acc = static_cast<Account*>(sender());
|
||||||
|
|
||||||
|
if (!clientCache.registerClientInfo(address, node, identities, features)) {
|
||||||
|
qDebug() << "Account" << acc->getName() << "received an ill-formed client discovery response from" << address << "about" << node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::Squawk::onAccountRemovePresence(const QString& jid, const QString& name) {
|
||||||
|
Account* acc = static_cast<Account*>(sender());
|
||||||
emit removePresence(acc->getName(), jid, name);
|
emit removePresence(acc->getName(), jid, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::onAccountAvailabilityChanged(Shared::Availability state)
|
void Core::Squawk::onAccountAvailabilityChanged(Shared::Availability state) {
|
||||||
{
|
|
||||||
Account* acc = static_cast<Account*>(sender());
|
Account* acc = static_cast<Account*>(sender());
|
||||||
emit changeAccount(acc->getName(), {{"availability", QVariant::fromValue(state)}});
|
emit changeAccount(acc->getName(), {{"availability", QVariant::fromValue(state)}});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::onAccountChanged(const QMap<QString, QVariant>& data)
|
void Core::Squawk::onAccountChanged(const QMap<QString, QVariant>& data) {
|
||||||
{
|
|
||||||
Account* acc = static_cast<Account*>(sender());
|
Account* acc = static_cast<Account*>(sender());
|
||||||
emit changeAccount(acc->getName(), data);
|
emit changeAccount(acc->getName(), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::onAccountMessage(const Shared::Message& data)
|
void Core::Squawk::onAccountMessage(const Shared::Message& data) {
|
||||||
{
|
|
||||||
Account* acc = static_cast<Account*>(sender());
|
Account* acc = static_cast<Account*>(sender());
|
||||||
emit accountMessage(acc->getName(), data);
|
emit accountMessage(acc->getName(), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::sendMessage(const QString& account, const Shared::Message& data)
|
void Core::Squawk::sendMessage(const QString& account, const Shared::Message& data) {
|
||||||
{
|
|
||||||
AccountsMap::const_iterator itr = amap.find(account);
|
AccountsMap::const_iterator itr = amap.find(account);
|
||||||
if (itr == amap.end()) {
|
if (itr == amap.end()) {
|
||||||
qDebug() << "An attempt to send a message with non existing account" << account << ", skipping";
|
qDebug() << "An attempt to send a message with non existing account" << account << ", skipping";
|
||||||
@ -351,8 +358,7 @@ void Core::Squawk::sendMessage(const QString& account, const Shared::Message& da
|
|||||||
itr->second->sendMessage(data);
|
itr->second->sendMessage(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::replaceMessage(const QString& account, const QString& originalId, const Shared::Message& data)
|
void Core::Squawk::replaceMessage(const QString& account, const QString& originalId, const Shared::Message& data) {
|
||||||
{
|
|
||||||
AccountsMap::const_iterator itr = amap.find(account);
|
AccountsMap::const_iterator itr = amap.find(account);
|
||||||
if (itr == amap.end()) {
|
if (itr == amap.end()) {
|
||||||
qDebug() << "An attempt to replace a message with non existing account" << account << ", skipping";
|
qDebug() << "An attempt to replace a message with non existing account" << account << ", skipping";
|
||||||
@ -362,8 +368,7 @@ void Core::Squawk::replaceMessage(const QString& account, const QString& origina
|
|||||||
itr->second->replaceMessage(originalId, data);
|
itr->second->replaceMessage(originalId, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::resendMessage(const QString& account, const QString& jid, const QString& id)
|
void Core::Squawk::resendMessage(const QString& account, const QString& jid, const QString& id) {
|
||||||
{
|
|
||||||
AccountsMap::const_iterator itr = amap.find(account);
|
AccountsMap::const_iterator itr = amap.find(account);
|
||||||
if (itr == amap.end()) {
|
if (itr == amap.end()) {
|
||||||
qDebug() << "An attempt to resend a message with non existing account" << account << ", skipping";
|
qDebug() << "An attempt to resend a message with non existing account" << account << ", skipping";
|
||||||
@ -373,8 +378,7 @@ void Core::Squawk::resendMessage(const QString& account, const QString& jid, con
|
|||||||
itr->second->resendMessage(jid, id);
|
itr->second->resendMessage(jid, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::requestArchive(const QString& account, const QString& jid, int count, const QString& before)
|
void Core::Squawk::requestArchive(const QString& account, const QString& jid, int count, const QString& before) {
|
||||||
{
|
|
||||||
AccountsMap::const_iterator itr = amap.find(account);
|
AccountsMap::const_iterator itr = amap.find(account);
|
||||||
if (itr == amap.end()) {
|
if (itr == amap.end()) {
|
||||||
qDebug("An attempt to request an archive of non existing account, skipping");
|
qDebug("An attempt to request an archive of non existing account, skipping");
|
||||||
@ -383,14 +387,12 @@ void Core::Squawk::requestArchive(const QString& account, const QString& jid, in
|
|||||||
itr->second->requestArchive(jid, count, before);
|
itr->second->requestArchive(jid, count, before);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::onAccountResponseArchive(const QString& jid, const std::list<Shared::Message>& list, bool last)
|
void Core::Squawk::onAccountResponseArchive(const QString& jid, const std::list<Shared::Message>& list, bool last) {
|
||||||
{
|
|
||||||
Account* acc = static_cast<Account*>(sender());
|
Account* acc = static_cast<Account*>(sender());
|
||||||
emit responseArchive(acc->getName(), jid, list, last);
|
emit responseArchive(acc->getName(), jid, list, last);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::modifyAccountRequest(const QString& name, const QMap<QString, QVariant>& map)
|
void Core::Squawk::modifyAccountRequest(const QString& name, const QMap<QString, QVariant>& map) {
|
||||||
{
|
|
||||||
AccountsMap::const_iterator itr = amap.find(name);
|
AccountsMap::const_iterator itr = amap.find(name);
|
||||||
if (itr == amap.end()) {
|
if (itr == amap.end()) {
|
||||||
qDebug("An attempt to modify non existing account, skipping");
|
qDebug("An attempt to modify non existing account, skipping");
|
||||||
@ -440,29 +442,24 @@ void Core::Squawk::modifyAccountRequest(const QString& name, const QMap<QString,
|
|||||||
}
|
}
|
||||||
|
|
||||||
mItr = map.find("login");
|
mItr = map.find("login");
|
||||||
if (mItr != map.end()) {
|
if (mItr != map.end())
|
||||||
acc->setLogin(mItr->toString());
|
acc->setLogin(mItr->toString());
|
||||||
}
|
|
||||||
|
|
||||||
mItr = map.find("password");
|
mItr = map.find("password");
|
||||||
if (mItr != map.end()) {
|
if (mItr != map.end())
|
||||||
acc->setPassword(mItr->toString());
|
acc->setPassword(mItr->toString());
|
||||||
}
|
|
||||||
|
|
||||||
mItr = map.find("resource");
|
mItr = map.find("resource");
|
||||||
if (mItr != map.end()) {
|
if (mItr != map.end())
|
||||||
acc->setResource(mItr->toString());
|
acc->setResource(mItr->toString());
|
||||||
}
|
|
||||||
|
|
||||||
mItr = map.find("server");
|
mItr = map.find("server");
|
||||||
if (mItr != map.end()) {
|
if (mItr != map.end())
|
||||||
acc->setServer(mItr->toString());
|
acc->setServer(mItr->toString());
|
||||||
}
|
|
||||||
|
|
||||||
mItr = map.find("passwordType");
|
mItr = map.find("passwordType");
|
||||||
if (mItr != map.end()) {
|
if (mItr != map.end())
|
||||||
acc->setPasswordType(Shared::Global::fromInt<Shared::AccountPassword>(mItr->toInt()));
|
acc->setPasswordType(Shared::Global::fromInt<Shared::AccountPassword>(mItr->toInt()));
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef WITH_KWALLET
|
#ifdef WITH_KWALLET
|
||||||
if (acc->getPasswordType() == Shared::AccountPassword::kwallet
|
if (acc->getPasswordType() == Shared::AccountPassword::kwallet
|
||||||
@ -474,28 +471,24 @@ void Core::Squawk::modifyAccountRequest(const QString& name, const QMap<QString,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (state != Shared::Availability::offline) {
|
if (state != Shared::Availability::offline) {
|
||||||
if (activeChanged && acc->getActive()) {
|
if (activeChanged && acc->getActive())
|
||||||
acc->connect();
|
acc->connect();
|
||||||
} else if (!wentReconnecting && acc->getActive() && acc->getLastError() == Account::Error::authentication) {
|
else if (!wentReconnecting && acc->getActive() && acc->getLastError() == Account::Error::authentication)
|
||||||
acc->connect();
|
acc->connect();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
emit changeAccount(name, map);
|
emit changeAccount(name, map);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::onAccountError(const QString& text)
|
void Core::Squawk::onAccountError(const QString& text) {
|
||||||
{
|
|
||||||
Account* acc = static_cast<Account*>(sender());
|
Account* acc = static_cast<Account*>(sender());
|
||||||
emit changeAccount(acc->getName(), {{"error", text}});
|
emit changeAccount(acc->getName(), {{"error", text}});
|
||||||
|
|
||||||
if (acc->getLastError() == Account::Error::authentication) {
|
if (acc->getLastError() == Account::Error::authentication)
|
||||||
emit requestPassword(acc->getName(), true);
|
emit requestPassword(acc->getName(), true);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::removeAccountRequest(const QString& name)
|
void Core::Squawk::removeAccountRequest(const QString& name) {
|
||||||
{
|
|
||||||
AccountsMap::const_iterator itr = amap.find(name);
|
AccountsMap::const_iterator itr = amap.find(name);
|
||||||
if (itr == amap.end()) {
|
if (itr == amap.end()) {
|
||||||
qDebug() << "An attempt to remove non existing account " << name << " from core, skipping";
|
qDebug() << "An attempt to remove non existing account " << name << " from core, skipping";
|
||||||
@ -503,9 +496,8 @@ void Core::Squawk::removeAccountRequest(const QString& name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Account* acc = itr->second;
|
Account* acc = itr->second;
|
||||||
if (acc->getState() != Shared::ConnectionState::disconnected) {
|
if (acc->getState() != Shared::ConnectionState::disconnected)
|
||||||
acc->disconnect();
|
acc->disconnect();
|
||||||
}
|
|
||||||
|
|
||||||
for (Accounts::const_iterator aItr = accounts.begin(); aItr != accounts.end(); ++aItr) {
|
for (Accounts::const_iterator aItr = accounts.begin(); aItr != accounts.end(); ++aItr) {
|
||||||
if (*aItr == acc) {
|
if (*aItr == acc) {
|
||||||
@ -525,8 +517,7 @@ void Core::Squawk::removeAccountRequest(const QString& name)
|
|||||||
acc->deleteLater();
|
acc->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::subscribeContact(const QString& account, const QString& jid, const QString& reason)
|
void Core::Squawk::subscribeContact(const QString& account, const QString& jid, const QString& reason) {
|
||||||
{
|
|
||||||
AccountsMap::const_iterator itr = amap.find(account);
|
AccountsMap::const_iterator itr = amap.find(account);
|
||||||
if (itr == amap.end()) {
|
if (itr == amap.end()) {
|
||||||
qDebug("An attempt to subscribe to the contact with non existing account, skipping");
|
qDebug("An attempt to subscribe to the contact with non existing account, skipping");
|
||||||
@ -536,8 +527,7 @@ void Core::Squawk::subscribeContact(const QString& account, const QString& jid,
|
|||||||
itr->second->subscribeToContact(jid, reason);
|
itr->second->subscribeToContact(jid, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::unsubscribeContact(const QString& account, const QString& jid, const QString& reason)
|
void Core::Squawk::unsubscribeContact(const QString& account, const QString& jid, const QString& reason) {
|
||||||
{
|
|
||||||
AccountsMap::const_iterator itr = amap.find(account);
|
AccountsMap::const_iterator itr = amap.find(account);
|
||||||
if (itr == amap.end()) {
|
if (itr == amap.end()) {
|
||||||
qDebug("An attempt to subscribe to the contact with non existing account, skipping");
|
qDebug("An attempt to subscribe to the contact with non existing account, skipping");
|
||||||
@ -547,8 +537,7 @@ void Core::Squawk::unsubscribeContact(const QString& account, const QString& jid
|
|||||||
itr->second->unsubscribeFromContact(jid, reason);
|
itr->second->unsubscribeFromContact(jid, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::removeContactRequest(const QString& account, const QString& jid)
|
void Core::Squawk::removeContactRequest(const QString& account, const QString& jid) {
|
||||||
{
|
|
||||||
AccountsMap::const_iterator itr = amap.find(account);
|
AccountsMap::const_iterator itr = amap.find(account);
|
||||||
if (itr == amap.end()) {
|
if (itr == amap.end()) {
|
||||||
qDebug("An attempt to remove contact from non existing account, skipping");
|
qDebug("An attempt to remove contact from non existing account, skipping");
|
||||||
@ -558,8 +547,7 @@ void Core::Squawk::removeContactRequest(const QString& account, const QString& j
|
|||||||
itr->second->removeContactRequest(jid);
|
itr->second->removeContactRequest(jid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::addContactRequest(const QString& account, const QString& jid, const QString& name, const QSet<QString>& groups)
|
void Core::Squawk::addContactRequest(const QString& account, const QString& jid, const QString& name, const QSet<QString>& groups) {
|
||||||
{
|
|
||||||
AccountsMap::const_iterator itr = amap.find(account);
|
AccountsMap::const_iterator itr = amap.find(account);
|
||||||
if (itr == amap.end()) {
|
if (itr == amap.end()) {
|
||||||
qDebug("An attempt to add contact to a non existing account, skipping");
|
qDebug("An attempt to add contact to a non existing account, skipping");
|
||||||
@ -569,26 +557,22 @@ void Core::Squawk::addContactRequest(const QString& account, const QString& jid,
|
|||||||
itr->second->addContactRequest(jid, name, groups);
|
itr->second->addContactRequest(jid, name, groups);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::onAccountAddRoom(const QString jid, const QMap<QString, QVariant>& data)
|
void Core::Squawk::onAccountAddRoom(const QString jid, const QMap<QString, QVariant>& data) {
|
||||||
{
|
|
||||||
Account* acc = static_cast<Account*>(sender());
|
Account* acc = static_cast<Account*>(sender());
|
||||||
emit addRoom(acc->getName(), jid, data);
|
emit addRoom(acc->getName(), jid, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::onAccountChangeRoom(const QString jid, const QMap<QString, QVariant>& data)
|
void Core::Squawk::onAccountChangeRoom(const QString jid, const QMap<QString, QVariant>& data) {
|
||||||
{
|
|
||||||
Account* acc = static_cast<Account*>(sender());
|
Account* acc = static_cast<Account*>(sender());
|
||||||
emit changeRoom(acc->getName(), jid, data);
|
emit changeRoom(acc->getName(), jid, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::onAccountRemoveRoom(const QString jid)
|
void Core::Squawk::onAccountRemoveRoom(const QString jid) {
|
||||||
{
|
|
||||||
Account* acc = static_cast<Account*>(sender());
|
Account* acc = static_cast<Account*>(sender());
|
||||||
emit removeRoom(acc->getName(), jid);
|
emit removeRoom(acc->getName(), jid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::setRoomJoined(const QString& account, const QString& jid, bool joined)
|
void Core::Squawk::setRoomJoined(const QString& account, const QString& jid, bool joined) {
|
||||||
{
|
|
||||||
AccountsMap::const_iterator itr = amap.find(account);
|
AccountsMap::const_iterator itr = amap.find(account);
|
||||||
if (itr == amap.end()) {
|
if (itr == amap.end()) {
|
||||||
qDebug() << "An attempt to set jouned to the room" << jid << "of non existing account" << account << ", skipping";
|
qDebug() << "An attempt to set jouned to the room" << jid << "of non existing account" << account << ", skipping";
|
||||||
@ -597,8 +581,7 @@ void Core::Squawk::setRoomJoined(const QString& account, const QString& jid, boo
|
|||||||
itr->second->setRoomJoined(jid, joined);
|
itr->second->setRoomJoined(jid, joined);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::setRoomAutoJoin(const QString& account, const QString& jid, bool joined)
|
void Core::Squawk::setRoomAutoJoin(const QString& account, const QString& jid, bool joined) {
|
||||||
{
|
|
||||||
AccountsMap::const_iterator itr = amap.find(account);
|
AccountsMap::const_iterator itr = amap.find(account);
|
||||||
if (itr == amap.end()) {
|
if (itr == amap.end()) {
|
||||||
qDebug() << "An attempt to set autoJoin to the room" << jid << "of non existing account" << account << ", skipping";
|
qDebug() << "An attempt to set autoJoin to the room" << jid << "of non existing account" << account << ", skipping";
|
||||||
@ -607,32 +590,36 @@ void Core::Squawk::setRoomAutoJoin(const QString& account, const QString& jid, b
|
|||||||
itr->second->setRoomAutoJoin(jid, joined);
|
itr->second->setRoomAutoJoin(jid, joined);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::onAccountAddRoomPresence(const QString& jid, const QString& nick, const QMap<QString, QVariant>& data)
|
void Core::Squawk::setContactEncryption(const QString& account, const QString& jid, Shared::EncryptionProtocol value) {
|
||||||
{
|
AccountsMap::const_iterator itr = amap.find(account);
|
||||||
|
if (itr == amap.end()) {
|
||||||
|
qDebug() << "An attempt to set encryption to the contact" << jid << "of non existing account" << account << ", skipping";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
itr->second->setContactEncryption(jid, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::Squawk::onAccountAddRoomPresence(const QString& jid, const QString& nick, const QMap<QString, QVariant>& data) {
|
||||||
Account* acc = static_cast<Account*>(sender());
|
Account* acc = static_cast<Account*>(sender());
|
||||||
emit addRoomParticipant(acc->getName(), jid, nick, data);
|
emit addRoomParticipant(acc->getName(), jid, nick, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::onAccountChangeRoomPresence(const QString& jid, const QString& nick, const QMap<QString, QVariant>& data)
|
void Core::Squawk::onAccountChangeRoomPresence(const QString& jid, const QString& nick, const QMap<QString, QVariant>& data) {
|
||||||
{
|
|
||||||
Account* acc = static_cast<Account*>(sender());
|
Account* acc = static_cast<Account*>(sender());
|
||||||
emit changeRoomParticipant(acc->getName(), jid, nick, data);
|
emit changeRoomParticipant(acc->getName(), jid, nick, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::onAccountRemoveRoomPresence(const QString& jid, const QString& nick)
|
void Core::Squawk::onAccountRemoveRoomPresence(const QString& jid, const QString& nick) {
|
||||||
{
|
|
||||||
Account* acc = static_cast<Account*>(sender());
|
Account* acc = static_cast<Account*>(sender());
|
||||||
emit removeRoomParticipant(acc->getName(), jid, nick);
|
emit removeRoomParticipant(acc->getName(), jid, nick);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::onAccountChangeMessage(const QString& jid, const QString& id, const QMap<QString, QVariant>& data)
|
void Core::Squawk::onAccountChangeMessage(const QString& jid, const QString& id, const QMap<QString, QVariant>& data) {
|
||||||
{
|
|
||||||
Account* acc = static_cast<Account*>(sender());
|
Account* acc = static_cast<Account*>(sender());
|
||||||
emit changeMessage(acc->getName(), jid, id, data);
|
emit changeMessage(acc->getName(), jid, id, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::removeRoomRequest(const QString& account, const QString& jid)
|
void Core::Squawk::removeRoomRequest(const QString& account, const QString& jid) {
|
||||||
{
|
|
||||||
AccountsMap::const_iterator itr = amap.find(account);
|
AccountsMap::const_iterator itr = amap.find(account);
|
||||||
if (itr == amap.end()) {
|
if (itr == amap.end()) {
|
||||||
qDebug() << "An attempt to remove the room" << jid << "of non existing account" << account << ", skipping";
|
qDebug() << "An attempt to remove the room" << jid << "of non existing account" << account << ", skipping";
|
||||||
@ -641,8 +628,7 @@ void Core::Squawk::removeRoomRequest(const QString& account, const QString& jid)
|
|||||||
itr->second->removeRoomRequest(jid);
|
itr->second->removeRoomRequest(jid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::addRoomRequest(const QString& account, const QString& jid, const QString& nick, const QString& password, bool autoJoin)
|
void Core::Squawk::addRoomRequest(const QString& account, const QString& jid, const QString& nick, const QString& password, bool autoJoin) {
|
||||||
{
|
|
||||||
AccountsMap::const_iterator itr = amap.find(account);
|
AccountsMap::const_iterator itr = amap.find(account);
|
||||||
if (itr == amap.end()) {
|
if (itr == amap.end()) {
|
||||||
qDebug() << "An attempt to add the room" << jid << "to non existing account" << account << ", skipping";
|
qDebug() << "An attempt to add the room" << jid << "to non existing account" << account << ", skipping";
|
||||||
@ -651,13 +637,11 @@ void Core::Squawk::addRoomRequest(const QString& account, const QString& jid, co
|
|||||||
itr->second->addRoomRequest(jid, nick, password, autoJoin);
|
itr->second->addRoomRequest(jid, nick, password, autoJoin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::fileDownloadRequest(const QString& url)
|
void Core::Squawk::fileDownloadRequest(const QString& url) {
|
||||||
{
|
|
||||||
network.downladFile(url);
|
network.downladFile(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::addContactToGroupRequest(const QString& account, const QString& jid, const QString& groupName)
|
void Core::Squawk::addContactToGroupRequest(const QString& account, const QString& jid, const QString& groupName) {
|
||||||
{
|
|
||||||
AccountsMap::const_iterator itr = amap.find(account);
|
AccountsMap::const_iterator itr = amap.find(account);
|
||||||
if (itr == amap.end()) {
|
if (itr == amap.end()) {
|
||||||
qDebug() << "An attempt to add contact" << jid << "of non existing account" << account << "to the group" << groupName << ", skipping";
|
qDebug() << "An attempt to add contact" << jid << "of non existing account" << account << "to the group" << groupName << ", skipping";
|
||||||
@ -666,8 +650,7 @@ void Core::Squawk::addContactToGroupRequest(const QString& account, const QStrin
|
|||||||
itr->second->addContactToGroupRequest(jid, groupName);
|
itr->second->addContactToGroupRequest(jid, groupName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::removeContactFromGroupRequest(const QString& account, const QString& jid, const QString& groupName)
|
void Core::Squawk::removeContactFromGroupRequest(const QString& account, const QString& jid, const QString& groupName) {
|
||||||
{
|
|
||||||
AccountsMap::const_iterator itr = amap.find(account);
|
AccountsMap::const_iterator itr = amap.find(account);
|
||||||
if (itr == amap.end()) {
|
if (itr == amap.end()) {
|
||||||
qDebug() << "An attempt to add contact" << jid << "of non existing account" << account << "to the group" << groupName << ", skipping";
|
qDebug() << "An attempt to add contact" << jid << "of non existing account" << account << "to the group" << groupName << ", skipping";
|
||||||
@ -676,8 +659,7 @@ void Core::Squawk::removeContactFromGroupRequest(const QString& account, const Q
|
|||||||
itr->second->removeContactFromGroupRequest(jid, groupName);
|
itr->second->removeContactFromGroupRequest(jid, groupName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::renameContactRequest(const QString& account, const QString& jid, const QString& newName)
|
void Core::Squawk::renameContactRequest(const QString& account, const QString& jid, const QString& newName) {
|
||||||
{
|
|
||||||
AccountsMap::const_iterator itr = amap.find(account);
|
AccountsMap::const_iterator itr = amap.find(account);
|
||||||
if (itr == amap.end()) {
|
if (itr == amap.end()) {
|
||||||
qDebug() << "An attempt to rename contact" << jid << "of non existing account" << account << ", skipping";
|
qDebug() << "An attempt to rename contact" << jid << "of non existing account" << account << ", skipping";
|
||||||
@ -686,28 +668,25 @@ void Core::Squawk::renameContactRequest(const QString& account, const QString& j
|
|||||||
itr->second->renameContactRequest(jid, newName);
|
itr->second->renameContactRequest(jid, newName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::requestVCard(const QString& account, const QString& jid)
|
void Core::Squawk::requestInfo(const QString& account, const QString& jid) {
|
||||||
{
|
|
||||||
AccountsMap::const_iterator itr = amap.find(account);
|
AccountsMap::const_iterator itr = amap.find(account);
|
||||||
if (itr == amap.end()) {
|
if (itr == amap.end()) {
|
||||||
qDebug() << "An attempt to request" << jid << "vcard of non existing account" << account << ", skipping";
|
qDebug() << "An attempt to request info about" << jid << "of non existing account" << account << ", skipping";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
itr->second->requestVCard(jid);
|
itr->second->requestInfo(jid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::uploadVCard(const QString& account, const Shared::VCard& card)
|
void Core::Squawk::updateInfo(const QString& account, const Shared::Info& info) {
|
||||||
{
|
|
||||||
AccountsMap::const_iterator itr = amap.find(account);
|
AccountsMap::const_iterator itr = amap.find(account);
|
||||||
if (itr == amap.end()) {
|
if (itr == amap.end()) {
|
||||||
qDebug() << "An attempt to upload vcard to non existing account" << account << ", skipping";
|
qDebug() << "An attempt to update info to non existing account" << account << ", skipping";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
itr->second->uploadVCard(card);
|
itr->second->updateInfo(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::readSettings()
|
void Core::Squawk::readSettings() {
|
||||||
{
|
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
settings.beginGroup("core");
|
settings.beginGroup("core");
|
||||||
int size = settings.beginReadArray("accounts");
|
int size = settings.beginReadArray("accounts");
|
||||||
@ -741,8 +720,7 @@ void Core::Squawk::readSettings()
|
|||||||
emit ready();
|
emit ready();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::onAccountNeedPassword()
|
void Core::Squawk::onAccountNeedPassword() {
|
||||||
{
|
|
||||||
Account* acc = static_cast<Account*>(sender());
|
Account* acc = static_cast<Account*>(sender());
|
||||||
switch (acc->getPasswordType()) {
|
switch (acc->getPasswordType()) {
|
||||||
case Shared::AccountPassword::alwaysAsk:
|
case Shared::AccountPassword::alwaysAsk:
|
||||||
@ -765,13 +743,11 @@ void Core::Squawk::onAccountNeedPassword()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::onWalletRejectPassword(const QString& login)
|
void Core::Squawk::onWalletRejectPassword(const QString& login) {
|
||||||
{
|
|
||||||
emit requestPassword(login, false);
|
emit requestPassword(login, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::responsePassword(const QString& account, const QString& password)
|
void Core::Squawk::responsePassword(const QString& account, const QString& password) {
|
||||||
{
|
|
||||||
AccountsMap::const_iterator itr = amap.find(account);
|
AccountsMap::const_iterator itr = amap.find(account);
|
||||||
if (itr == amap.end()) {
|
if (itr == amap.end()) {
|
||||||
qDebug() << "An attempt to set password to non existing account" << account << ", skipping";
|
qDebug() << "An attempt to set password to non existing account" << account << ", skipping";
|
||||||
@ -780,24 +756,19 @@ void Core::Squawk::responsePassword(const QString& account, const QString& passw
|
|||||||
Account* acc = itr->second;
|
Account* acc = itr->second;
|
||||||
acc->setPassword(password);
|
acc->setPassword(password);
|
||||||
emit changeAccount(account, {{"password", password}});
|
emit changeAccount(account, {{"password", password}});
|
||||||
if (state != Shared::Availability::offline && acc->getActive()) {
|
if (state != Shared::Availability::offline && acc->getActive())
|
||||||
acc->connect();
|
acc->connect();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::onAccountUploadFileError(const QString& jid, const QString id, const QString& errorText)
|
void Core::Squawk::onAccountUploadFileError(const QString& jid, const QString id, const QString& errorText) {
|
||||||
{
|
|
||||||
Account* acc = static_cast<Account*>(sender());
|
Account* acc = static_cast<Account*>(sender());
|
||||||
emit fileError({{acc->getName(), jid, id}}, errorText, true);
|
emit fileError({{acc->getName(), jid, id}}, errorText, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::onLocalPathInvalid(const QString& path)
|
void Core::Squawk::onLocalPathInvalid(const QString& path) {
|
||||||
{
|
|
||||||
std::list<Shared::MessageInfo> list = network.reportPathInvalid(path);
|
std::list<Shared::MessageInfo> list = network.reportPathInvalid(path);
|
||||||
|
|
||||||
QMap<QString, QVariant> data({
|
QMap<QString, QVariant> data({{"attachPath", ""}});
|
||||||
{"attachPath", ""}
|
|
||||||
});
|
|
||||||
for (const Shared::MessageInfo& info : list) {
|
for (const Shared::MessageInfo& info : list) {
|
||||||
AccountsMap::const_iterator itr = amap.find(info.account);
|
AccountsMap::const_iterator itr = amap.find(info.account);
|
||||||
if (itr != amap.end()) {
|
if (itr != amap.end()) {
|
||||||
@ -808,8 +779,7 @@ void Core::Squawk::onLocalPathInvalid(const QString& path)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Squawk::changeDownloadsPath(const QString& path)
|
void Core::Squawk::changeDownloadsPath(const QString& path) {
|
||||||
{
|
|
||||||
network.moveFilesDirectory(path);
|
network.moveFilesDirectory(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,9 +31,13 @@
|
|||||||
#include "shared/enums.h"
|
#include "shared/enums.h"
|
||||||
#include "shared/message.h"
|
#include "shared/message.h"
|
||||||
#include "shared/global.h"
|
#include "shared/global.h"
|
||||||
#include "networkaccess.h"
|
#include "shared/info.h"
|
||||||
|
#include "shared/clientinfo.h"
|
||||||
#include "external/simpleCrypt/simplecrypt.h"
|
#include "external/simpleCrypt/simplecrypt.h"
|
||||||
|
|
||||||
|
#include <core/components/clientcache.h>
|
||||||
|
#include <core/components/networkaccess.h>
|
||||||
|
|
||||||
#ifdef WITH_KWALLET
|
#ifdef WITH_KWALLET
|
||||||
#include "passwordStorageEngines/kwallet.h"
|
#include "passwordStorageEngines/kwallet.h"
|
||||||
#endif
|
#endif
|
||||||
@ -84,7 +88,7 @@ signals:
|
|||||||
void fileDownloadComplete(const std::list<Shared::MessageInfo> msgs, const QString& path);
|
void fileDownloadComplete(const std::list<Shared::MessageInfo> msgs, const QString& path);
|
||||||
void fileUploadComplete(const std::list<Shared::MessageInfo> msgs, const QString& url, const QString& path);
|
void fileUploadComplete(const std::list<Shared::MessageInfo> msgs, const QString& url, const QString& path);
|
||||||
|
|
||||||
void responseVCard(const QString& jid, const Shared::VCard& card);
|
void responseInfo(const Shared::Info& info);
|
||||||
void changeMessage(const QString& account, const QString& jid, const QString& id, const QMap<QString, QVariant>& data);
|
void changeMessage(const QString& account, const QString& jid, const QString& id, const QMap<QString, QVariant>& data);
|
||||||
void requestPassword(const QString& account, bool authernticationError);
|
void requestPassword(const QString& account, bool authernticationError);
|
||||||
|
|
||||||
@ -112,6 +116,7 @@ public slots:
|
|||||||
void removeContactRequest(const QString& account, const QString& jid);
|
void removeContactRequest(const QString& account, const QString& jid);
|
||||||
void renameContactRequest(const QString& account, const QString& jid, const QString& newName);
|
void renameContactRequest(const QString& account, const QString& jid, const QString& newName);
|
||||||
void addContactRequest(const QString& account, const QString& jid, const QString& name, const QSet<QString>& groups);
|
void addContactRequest(const QString& account, const QString& jid, const QString& name, const QSet<QString>& groups);
|
||||||
|
void setContactEncryption(const QString& account, const QString& jid, Shared::EncryptionProtocol value);
|
||||||
|
|
||||||
void setRoomJoined(const QString& account, const QString& jid, bool joined);
|
void setRoomJoined(const QString& account, const QString& jid, bool joined);
|
||||||
void setRoomAutoJoin(const QString& account, const QString& jid, bool joined);
|
void setRoomAutoJoin(const QString& account, const QString& jid, bool joined);
|
||||||
@ -120,8 +125,8 @@ public slots:
|
|||||||
|
|
||||||
void fileDownloadRequest(const QString& url);
|
void fileDownloadRequest(const QString& url);
|
||||||
|
|
||||||
void requestVCard(const QString& account, const QString& jid);
|
void requestInfo(const QString& account, const QString& jid);
|
||||||
void uploadVCard(const QString& account, const Shared::VCard& card);
|
void updateInfo(const QString& account, const Shared::Info& info);
|
||||||
void responsePassword(const QString& account, const QString& password);
|
void responsePassword(const QString& account, const QString& password);
|
||||||
void onLocalPathInvalid(const QString& path);
|
void onLocalPathInvalid(const QString& path);
|
||||||
void changeDownloadsPath(const QString& path);
|
void changeDownloadsPath(const QString& path);
|
||||||
@ -135,6 +140,7 @@ 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;
|
||||||
@ -179,17 +185,10 @@ private slots:
|
|||||||
void onWalletOpened(bool success);
|
void onWalletOpened(bool success);
|
||||||
void onWalletRejectPassword(const QString& login);
|
void onWalletRejectPassword(const QString& login);
|
||||||
|
|
||||||
|
void onAccountInfoDiscovered(const QString& address, const QString& node, const std::set<Shared::Identity>& identities, const std::set<QString>& features);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void readSettings();
|
void readSettings();
|
||||||
void parseAccount(
|
|
||||||
const QString& login,
|
|
||||||
const QString& server,
|
|
||||||
const QString& password,
|
|
||||||
const QString& name,
|
|
||||||
const QString& resource,
|
|
||||||
bool active,
|
|
||||||
Shared::AccountPassword passwordType
|
|
||||||
);
|
|
||||||
|
|
||||||
static const quint64 passwordHash = 0x08d054225ac4871d;
|
static const quint64 passwordHash = 0x08d054225ac4871d;
|
||||||
};
|
};
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
target_sources(squawk PRIVATE
|
|
||||||
archive.cpp
|
|
||||||
archive.h
|
|
||||||
storage.cpp
|
|
||||||
storage.h
|
|
||||||
urlstorage.cpp
|
|
||||||
urlstorage.h
|
|
||||||
)
|
|
@ -1,197 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef CORE_ARCHIVE_H
|
|
||||||
#define CORE_ARCHIVE_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QCryptographicHash>
|
|
||||||
#include <QMimeDatabase>
|
|
||||||
#include <QMimeType>
|
|
||||||
|
|
||||||
#include "shared/message.h"
|
|
||||||
#include "shared/exception.h"
|
|
||||||
#include <lmdb.h>
|
|
||||||
#include <list>
|
|
||||||
|
|
||||||
namespace Core {
|
|
||||||
|
|
||||||
class Archive : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
class AvatarInfo;
|
|
||||||
|
|
||||||
Archive(const QString& jid, QObject* parent = 0);
|
|
||||||
~Archive();
|
|
||||||
|
|
||||||
void open(const QString& account);
|
|
||||||
void close();
|
|
||||||
|
|
||||||
bool addElement(const Shared::Message& message);
|
|
||||||
unsigned int addElements(const std::list<Shared::Message>& messages);
|
|
||||||
Shared::Message getElement(const QString& id) const;
|
|
||||||
bool hasElement(const QString& id) const;
|
|
||||||
void changeMessage(const QString& id, const QMap<QString, QVariant>& data);
|
|
||||||
Shared::Message oldest();
|
|
||||||
QString oldestId();
|
|
||||||
Shared::Message newest();
|
|
||||||
QString newestId();
|
|
||||||
void clear();
|
|
||||||
long unsigned int size() const;
|
|
||||||
std::list<Shared::Message> getBefore(int count, const QString& id);
|
|
||||||
bool isFromTheBeginning();
|
|
||||||
void setFromTheBeginning(bool is);
|
|
||||||
bool setAvatar(const QByteArray& data, AvatarInfo& info, bool generated = false, const QString& resource = "");
|
|
||||||
AvatarInfo getAvatarInfo(const QString& resource = "") const;
|
|
||||||
bool readAvatarInfo(AvatarInfo& target, const QString& resource = "") const;
|
|
||||||
void readAllResourcesAvatars(std::map<QString, AvatarInfo>& data) const;
|
|
||||||
QString idByStanzaId(const QString& stanzaId) const;
|
|
||||||
QString stanzaIdById(const QString& id) const;
|
|
||||||
|
|
||||||
public:
|
|
||||||
const QString jid;
|
|
||||||
|
|
||||||
public:
|
|
||||||
class Directory:
|
|
||||||
public Utils::Exception
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Directory(const std::string& p_path):Exception(), path(p_path){}
|
|
||||||
|
|
||||||
std::string getMessage() const{return "Can't create directory for database at " + path;}
|
|
||||||
private:
|
|
||||||
std::string path;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Closed:
|
|
||||||
public Utils::Exception
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Closed(const std::string& op, const std::string& acc):Exception(), operation(op), account(acc){}
|
|
||||||
|
|
||||||
std::string getMessage() const{return "An attempt to perform operation " + operation + " on closed archive for " + account;}
|
|
||||||
private:
|
|
||||||
std::string operation;
|
|
||||||
std::string account;
|
|
||||||
};
|
|
||||||
|
|
||||||
class NotFound:
|
|
||||||
public Utils::Exception
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
NotFound(const std::string& k, const std::string& acc):Exception(), key(k), account(acc){}
|
|
||||||
|
|
||||||
std::string getMessage() const{return "Element for id " + key + " wasn't found in database " + account;}
|
|
||||||
private:
|
|
||||||
std::string key;
|
|
||||||
std::string account;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Empty:
|
|
||||||
public Utils::Exception
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Empty(const std::string& acc):Exception(), account(acc){}
|
|
||||||
|
|
||||||
std::string getMessage() const{return "An attempt to read ordered elements from database " + account + " but it's empty";}
|
|
||||||
private:
|
|
||||||
std::string account;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Exist:
|
|
||||||
public Utils::Exception
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Exist(const std::string& acc, const std::string& p_key):Exception(), account(acc), key(p_key){}
|
|
||||||
|
|
||||||
std::string getMessage() const{return "An attempt to insert element " + key + " to database " + account + " but it already has an element with given id";}
|
|
||||||
private:
|
|
||||||
std::string account;
|
|
||||||
std::string key;
|
|
||||||
};
|
|
||||||
|
|
||||||
class NoAvatar:
|
|
||||||
public Utils::Exception
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
NoAvatar(const std::string& el, const std::string& res):Exception(), element(el), resource(res){
|
|
||||||
if (resource.size() == 0) {
|
|
||||||
resource = "for himself";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string getMessage() const{return "Element " + element + " has no avatar for " + resource ;}
|
|
||||||
private:
|
|
||||||
std::string element;
|
|
||||||
std::string resource;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Unknown:
|
|
||||||
public Utils::Exception
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Unknown(const std::string& acc, const std::string& message):Exception(), account(acc), msg(message){}
|
|
||||||
|
|
||||||
std::string getMessage() const{return "Unknown error on database " + account + ": " + msg;}
|
|
||||||
private:
|
|
||||||
std::string account;
|
|
||||||
std::string msg;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class AvatarInfo {
|
|
||||||
public:
|
|
||||||
AvatarInfo();
|
|
||||||
AvatarInfo(const QString& type, const QByteArray& hash, bool autogenerated);
|
|
||||||
|
|
||||||
void deserialize(char* pointer, uint32_t size);
|
|
||||||
void serialize(QByteArray* ba) const;
|
|
||||||
|
|
||||||
QString type;
|
|
||||||
QByteArray hash;
|
|
||||||
bool autogenerated;
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool opened;
|
|
||||||
bool fromTheBeginning;
|
|
||||||
MDB_env* environment;
|
|
||||||
MDB_dbi main; //id to message
|
|
||||||
MDB_dbi order; //time to id
|
|
||||||
MDB_dbi stats;
|
|
||||||
MDB_dbi avatars;
|
|
||||||
MDB_dbi sid; //stanzaId to id
|
|
||||||
|
|
||||||
bool getStatBoolValue(const std::string& id, MDB_txn* txn);
|
|
||||||
std::string getStatStringValue(const std::string& id, MDB_txn* txn);
|
|
||||||
|
|
||||||
bool setStatValue(const std::string& id, bool value, MDB_txn* txn);
|
|
||||||
bool setStatValue(const std::string& id, const std::string& value, MDB_txn* txn);
|
|
||||||
bool readAvatarInfo(AvatarInfo& target, const std::string& res, MDB_txn* txn) const;
|
|
||||||
void printOrder();
|
|
||||||
void printKeys();
|
|
||||||
bool dropAvatar(const std::string& resource);
|
|
||||||
Shared::Message getMessage(const std::string& id, MDB_txn* txn) const;
|
|
||||||
Shared::Message getStoredMessage(MDB_txn *txn, MDB_cursor* cursor, MDB_cursor_op op, MDB_val* key, MDB_val* value, int& rc);
|
|
||||||
Shared::Message edge(bool end);
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // CORE_ARCHIVE_H
|
|
@ -1,184 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 <QStandardPaths>
|
|
||||||
#include <QDir>
|
|
||||||
|
|
||||||
#include "storage.h"
|
|
||||||
|
|
||||||
Core::Storage::Storage(const QString& p_name):
|
|
||||||
name(p_name),
|
|
||||||
opened(false),
|
|
||||||
environment(),
|
|
||||||
base()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Core::Storage::~Storage()
|
|
||||||
{
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::Storage::open()
|
|
||||||
{
|
|
||||||
if (!opened) {
|
|
||||||
mdb_env_create(&environment);
|
|
||||||
QString path(QStandardPaths::writableLocation(QStandardPaths::CacheLocation));
|
|
||||||
path += "/" + name;
|
|
||||||
QDir cache(path);
|
|
||||||
|
|
||||||
if (!cache.exists()) {
|
|
||||||
bool res = cache.mkpath(path);
|
|
||||||
if (!res) {
|
|
||||||
throw Archive::Directory(path.toStdString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mdb_env_set_maxdbs(environment, 1);
|
|
||||||
mdb_env_set_mapsize(environment, 10UL * 1024UL * 1024UL);
|
|
||||||
mdb_env_open(environment, path.toStdString().c_str(), 0, 0664);
|
|
||||||
|
|
||||||
MDB_txn *txn;
|
|
||||||
mdb_txn_begin(environment, NULL, 0, &txn);
|
|
||||||
mdb_dbi_open(txn, "base", MDB_CREATE, &base);
|
|
||||||
mdb_txn_commit(txn);
|
|
||||||
opened = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::Storage::close()
|
|
||||||
{
|
|
||||||
if (opened) {
|
|
||||||
mdb_dbi_close(environment, base);
|
|
||||||
mdb_env_close(environment);
|
|
||||||
opened = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::Storage::addRecord(const QString& key, const QString& value)
|
|
||||||
{
|
|
||||||
if (!opened) {
|
|
||||||
throw Archive::Closed("addRecord", name.toStdString());
|
|
||||||
}
|
|
||||||
const std::string& id = key.toStdString();
|
|
||||||
const std::string& val = value.toStdString();
|
|
||||||
|
|
||||||
MDB_val lmdbKey, lmdbData;
|
|
||||||
lmdbKey.mv_size = id.size();
|
|
||||||
lmdbKey.mv_data = (char*)id.c_str();
|
|
||||||
lmdbData.mv_size = val.size();
|
|
||||||
lmdbData.mv_data = (char*)val.c_str();
|
|
||||||
MDB_txn *txn;
|
|
||||||
mdb_txn_begin(environment, NULL, 0, &txn);
|
|
||||||
int rc;
|
|
||||||
rc = mdb_put(txn, base, &lmdbKey, &lmdbData, MDB_NOOVERWRITE);
|
|
||||||
if (rc != 0) {
|
|
||||||
mdb_txn_abort(txn);
|
|
||||||
if (rc == MDB_KEYEXIST) {
|
|
||||||
throw Archive::Exist(name.toStdString(), id);
|
|
||||||
} else {
|
|
||||||
throw Archive::Unknown(name.toStdString(), mdb_strerror(rc));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mdb_txn_commit(txn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::Storage::changeRecord(const QString& key, const QString& value)
|
|
||||||
{
|
|
||||||
if (!opened) {
|
|
||||||
throw Archive::Closed("changeRecord", name.toStdString());
|
|
||||||
}
|
|
||||||
const std::string& id = key.toStdString();
|
|
||||||
const std::string& val = value.toStdString();
|
|
||||||
|
|
||||||
MDB_val lmdbKey, lmdbData;
|
|
||||||
lmdbKey.mv_size = id.size();
|
|
||||||
lmdbKey.mv_data = (char*)id.c_str();
|
|
||||||
lmdbData.mv_size = val.size();
|
|
||||||
lmdbData.mv_data = (char*)val.c_str();
|
|
||||||
MDB_txn *txn;
|
|
||||||
mdb_txn_begin(environment, NULL, 0, &txn);
|
|
||||||
int rc;
|
|
||||||
rc = mdb_put(txn, base, &lmdbKey, &lmdbData, 0);
|
|
||||||
if (rc != 0) {
|
|
||||||
mdb_txn_abort(txn);
|
|
||||||
if (rc) {
|
|
||||||
throw Archive::Unknown(name.toStdString(), mdb_strerror(rc));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mdb_txn_commit(txn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QString Core::Storage::getRecord(const QString& key) const
|
|
||||||
{
|
|
||||||
if (!opened) {
|
|
||||||
throw Archive::Closed("addElement", name.toStdString());
|
|
||||||
}
|
|
||||||
const std::string& id = key.toStdString();
|
|
||||||
|
|
||||||
MDB_val lmdbKey, lmdbData;
|
|
||||||
lmdbKey.mv_size = id.size();
|
|
||||||
lmdbKey.mv_data = (char*)id.c_str();
|
|
||||||
|
|
||||||
MDB_txn *txn;
|
|
||||||
int rc;
|
|
||||||
mdb_txn_begin(environment, NULL, MDB_RDONLY, &txn);
|
|
||||||
rc = mdb_get(txn, base, &lmdbKey, &lmdbData);
|
|
||||||
if (rc) {
|
|
||||||
mdb_txn_abort(txn);
|
|
||||||
if (rc == MDB_NOTFOUND) {
|
|
||||||
throw Archive::NotFound(id, name.toStdString());
|
|
||||||
} else {
|
|
||||||
throw Archive::Unknown(name.toStdString(), mdb_strerror(rc));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
std::string sId((char*)lmdbData.mv_data, lmdbData.mv_size);
|
|
||||||
QString value(sId.c_str());
|
|
||||||
mdb_txn_abort(txn);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::Storage::removeRecord(const QString& key)
|
|
||||||
{
|
|
||||||
if (!opened) {
|
|
||||||
throw Archive::Closed("addElement", name.toStdString());
|
|
||||||
}
|
|
||||||
const std::string& id = key.toStdString();
|
|
||||||
|
|
||||||
MDB_val lmdbKey;
|
|
||||||
lmdbKey.mv_size = id.size();
|
|
||||||
lmdbKey.mv_data = (char*)id.c_str();
|
|
||||||
|
|
||||||
MDB_txn *txn;
|
|
||||||
int rc;
|
|
||||||
mdb_txn_begin(environment, NULL, 0, &txn);
|
|
||||||
rc = mdb_del(txn, base, &lmdbKey, NULL);
|
|
||||||
if (rc) {
|
|
||||||
mdb_txn_abort(txn);
|
|
||||||
if (rc == MDB_NOTFOUND) {
|
|
||||||
throw Archive::NotFound(id, name.toStdString());
|
|
||||||
} else {
|
|
||||||
throw Archive::Unknown(name.toStdString(), mdb_strerror(rc));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mdb_txn_commit(txn);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,491 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 <QStandardPaths>
|
|
||||||
#include <QDir>
|
|
||||||
#include <QDebug>
|
|
||||||
|
|
||||||
#include "urlstorage.h"
|
|
||||||
|
|
||||||
Core::UrlStorage::UrlStorage(const QString& p_name):
|
|
||||||
name(p_name),
|
|
||||||
opened(false),
|
|
||||||
environment(),
|
|
||||||
base(),
|
|
||||||
map()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Core::UrlStorage::~UrlStorage()
|
|
||||||
{
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::UrlStorage::open()
|
|
||||||
{
|
|
||||||
if (!opened) {
|
|
||||||
mdb_env_create(&environment);
|
|
||||||
QString path(QStandardPaths::writableLocation(QStandardPaths::CacheLocation));
|
|
||||||
path += "/" + name;
|
|
||||||
QDir cache(path);
|
|
||||||
|
|
||||||
if (!cache.exists()) {
|
|
||||||
bool res = cache.mkpath(path);
|
|
||||||
if (!res) {
|
|
||||||
throw Archive::Directory(path.toStdString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mdb_env_set_maxdbs(environment, 2);
|
|
||||||
mdb_env_set_mapsize(environment, 10UL * 1024UL * 1024UL);
|
|
||||||
mdb_env_open(environment, path.toStdString().c_str(), 0, 0664);
|
|
||||||
|
|
||||||
MDB_txn *txn;
|
|
||||||
mdb_txn_begin(environment, NULL, 0, &txn);
|
|
||||||
mdb_dbi_open(txn, "base", MDB_CREATE, &base);
|
|
||||||
mdb_dbi_open(txn, "map", MDB_CREATE, &map);
|
|
||||||
mdb_txn_commit(txn);
|
|
||||||
opened = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::UrlStorage::close()
|
|
||||||
{
|
|
||||||
if (opened) {
|
|
||||||
mdb_dbi_close(environment, map);
|
|
||||||
mdb_dbi_close(environment, base);
|
|
||||||
mdb_env_close(environment);
|
|
||||||
opened = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::UrlStorage::writeInfo(const QString& key, const Core::UrlStorage::UrlInfo& info, bool overwrite)
|
|
||||||
{
|
|
||||||
MDB_txn *txn;
|
|
||||||
mdb_txn_begin(environment, NULL, 0, &txn);
|
|
||||||
|
|
||||||
try {
|
|
||||||
writeInfo(key, info, txn, overwrite);
|
|
||||||
mdb_txn_commit(txn);
|
|
||||||
} catch (...) {
|
|
||||||
mdb_txn_abort(txn);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::UrlStorage::writeInfo(const QString& key, const Core::UrlStorage::UrlInfo& info, MDB_txn* txn, bool overwrite)
|
|
||||||
{
|
|
||||||
QByteArray ba;
|
|
||||||
QDataStream ds(&ba, QIODevice::WriteOnly);
|
|
||||||
info.serialize(ds);
|
|
||||||
|
|
||||||
const std::string& id = key.toStdString();
|
|
||||||
MDB_val lmdbKey, lmdbData;
|
|
||||||
lmdbKey.mv_size = id.size();
|
|
||||||
lmdbKey.mv_data = (char*)id.c_str();
|
|
||||||
lmdbData.mv_size = ba.size();
|
|
||||||
lmdbData.mv_data = (uint8_t*)ba.data();
|
|
||||||
|
|
||||||
int rc;
|
|
||||||
rc = mdb_put(txn, base, &lmdbKey, &lmdbData, overwrite ? 0 : MDB_NOOVERWRITE);
|
|
||||||
|
|
||||||
if (rc != 0) {
|
|
||||||
if (rc == MDB_KEYEXIST) {
|
|
||||||
if (!overwrite) {
|
|
||||||
throw Archive::Exist(name.toStdString(), id);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw Archive::Unknown(name.toStdString(), mdb_strerror(rc));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info.hasPath()) {
|
|
||||||
std::string sp = info.getPath().toStdString();
|
|
||||||
lmdbData.mv_size = sp.size();
|
|
||||||
lmdbData.mv_data = (char*)sp.c_str();
|
|
||||||
rc = mdb_put(txn, map, &lmdbData, &lmdbKey, 0);
|
|
||||||
if (rc != 0) {
|
|
||||||
throw Archive::Unknown(name.toStdString(), mdb_strerror(rc));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::UrlStorage::readInfo(const QString& key, Core::UrlStorage::UrlInfo& info, MDB_txn* txn)
|
|
||||||
{
|
|
||||||
const std::string& id = key.toStdString();
|
|
||||||
MDB_val lmdbKey, lmdbData;
|
|
||||||
lmdbKey.mv_size = id.size();
|
|
||||||
lmdbKey.mv_data = (char*)id.c_str();
|
|
||||||
int rc = mdb_get(txn, base, &lmdbKey, &lmdbData);
|
|
||||||
|
|
||||||
if (rc == 0) {
|
|
||||||
QByteArray ba((char*)lmdbData.mv_data, lmdbData.mv_size);
|
|
||||||
QDataStream ds(&ba, QIODevice::ReadOnly);
|
|
||||||
|
|
||||||
info.deserialize(ds);
|
|
||||||
} else if (rc == MDB_NOTFOUND) {
|
|
||||||
throw Archive::NotFound(id, name.toStdString());
|
|
||||||
} else {
|
|
||||||
throw Archive::Unknown(name.toStdString(), mdb_strerror(rc));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::UrlStorage::readInfo(const QString& key, Core::UrlStorage::UrlInfo& info)
|
|
||||||
{
|
|
||||||
MDB_txn *txn;
|
|
||||||
mdb_txn_begin(environment, NULL, MDB_RDONLY, &txn);
|
|
||||||
|
|
||||||
try {
|
|
||||||
readInfo(key, info, txn);
|
|
||||||
mdb_txn_commit(txn);
|
|
||||||
} catch (...) {
|
|
||||||
mdb_txn_abort(txn);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::UrlStorage::addFile(const QString& url)
|
|
||||||
{
|
|
||||||
if (!opened) {
|
|
||||||
throw Archive::Closed("addFile(no message, no path)", name.toStdString());
|
|
||||||
}
|
|
||||||
|
|
||||||
addToInfo(url, "", "", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::UrlStorage::addFile(const QString& url, const QString& path)
|
|
||||||
{
|
|
||||||
if (!opened) {
|
|
||||||
throw Archive::Closed("addFile(no message, with path)", name.toStdString());
|
|
||||||
}
|
|
||||||
|
|
||||||
addToInfo(url, "", "", "", path);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::UrlStorage::addFile(const QString& url, const QString& account, const QString& jid, const QString& id)
|
|
||||||
{
|
|
||||||
if (!opened) {
|
|
||||||
throw Archive::Closed("addFile(with message, no path)", name.toStdString());
|
|
||||||
}
|
|
||||||
|
|
||||||
addToInfo(url, account, jid, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::UrlStorage::addFile(const QString& url, const QString& path, const QString& account, const QString& jid, const QString& id)
|
|
||||||
{
|
|
||||||
if (!opened) {
|
|
||||||
throw Archive::Closed("addFile(with message, with path)", name.toStdString());
|
|
||||||
}
|
|
||||||
|
|
||||||
addToInfo(url, account, jid, id, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::UrlStorage::addFile(const std::list<Shared::MessageInfo>& msgs, const QString& url, const QString& path)
|
|
||||||
{
|
|
||||||
if (!opened) {
|
|
||||||
throw Archive::Closed("addFile(with list)", name.toStdString());
|
|
||||||
}
|
|
||||||
|
|
||||||
UrlInfo info (path, msgs);
|
|
||||||
writeInfo(url, info, true);;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString Core::UrlStorage::addMessageAndCheckForPath(const QString& url, const QString& account, const QString& jid, const QString& id)
|
|
||||||
{
|
|
||||||
if (!opened) {
|
|
||||||
throw Archive::Closed("addMessageAndCheckForPath", name.toStdString());
|
|
||||||
}
|
|
||||||
|
|
||||||
return addToInfo(url, account, jid, id).getPath();
|
|
||||||
}
|
|
||||||
|
|
||||||
Core::UrlStorage::UrlInfo Core::UrlStorage::addToInfo(const QString& url, const QString& account, const QString& jid, const QString& id, const QString& path)
|
|
||||||
{
|
|
||||||
UrlInfo info;
|
|
||||||
MDB_txn *txn;
|
|
||||||
mdb_txn_begin(environment, NULL, 0, &txn);
|
|
||||||
|
|
||||||
try {
|
|
||||||
readInfo(url, info, txn);
|
|
||||||
} catch (const Archive::NotFound& e) {
|
|
||||||
|
|
||||||
} catch (...) {
|
|
||||||
mdb_txn_abort(txn);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pathChange = false;
|
|
||||||
bool listChange = false;
|
|
||||||
if (path != "-s") {
|
|
||||||
if (info.getPath() != path) {
|
|
||||||
info.setPath(path);
|
|
||||||
pathChange = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (account.size() > 0 && jid.size() > 0 && id.size() > 0) {
|
|
||||||
listChange = info.addMessage(account, jid, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pathChange || listChange) {
|
|
||||||
try {
|
|
||||||
writeInfo(url, info, txn, true);
|
|
||||||
mdb_txn_commit(txn);
|
|
||||||
} catch (...) {
|
|
||||||
mdb_txn_abort(txn);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mdb_txn_abort(txn);
|
|
||||||
}
|
|
||||||
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::list<Shared::MessageInfo> Core::UrlStorage::setPath(const QString& url, const QString& path)
|
|
||||||
{
|
|
||||||
std::list<Shared::MessageInfo> list;
|
|
||||||
|
|
||||||
MDB_txn *txn;
|
|
||||||
mdb_txn_begin(environment, NULL, 0, &txn);
|
|
||||||
UrlInfo info;
|
|
||||||
|
|
||||||
try {
|
|
||||||
readInfo(url, info, txn);
|
|
||||||
info.getMessages(list);
|
|
||||||
} catch (const Archive::NotFound& e) {
|
|
||||||
} catch (...) {
|
|
||||||
mdb_txn_abort(txn);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
info.setPath(path);
|
|
||||||
try {
|
|
||||||
writeInfo(url, info, txn, true);
|
|
||||||
mdb_txn_commit(txn);
|
|
||||||
} catch (...) {
|
|
||||||
mdb_txn_abort(txn);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::list<Shared::MessageInfo> Core::UrlStorage::removeFile(const QString& url)
|
|
||||||
{
|
|
||||||
std::list<Shared::MessageInfo> list;
|
|
||||||
|
|
||||||
MDB_txn *txn;
|
|
||||||
mdb_txn_begin(environment, NULL, 0, &txn);
|
|
||||||
UrlInfo info;
|
|
||||||
|
|
||||||
try {
|
|
||||||
std::string id = url.toStdString();
|
|
||||||
readInfo(url, info, txn);
|
|
||||||
info.getMessages(list);
|
|
||||||
|
|
||||||
MDB_val lmdbKey;
|
|
||||||
lmdbKey.mv_size = id.size();
|
|
||||||
lmdbKey.mv_data = (char*)id.c_str();
|
|
||||||
int rc = mdb_del(txn, base, &lmdbKey, NULL);
|
|
||||||
if (rc != 0) {
|
|
||||||
throw Archive::Unknown(name.toStdString(), mdb_strerror(rc));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info.hasPath()) {
|
|
||||||
std::string path = info.getPath().toStdString();
|
|
||||||
lmdbKey.mv_size = path.size();
|
|
||||||
lmdbKey.mv_data = (char*)path.c_str();
|
|
||||||
|
|
||||||
int rc = mdb_del(txn, map, &lmdbKey, NULL);
|
|
||||||
if (rc != 0) {
|
|
||||||
throw Archive::Unknown(name.toStdString(), mdb_strerror(rc));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mdb_txn_commit(txn);
|
|
||||||
} catch (...) {
|
|
||||||
mdb_txn_abort(txn);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::list<Shared::MessageInfo> Core::UrlStorage::deletedFile(const QString& path)
|
|
||||||
{
|
|
||||||
std::list<Shared::MessageInfo> list;
|
|
||||||
|
|
||||||
MDB_txn *txn;
|
|
||||||
mdb_txn_begin(environment, NULL, 0, &txn);
|
|
||||||
|
|
||||||
try {
|
|
||||||
std::string spath = path.toStdString();
|
|
||||||
|
|
||||||
MDB_val lmdbKey, lmdbData;
|
|
||||||
lmdbKey.mv_size = spath.size();
|
|
||||||
lmdbKey.mv_data = (char*)spath.c_str();
|
|
||||||
|
|
||||||
QString url;
|
|
||||||
int rc = mdb_get(txn, map, &lmdbKey, &lmdbData);
|
|
||||||
|
|
||||||
if (rc == 0) {
|
|
||||||
std::string surl((char*)lmdbData.mv_data, lmdbData.mv_size);
|
|
||||||
url = QString(surl.c_str());
|
|
||||||
} else if (rc == MDB_NOTFOUND) {
|
|
||||||
qDebug() << "Have been asked to remove file" << path << ", which isn't in the database, skipping";
|
|
||||||
mdb_txn_abort(txn);
|
|
||||||
return list;
|
|
||||||
} else {
|
|
||||||
throw Archive::Unknown(name.toStdString(), mdb_strerror(rc));
|
|
||||||
}
|
|
||||||
|
|
||||||
UrlInfo info;
|
|
||||||
std::string id = url.toStdString();
|
|
||||||
readInfo(url, info, txn);
|
|
||||||
info.getMessages(list);
|
|
||||||
info.setPath(QString());
|
|
||||||
writeInfo(url, info, txn, true);
|
|
||||||
|
|
||||||
rc = mdb_del(txn, map, &lmdbKey, NULL);
|
|
||||||
if (rc != 0) {
|
|
||||||
throw Archive::Unknown(name.toStdString(), mdb_strerror(rc));
|
|
||||||
}
|
|
||||||
|
|
||||||
mdb_txn_commit(txn);
|
|
||||||
} catch (...) {
|
|
||||||
mdb_txn_abort(txn);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
QString Core::UrlStorage::getUrl(const QString& path)
|
|
||||||
{
|
|
||||||
std::list<Shared::MessageInfo> list;
|
|
||||||
|
|
||||||
MDB_txn *txn;
|
|
||||||
mdb_txn_begin(environment, NULL, MDB_RDONLY, &txn);
|
|
||||||
|
|
||||||
std::string spath = path.toStdString();
|
|
||||||
|
|
||||||
MDB_val lmdbKey, lmdbData;
|
|
||||||
lmdbKey.mv_size = spath.size();
|
|
||||||
lmdbKey.mv_data = (char*)spath.c_str();
|
|
||||||
|
|
||||||
QString url;
|
|
||||||
int rc = mdb_get(txn, map, &lmdbKey, &lmdbData);
|
|
||||||
|
|
||||||
if (rc == 0) {
|
|
||||||
std::string surl((char*)lmdbData.mv_data, lmdbData.mv_size);
|
|
||||||
url = QString(surl.c_str());
|
|
||||||
|
|
||||||
mdb_txn_abort(txn);
|
|
||||||
return url;
|
|
||||||
} else if (rc == MDB_NOTFOUND) {
|
|
||||||
mdb_txn_abort(txn);
|
|
||||||
throw Archive::NotFound(spath, name.toStdString());
|
|
||||||
} else {
|
|
||||||
mdb_txn_abort(txn);
|
|
||||||
throw Archive::Unknown(name.toStdString(), mdb_strerror(rc));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<QString, std::list<Shared::MessageInfo>> Core::UrlStorage::getPath(const QString& url)
|
|
||||||
{
|
|
||||||
UrlInfo info;
|
|
||||||
readInfo(url, info);
|
|
||||||
std::list<Shared::MessageInfo> container;
|
|
||||||
info.getMessages(container);
|
|
||||||
return std::make_pair(info.getPath(), container);
|
|
||||||
}
|
|
||||||
|
|
||||||
Core::UrlStorage::UrlInfo::UrlInfo():
|
|
||||||
localPath(),
|
|
||||||
messages() {}
|
|
||||||
|
|
||||||
Core::UrlStorage::UrlInfo::UrlInfo(const QString& path):
|
|
||||||
localPath(path),
|
|
||||||
messages() {}
|
|
||||||
|
|
||||||
Core::UrlStorage::UrlInfo::UrlInfo(const QString& path, const std::list<Shared::MessageInfo>& msgs):
|
|
||||||
localPath(path),
|
|
||||||
messages(msgs) {}
|
|
||||||
|
|
||||||
Core::UrlStorage::UrlInfo::~UrlInfo() {}
|
|
||||||
|
|
||||||
bool Core::UrlStorage::UrlInfo::addMessage(const QString& acc, const QString& jid, const QString& id)
|
|
||||||
{
|
|
||||||
for (const Shared::MessageInfo& info : messages) {
|
|
||||||
if (info.account == acc && info.jid == jid && info.messageId == id) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
messages.emplace_back(acc, jid, id);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::UrlStorage::UrlInfo::serialize(QDataStream& data) const
|
|
||||||
{
|
|
||||||
data << localPath;
|
|
||||||
std::list<Shared::MessageInfo>::size_type size = messages.size();
|
|
||||||
data << quint32(size);
|
|
||||||
for (const Shared::MessageInfo& info : messages) {
|
|
||||||
data << info.account;
|
|
||||||
data << info.jid;
|
|
||||||
data << info.messageId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::UrlStorage::UrlInfo::deserialize(QDataStream& data)
|
|
||||||
{
|
|
||||||
data >> localPath;
|
|
||||||
quint32 size;
|
|
||||||
data >> size;
|
|
||||||
for (quint32 i = 0; i < size; ++i) {
|
|
||||||
messages.emplace_back();
|
|
||||||
Shared::MessageInfo& info = messages.back();
|
|
||||||
data >> info.account;
|
|
||||||
data >> info.jid;
|
|
||||||
data >> info.messageId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::UrlStorage::UrlInfo::getMessages(std::list<Shared::MessageInfo>& container) const
|
|
||||||
{
|
|
||||||
for (const Shared::MessageInfo& info : messages) {
|
|
||||||
container.emplace_back(info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QString Core::UrlStorage::UrlInfo::getPath() const
|
|
||||||
{
|
|
||||||
return localPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Core::UrlStorage::UrlInfo::hasPath() const
|
|
||||||
{
|
|
||||||
return localPath.size() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Core::UrlStorage::UrlInfo::setPath(const QString& path)
|
|
||||||
{
|
|
||||||
localPath = path;
|
|
||||||
}
|
|
1
external/lmdbal
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit d62eddc47edbec9f8c071459e045578f61ab58df
|
2
external/qxmpp
vendored
@ -1 +1 @@
|
|||||||
Subproject commit fe83e9c3d42c3becf682e2b5ecfc9d77b24c614f
|
Subproject commit 0cd7379bd78aa01af7e84f2fad6269ef0c0ba49c
|
2
external/simpleCrypt/CMakeLists.txt
vendored
@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.0)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
project(simplecrypt LANGUAGES CXX)
|
project(simplecrypt LANGUAGES CXX)
|
||||||
|
|
||||||
set(CMAKE_AUTOMOC ON)
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
@ -1,7 +1,14 @@
|
|||||||
target_sources(squawk PRIVATE
|
set(SOURCE_FILES
|
||||||
main.cpp
|
main.cpp
|
||||||
application.cpp
|
application.cpp
|
||||||
application.h
|
|
||||||
dialogqueue.cpp
|
dialogqueue.cpp
|
||||||
dialogqueue.h
|
root.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set(HEADER_FILES
|
||||||
|
application.h
|
||||||
|
dialogqueue.h
|
||||||
|
root.h
|
||||||
|
)
|
||||||
|
|
||||||
|
target_sources(squawk PRIVATE ${SOURCE_FILES})
|
||||||
|
@ -50,6 +50,7 @@ Application::Application(Core::Squawk* p_core):
|
|||||||
connect(this, &Application::replaceMessage, core, &Core::Squawk::replaceMessage);
|
connect(this, &Application::replaceMessage, core, &Core::Squawk::replaceMessage);
|
||||||
connect(this, &Application::sendMessage, core, &Core::Squawk::sendMessage);
|
connect(this, &Application::sendMessage, core, &Core::Squawk::sendMessage);
|
||||||
connect(this, &Application::resendMessage, core, &Core::Squawk::resendMessage);
|
connect(this, &Application::resendMessage, core, &Core::Squawk::resendMessage);
|
||||||
|
connect(this, &Application::setEncryption, core, &Core::Squawk::setContactEncryption);
|
||||||
connect(&roster, &Models::Roster::requestArchive,
|
connect(&roster, &Models::Roster::requestArchive,
|
||||||
std::bind(&Core::Squawk::requestArchive, core, std::placeholders::_1, std::placeholders::_2, 20, std::placeholders::_3));
|
std::bind(&Core::Squawk::requestArchive, core, std::placeholders::_1, std::placeholders::_2, 20, std::placeholders::_3));
|
||||||
|
|
||||||
@ -120,8 +121,7 @@ Application::Application(Core::Squawk* p_core):
|
|||||||
|
|
||||||
Application::~Application() {}
|
Application::~Application() {}
|
||||||
|
|
||||||
void Application::quit()
|
void Application::quit() {
|
||||||
{
|
|
||||||
if (!nowQuitting) {
|
if (!nowQuitting) {
|
||||||
nowQuitting = true;
|
nowQuitting = true;
|
||||||
emit quitting();
|
emit quitting();
|
||||||
@ -135,32 +135,27 @@ void Application::quit()
|
|||||||
conversations.clear();
|
conversations.clear();
|
||||||
dialogueQueue.quit();
|
dialogueQueue.quit();
|
||||||
|
|
||||||
if (squawk != nullptr) {
|
if (squawk != nullptr)
|
||||||
squawk->close();
|
squawk->close();
|
||||||
}
|
|
||||||
|
|
||||||
if (trayIcon != nullptr) {
|
if (trayIcon != nullptr) {
|
||||||
trayIcon->deleteLater();
|
trayIcon->deleteLater();
|
||||||
trayIcon = nullptr;
|
trayIcon = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!destroyingSquawk) {
|
if (!destroyingSquawk)
|
||||||
checkForTheLastWindow();
|
checkForTheLastWindow();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::checkForTheLastWindow()
|
void Application::checkForTheLastWindow() {
|
||||||
{
|
if (QApplication::topLevelWidgets().size() > 0)
|
||||||
if (QApplication::topLevelWidgets().size() > 0) {
|
|
||||||
emit readyToQuit();
|
emit readyToQuit();
|
||||||
} else {
|
else
|
||||||
connect(qApp, &QApplication::lastWindowClosed, this, &Application::readyToQuit);
|
connect(qApp, &QApplication::lastWindowClosed, this, &Application::readyToQuit);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::createMainWindow()
|
void Application::createMainWindow() {
|
||||||
{
|
|
||||||
if (squawk == nullptr) {
|
if (squawk == nullptr) {
|
||||||
squawk = new Squawk(roster);
|
squawk = new Squawk(roster);
|
||||||
|
|
||||||
@ -188,11 +183,11 @@ void Application::createMainWindow()
|
|||||||
connect(squawk, &Squawk::addContactToGroupRequest, core, &Core::Squawk::addContactToGroupRequest);
|
connect(squawk, &Squawk::addContactToGroupRequest, core, &Core::Squawk::addContactToGroupRequest);
|
||||||
connect(squawk, &Squawk::removeContactFromGroupRequest, core, &Core::Squawk::removeContactFromGroupRequest);
|
connect(squawk, &Squawk::removeContactFromGroupRequest, core, &Core::Squawk::removeContactFromGroupRequest);
|
||||||
connect(squawk, &Squawk::renameContactRequest, core, &Core::Squawk::renameContactRequest);
|
connect(squawk, &Squawk::renameContactRequest, core, &Core::Squawk::renameContactRequest);
|
||||||
connect(squawk, &Squawk::requestVCard, core, &Core::Squawk::requestVCard);
|
connect(squawk, &Squawk::requestInfo, core, &Core::Squawk::requestInfo);
|
||||||
connect(squawk, &Squawk::uploadVCard, core, &Core::Squawk::uploadVCard);
|
connect(squawk, &Squawk::updateInfo, core, &Core::Squawk::updateInfo);
|
||||||
connect(squawk, &Squawk::changeDownloadsPath, core, &Core::Squawk::changeDownloadsPath);
|
connect(squawk, &Squawk::changeDownloadsPath, core, &Core::Squawk::changeDownloadsPath);
|
||||||
|
|
||||||
connect(core, &Core::Squawk::responseVCard, squawk, &Squawk::responseVCard);
|
connect(core, &Core::Squawk::responseInfo, squawk, &Squawk::responseInfo);
|
||||||
|
|
||||||
dialogueQueue.setParentWidnow(squawk);
|
dialogueQueue.setParentWidnow(squawk);
|
||||||
squawk->stateChanged(availability);
|
squawk->stateChanged(availability);
|
||||||
@ -202,22 +197,20 @@ void Application::createMainWindow()
|
|||||||
|
|
||||||
for (const std::list<QString>& entry : expandedPaths) {
|
for (const std::list<QString>& entry : expandedPaths) {
|
||||||
QModelIndex ind = roster.getIndexByPath(entry);
|
QModelIndex ind = roster.getIndexByPath(entry);
|
||||||
if (ind.isValid()) {
|
if (ind.isValid())
|
||||||
squawk->expand(ind);
|
squawk->expand(ind);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
connect(squawk, &Squawk::itemExpanded, this, &Application::onItemExpanded);
|
connect(squawk, &Squawk::itemExpanded, this, &Application::onItemExpanded);
|
||||||
connect(squawk, &Squawk::itemCollapsed, this, &Application::onItemCollapsed);
|
connect(squawk, &Squawk::itemCollapsed, this, &Application::onItemCollapsed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::onSquawkClosing()
|
void Application::onSquawkClosing() {
|
||||||
{
|
|
||||||
dialogueQueue.setParentWidnow(nullptr);
|
dialogueQueue.setParentWidnow(nullptr);
|
||||||
|
|
||||||
if (!nowQuitting) {
|
if (!nowQuitting) {
|
||||||
disconnect(core, &Core::Squawk::responseVCard, squawk, &Squawk::responseVCard);
|
disconnect(core, &Core::Squawk::responseInfo, squawk, &Squawk::responseInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
destroyingSquawk = true;
|
destroyingSquawk = true;
|
||||||
@ -237,18 +230,15 @@ void Application::onSquawkClosing()
|
|||||||
|
|
||||||
void Application::onSquawkDestroyed() {
|
void Application::onSquawkDestroyed() {
|
||||||
destroyingSquawk = false;
|
destroyingSquawk = false;
|
||||||
if (nowQuitting) {
|
if (nowQuitting)
|
||||||
checkForTheLastWindow();
|
checkForTheLastWindow();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::onChangeTray(bool enabled, bool hide)
|
void Application::onChangeTray(bool enabled, bool hide) {
|
||||||
{
|
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
if (trayIcon == nullptr) {
|
if (trayIcon == nullptr) {
|
||||||
if (!hide || squawk == nullptr) {
|
if (!hide || squawk == nullptr)
|
||||||
createTrayIcon();
|
createTrayIcon();
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (hide && squawk != nullptr) {
|
if (hide && squawk != nullptr) {
|
||||||
trayIcon->deleteLater();
|
trayIcon->deleteLater();
|
||||||
@ -261,8 +251,7 @@ void Application::onChangeTray(bool enabled, bool hide)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::createTrayIcon()
|
void Application::createTrayIcon() {
|
||||||
{
|
|
||||||
trayIcon = new QSystemTrayIcon();
|
trayIcon = new QSystemTrayIcon();
|
||||||
|
|
||||||
QMenu* trayIconMenu = new QMenu();
|
QMenu* trayIconMenu = new QMenu();
|
||||||
@ -279,8 +268,7 @@ void Application::createTrayIcon()
|
|||||||
trayIcon->show();
|
trayIcon->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::trayClicked(QSystemTrayIcon::ActivationReason reason)
|
void Application::trayClicked(QSystemTrayIcon::ActivationReason reason) {
|
||||||
{
|
|
||||||
switch (reason) {
|
switch (reason) {
|
||||||
case QSystemTrayIcon::Trigger:
|
case QSystemTrayIcon::Trigger:
|
||||||
case QSystemTrayIcon::DoubleClick:
|
case QSystemTrayIcon::DoubleClick:
|
||||||
@ -292,8 +280,7 @@ void Application::trayClicked(QSystemTrayIcon::ActivationReason reason)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::toggleSquawk()
|
void Application::toggleSquawk() {
|
||||||
{
|
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
if (squawk == nullptr) {
|
if (squawk == nullptr) {
|
||||||
createMainWindow();
|
createMainWindow();
|
||||||
@ -308,34 +295,27 @@ void Application::toggleSquawk()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::onItemCollapsed(const QModelIndex& index)
|
void Application::onItemCollapsed(const QModelIndex& index) {
|
||||||
{
|
|
||||||
std::list<QString> address = roster.getItemPath(index);
|
std::list<QString> address = roster.getItemPath(index);
|
||||||
if (address.size() > 0) {
|
if (address.size() > 0)
|
||||||
expandedPaths.erase(address);
|
expandedPaths.erase(address);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::onItemExpanded(const QModelIndex& index)
|
void Application::onItemExpanded(const QModelIndex& index) {
|
||||||
{
|
|
||||||
std::list<QString> address = roster.getItemPath(index);
|
std::list<QString> address = roster.getItemPath(index);
|
||||||
if (address.size() > 0) {
|
if (address.size() > 0)
|
||||||
expandedPaths.insert(address);
|
expandedPaths.insert(address);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::onAddedElement(const std::list<QString>& path)
|
void Application::onAddedElement(const std::list<QString>& path) {
|
||||||
{
|
|
||||||
if (squawk != nullptr && expandedPaths.count(path) > 0) {
|
if (squawk != nullptr && expandedPaths.count(path) > 0) {
|
||||||
QModelIndex index = roster.getIndexByPath(path);
|
QModelIndex index = roster.getIndexByPath(path);
|
||||||
if (index.isValid()) {
|
if (index.isValid())
|
||||||
squawk->expand(index);
|
squawk->expand(index);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::notify(const QString& account, const Shared::Message& msg)
|
void Application::notify(const QString& account, const Shared::Message& msg) {
|
||||||
{
|
|
||||||
QString jid = msg.getPenPalJid();
|
QString jid = msg.getPenPalJid();
|
||||||
QString name = QString(roster.getContactName(account, jid));
|
QString name = QString(roster.getContactName(account, jid));
|
||||||
QString path = QString(roster.getContactIconPath(account, jid, msg.getPenPalResource()));
|
QString path = QString(roster.getContactIconPath(account, jid, msg.getPenPalResource()));
|
||||||
@ -344,16 +324,15 @@ void Application::notify(const QString& account, const Shared::Message& msg)
|
|||||||
|
|
||||||
uint32_t notificationId = qHash(msg.getId());
|
uint32_t notificationId = qHash(msg.getId());
|
||||||
args << notificationId;
|
args << notificationId;
|
||||||
if (path.size() > 0) {
|
if (path.size() > 0)
|
||||||
args << path;
|
args << path;
|
||||||
} else {
|
else
|
||||||
args << QString("mail-message"); //TODO should here better be unknown user icon?
|
args << QString("mail-message"); //TODO should here better be unknown user icon?
|
||||||
}
|
|
||||||
if (msg.getType() == Shared::Message::groupChat) {
|
if (msg.getType() == Shared::Message::groupChat)
|
||||||
args << msg.getFromResource() + tr(" from ") + name;
|
args << msg.getFromResource() + tr(" from ") + name;
|
||||||
} else {
|
else
|
||||||
args << name;
|
args << name;
|
||||||
}
|
|
||||||
|
|
||||||
QString body(msg.getBody());
|
QString body(msg.getBody());
|
||||||
QString oob(msg.getOutOfBandUrl());
|
QString oob(msg.getOutOfBandUrl());
|
||||||
@ -378,13 +357,11 @@ void Application::notify(const QString& account, const Shared::Message& msg)
|
|||||||
|
|
||||||
storage.insert(std::make_pair(notificationId, std::make_pair(Models::Roster::ElId(account, name), msg.getId())));
|
storage.insert(std::make_pair(notificationId, std::make_pair(Models::Roster::ElId(account, name), msg.getId())));
|
||||||
|
|
||||||
if (squawk != nullptr) {
|
if (squawk != nullptr)
|
||||||
QApplication::alert(squawk);
|
QApplication::alert(squawk);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::onNotificationClosed(quint32 id, quint32 reason)
|
void Application::onNotificationClosed(quint32 id, quint32 reason) {
|
||||||
{
|
|
||||||
Notifications::const_iterator itr = storage.find(id);
|
Notifications::const_iterator itr = storage.find(id);
|
||||||
if (itr != storage.end()) {
|
if (itr != storage.end()) {
|
||||||
if (reason == 2) { //dissmissed by user (https://specifications.freedesktop.org/notification-spec/latest/ar01s09.html)
|
if (reason == 2) { //dissmissed by user (https://specifications.freedesktop.org/notification-spec/latest/ar01s09.html)
|
||||||
@ -397,21 +374,18 @@ void Application::onNotificationClosed(quint32 id, quint32 reason)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::onNotificationInvoked(quint32 id, const QString& action)
|
void Application::onNotificationInvoked(quint32 id, const QString& action) {
|
||||||
{
|
|
||||||
qDebug() << "Notification" << id << action << "request";
|
qDebug() << "Notification" << id << action << "request";
|
||||||
Notifications::const_iterator itr = storage.find(id);
|
Notifications::const_iterator itr = storage.find(id);
|
||||||
if (itr != storage.end()) {
|
if (itr != storage.end()) {
|
||||||
if (action == "markAsRead") {
|
if (action == "markAsRead")
|
||||||
roster.markMessageAsRead(itr->second.first, itr->second.second);
|
roster.markMessageAsRead(itr->second.first, itr->second.second);
|
||||||
} else if (action == "openConversation") {
|
else if (action == "openConversation")
|
||||||
focusConversation(itr->second.first, "", itr->second.second);
|
focusConversation(itr->second.first, "", itr->second.second);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::unreadMessagesCountChanged(int count)
|
void Application::unreadMessagesCountChanged(int count) {
|
||||||
{
|
|
||||||
QDBusMessage signal = QDBusMessage::createSignal("/", "com.canonical.Unity.LauncherEntry", "Update");
|
QDBusMessage signal = QDBusMessage::createSignal("/", "com.canonical.Unity.LauncherEntry", "Update");
|
||||||
signal << qApp->desktopFileName() + QLatin1String(".desktop");
|
signal << qApp->desktopFileName() + QLatin1String(".desktop");
|
||||||
signal << QVariantMap ({
|
signal << QVariantMap ({
|
||||||
@ -421,54 +395,49 @@ void Application::unreadMessagesCountChanged(int count)
|
|||||||
QDBusConnection::sessionBus().send(signal);
|
QDBusConnection::sessionBus().send(signal);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::focusConversation(const Models::Roster::ElId& id, const QString& resource, const QString& messageId)
|
void Application::focusConversation(const Models::Roster::ElId& id, const QString& resource, const QString& messageId) {
|
||||||
{
|
|
||||||
if (squawk != nullptr) {
|
if (squawk != nullptr) {
|
||||||
if (squawk->currentConversationId() != id) {
|
if (squawk->currentConversationId() != id) {
|
||||||
QModelIndex index = roster.getContactIndex(id.account, id.name, resource);
|
QModelIndex index = roster.getContactIndex(id.account, id.name, resource);
|
||||||
squawk->select(index);
|
squawk->select(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (squawk->isMinimized()) {
|
if (squawk->isMinimized())
|
||||||
squawk->showNormal();
|
squawk->showNormal();
|
||||||
} else {
|
else
|
||||||
squawk->show();
|
squawk->show();
|
||||||
}
|
|
||||||
squawk->raise();
|
squawk->raise();
|
||||||
squawk->activateWindow();
|
squawk->activateWindow();
|
||||||
} else {
|
} else {
|
||||||
openConversation(id, resource);
|
openConversation(id, resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SHARED_UNUSED(messageId);
|
||||||
//TODO focus messageId;
|
//TODO focus messageId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::setState(Shared::Availability p_availability)
|
void Application::setState(Shared::Availability p_availability) {
|
||||||
{
|
|
||||||
if (availability != p_availability) {
|
if (availability != p_availability) {
|
||||||
availability = p_availability;
|
availability = p_availability;
|
||||||
emit changeState(availability);
|
emit changeState(availability);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::stateChanged(Shared::Availability state)
|
void Application::stateChanged(Shared::Availability state) {
|
||||||
{
|
|
||||||
availability = state;
|
availability = state;
|
||||||
if (squawk != nullptr) {
|
if (squawk != nullptr)
|
||||||
squawk->stateChanged(state);
|
squawk->stateChanged(state);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::readSettings()
|
void Application::readSettings() {
|
||||||
{
|
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
settings.beginGroup("ui");
|
settings.beginGroup("ui");
|
||||||
int avail;
|
int avail;
|
||||||
if (settings.contains("availability")) {
|
if (settings.contains("availability"))
|
||||||
avail = settings.value("availability").toInt();
|
avail = settings.value("availability").toInt();
|
||||||
} else {
|
else
|
||||||
avail = static_cast<int>(Shared::Availability::online);
|
avail = static_cast<int>(Shared::Availability::online);
|
||||||
}
|
|
||||||
|
|
||||||
settings.beginGroup("roster");
|
settings.beginGroup("roster");
|
||||||
QStringList entries = settings.allKeys();
|
QStringList entries = settings.allKeys();
|
||||||
@ -486,13 +455,11 @@ void Application::readSettings()
|
|||||||
setState(Shared::Global::fromInt<Shared::Availability>(avail));
|
setState(Shared::Global::fromInt<Shared::Availability>(avail));
|
||||||
createMainWindow();
|
createMainWindow();
|
||||||
|
|
||||||
if (settings.value("tray", false).toBool() && !settings.value("hideTray", false).toBool()) {
|
if (settings.value("tray", false).toBool() && !settings.value("hideTray", false).toBool())
|
||||||
createTrayIcon();
|
createTrayIcon();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::writeSettings()
|
void Application::writeSettings() {
|
||||||
{
|
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
settings.beginGroup("ui");
|
settings.beginGroup("ui");
|
||||||
settings.setValue("availability", static_cast<int>(availability));
|
settings.setValue("availability", static_cast<int>(availability));
|
||||||
@ -501,9 +468,9 @@ void Application::writeSettings()
|
|||||||
settings.beginGroup("roster");
|
settings.beginGroup("roster");
|
||||||
for (const std::list<QString>& address : expandedPaths) {
|
for (const std::list<QString>& address : expandedPaths) {
|
||||||
QString path = "";
|
QString path = "";
|
||||||
for (const QString& hop : address) {
|
for (const QString& hop : address)
|
||||||
path += hop + "/";
|
path += hop + "/";
|
||||||
}
|
|
||||||
path += "expanded";
|
path += "expanded";
|
||||||
settings.setValue(path, true);
|
settings.setValue(path, true);
|
||||||
}
|
}
|
||||||
@ -513,63 +480,58 @@ void Application::writeSettings()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Application::requestPassword(const QString& account, bool authenticationError) {
|
void Application::requestPassword(const QString& account, bool authenticationError) {
|
||||||
if (authenticationError) {
|
if (authenticationError)
|
||||||
dialogueQueue.addAction(account, DialogQueue::askCredentials);
|
dialogueQueue.addAction(account, DialogQueue::askCredentials);
|
||||||
} else {
|
else
|
||||||
dialogueQueue.addAction(account, DialogQueue::askPassword);
|
dialogueQueue.addAction(account, DialogQueue::askPassword);
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
void Application::onConversationClosed()
|
|
||||||
{
|
void Application::onConversationClosed() {
|
||||||
Conversation* conv = static_cast<Conversation*>(sender());
|
Conversation* conv = static_cast<Conversation*>(sender());
|
||||||
Models::Roster::ElId id(conv->getAccount(), conv->getJid());
|
Models::Roster::ElId id(conv->getAccount(), conv->getJid());
|
||||||
Conversations::const_iterator itr = conversations.find(id);
|
Conversations::const_iterator itr = conversations.find(id);
|
||||||
if (itr != conversations.end()) {
|
if (itr != conversations.end())
|
||||||
conversations.erase(itr);
|
conversations.erase(itr);
|
||||||
}
|
|
||||||
if (conv->isMuc) {
|
if (conv->isMuc) {
|
||||||
Room* room = static_cast<Room*>(conv);
|
Room* room = static_cast<Room*>(conv);
|
||||||
if (!room->autoJoined()) {
|
if (!room->autoJoined())
|
||||||
emit setRoomJoined(id.account, id.name, false);
|
emit setRoomJoined(id.account, id.name, false);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::changeSubscription(const Models::Roster::ElId& id, bool subscribe)
|
void Application::changeSubscription(const Models::Roster::ElId& id, bool subscribe) {
|
||||||
{
|
|
||||||
Models::Item::Type type = roster.getContactType(id);
|
Models::Item::Type type = roster.getContactType(id);
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Models::Item::contact:
|
case Models::Item::contact:
|
||||||
if (subscribe) {
|
if (subscribe)
|
||||||
emit subscribeContact(id.account, id.name, "");
|
emit subscribeContact(id.account, id.name, "");
|
||||||
} else {
|
else
|
||||||
emit unsubscribeContact(id.account, id.name, "");
|
emit unsubscribeContact(id.account, id.name, "");
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case Models::Item::room:
|
case Models::Item::room:
|
||||||
setRoomAutoJoin(id.account, id.name, subscribe);
|
setRoomAutoJoin(id.account, id.name, subscribe);
|
||||||
if (!isConverstationOpened(id)) {
|
if (!isConverstationOpened(id))
|
||||||
emit setRoomJoined(id.account, id.name, subscribe);
|
emit setRoomJoined(id.account, id.name, subscribe);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::subscribeConversation(Conversation* conv)
|
void Application::subscribeConversation(Conversation* conv) {
|
||||||
{
|
|
||||||
connect(conv, &Conversation::destroyed, this, &Application::onConversationClosed);
|
connect(conv, &Conversation::destroyed, this, &Application::onConversationClosed);
|
||||||
connect(conv, &Conversation::sendMessage, this, &Application::onConversationMessage);
|
connect(conv, &Conversation::sendMessage, this, &Application::onConversationMessage);
|
||||||
connect(conv, &Conversation::replaceMessage, this, &Application::onConversationReplaceMessage);
|
connect(conv, &Conversation::replaceMessage, this, &Application::onConversationReplaceMessage);
|
||||||
connect(conv, &Conversation::resendMessage, this, &Application::onConversationResend);
|
connect(conv, &Conversation::resendMessage, this, &Application::onConversationResend);
|
||||||
|
connect(conv, &Conversation::setEncryption, this, &Application::onConversationSetEncryption);
|
||||||
connect(conv, &Conversation::notifyableMessage, this, &Application::notify);
|
connect(conv, &Conversation::notifyableMessage, this, &Application::notify);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::openConversation(const Models::Roster::ElId& id, const QString& resource)
|
void Application::openConversation(const Models::Roster::ElId& id, const QString& resource) {
|
||||||
{
|
|
||||||
Conversations::const_iterator itr = conversations.find(id);
|
Conversations::const_iterator itr = conversations.find(id);
|
||||||
Models::Account* acc = roster.getAccount(id.account);
|
Models::Account* acc = roster.getAccount(id.account);
|
||||||
Conversation* conv = nullptr;
|
Conversation* conv = nullptr;
|
||||||
@ -583,9 +545,8 @@ void Application::openConversation(const Models::Roster::ElId& id, const QString
|
|||||||
created = true;
|
created = true;
|
||||||
Models::Room* room = static_cast<Models::Room*>(el);
|
Models::Room* room = static_cast<Models::Room*>(el);
|
||||||
conv = new Room(acc, room);
|
conv = new Room(acc, room);
|
||||||
if (!room->getJoined()) {
|
if (!room->getJoined())
|
||||||
emit setRoomJoined(id.account, id.name, true);
|
emit setRoomJoined(id.account, id.name, true);
|
||||||
}
|
|
||||||
} else if (el->type == Models::Item::contact) {
|
} else if (el->type == Models::Item::contact) {
|
||||||
created = true;
|
created = true;
|
||||||
conv = new Chat(acc, static_cast<Models::Contact*>(el));
|
conv = new Chat(acc, static_cast<Models::Contact*>(el));
|
||||||
@ -604,14 +565,12 @@ void Application::openConversation(const Models::Roster::ElId& id, const QString
|
|||||||
conv->raise();
|
conv->raise();
|
||||||
conv->activateWindow();
|
conv->activateWindow();
|
||||||
|
|
||||||
if (resource.size() > 0) {
|
if (resource.size() > 0)
|
||||||
conv->setPalResource(resource);
|
conv->setPalResource(resource);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::onConversationMessage(const Shared::Message& msg)
|
void Application::onConversationMessage(const Shared::Message& msg) {
|
||||||
{
|
|
||||||
Conversation* conv = static_cast<Conversation*>(sender());
|
Conversation* conv = static_cast<Conversation*>(sender());
|
||||||
QString acc = conv->getAccount();
|
QString acc = conv->getAccount();
|
||||||
|
|
||||||
@ -619,8 +578,7 @@ void Application::onConversationMessage(const Shared::Message& msg)
|
|||||||
emit sendMessage(acc, msg);
|
emit sendMessage(acc, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::onConversationReplaceMessage(const QString& originalId, const Shared::Message& msg)
|
void Application::onConversationReplaceMessage(const QString& originalId, const Shared::Message& msg) {
|
||||||
{
|
|
||||||
Conversation* conv = static_cast<Conversation*>(sender());
|
Conversation* conv = static_cast<Conversation*>(sender());
|
||||||
QString acc = conv->getAccount();
|
QString acc = conv->getAccount();
|
||||||
|
|
||||||
@ -630,8 +588,15 @@ void Application::onConversationReplaceMessage(const QString& originalId, const
|
|||||||
emit replaceMessage(acc, originalId, msg);
|
emit replaceMessage(acc, originalId, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::onConversationResend(const QString& id)
|
void Application::onConversationSetEncryption(Shared::EncryptionProtocol value) {
|
||||||
{
|
Conversation* conv = static_cast<Conversation*>(sender());
|
||||||
|
QString acc = conv->getAccount();
|
||||||
|
QString jid = conv->getJid();
|
||||||
|
|
||||||
|
emit setEncryption(acc, jid, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::onConversationResend(const QString& id) {
|
||||||
Conversation* conv = static_cast<Conversation*>(sender());
|
Conversation* conv = static_cast<Conversation*>(sender());
|
||||||
QString acc = conv->getAccount();
|
QString acc = conv->getAccount();
|
||||||
QString jid = conv->getJid();
|
QString jid = conv->getJid();
|
||||||
@ -649,8 +614,7 @@ void Application::onSquawkOpenedConversation() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::removeAccount(const QString& account)
|
void Application::removeAccount(const QString& account) {
|
||||||
{
|
|
||||||
Conversations::const_iterator itr = conversations.begin();
|
Conversations::const_iterator itr = conversations.begin();
|
||||||
while (itr != conversations.end()) {
|
while (itr != conversations.end()) {
|
||||||
if (itr->first.account == account) {
|
if (itr->first.account == account) {
|
||||||
@ -665,23 +629,20 @@ void Application::removeAccount(const QString& account)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (squawk != nullptr && squawk->currentConversationId().account == account) {
|
if (squawk != nullptr && squawk->currentConversationId().account == account)
|
||||||
squawk->closeCurrentConversation();
|
squawk->closeCurrentConversation();
|
||||||
}
|
|
||||||
|
|
||||||
roster.removeAccount(account);
|
roster.removeAccount(account);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::changeAccount(const QString& account, const QMap<QString, QVariant>& data)
|
void Application::changeAccount(const QString& account, const QMap<QString, QVariant>& data) {
|
||||||
{
|
|
||||||
for (QMap<QString, QVariant>::const_iterator itr = data.begin(), end = data.end(); itr != end; ++itr) {
|
for (QMap<QString, QVariant>::const_iterator itr = data.begin(), end = data.end(); itr != end; ++itr) {
|
||||||
QString attr = itr.key();
|
QString attr = itr.key();
|
||||||
roster.updateAccount(account, attr, *itr);
|
roster.updateAccount(account, attr, *itr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::addGroup(const QString& account, const QString& name)
|
void Application::addGroup(const QString& account, const QString& name) {
|
||||||
{
|
|
||||||
roster.addGroup(account, name);
|
roster.addGroup(account, name);
|
||||||
|
|
||||||
if (squawk != nullptr) {
|
if (squawk != nullptr) {
|
||||||
@ -692,10 +653,9 @@ void Application::addGroup(const QString& account, const QString& name)
|
|||||||
if (settings.value("expanded", false).toBool()) {
|
if (settings.value("expanded", false).toBool()) {
|
||||||
QModelIndex ind = roster.getAccountIndex(account);
|
QModelIndex ind = roster.getAccountIndex(account);
|
||||||
squawk->expand(ind);
|
squawk->expand(ind);
|
||||||
if (settings.value(name + "/expanded", false).toBool()) {
|
if (settings.value(name + "/expanded", false).toBool())
|
||||||
squawk->expand(roster.getGroupIndex(account, name));
|
squawk->expand(roster.getGroupIndex(account, name));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
|
@ -60,6 +60,7 @@ signals:
|
|||||||
void setRoomAutoJoin(const QString& account, const QString& jid, bool joined);
|
void setRoomAutoJoin(const QString& account, const QString& jid, bool joined);
|
||||||
void subscribeContact(const QString& account, const QString& jid, const QString& reason);
|
void subscribeContact(const QString& account, const QString& jid, const QString& reason);
|
||||||
void unsubscribeContact(const QString& account, const QString& jid, const QString& reason);
|
void unsubscribeContact(const QString& account, const QString& jid, const QString& reason);
|
||||||
|
void setEncryption(const QString& account, const QString& jid, Shared::EncryptionProtocol value);
|
||||||
|
|
||||||
void quitting();
|
void quitting();
|
||||||
void readyToQuit();
|
void readyToQuit();
|
||||||
@ -101,6 +102,7 @@ private slots:
|
|||||||
void onItemExpanded(const QModelIndex& index);
|
void onItemExpanded(const QModelIndex& index);
|
||||||
void onItemCollapsed(const QModelIndex& index);
|
void onItemCollapsed(const QModelIndex& index);
|
||||||
void onAddedElement(const std::list<QString>& path);
|
void onAddedElement(const std::list<QString>& path);
|
||||||
|
void onConversationSetEncryption(Shared::EncryptionProtocol value);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void createMainWindow();
|
void createMainWindow();
|
||||||
|
130
main/main.cpp
@ -16,125 +16,43 @@
|
|||||||
* 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 "shared/global.h"
|
#include "root.h"
|
||||||
#include "shared/messageinfo.h"
|
#include "shared/messageinfo.h"
|
||||||
#include "shared/pathcheck.h"
|
#include "shared/identity.h"
|
||||||
#include "main/application.h"
|
#include "shared/info.h"
|
||||||
#include "core/signalcatcher.h"
|
|
||||||
#include "core/squawk.h"
|
|
||||||
|
|
||||||
#include <QLibraryInfo>
|
#include <QObject>
|
||||||
#include <QSettings>
|
|
||||||
#include <QStandardPaths>
|
|
||||||
#include <QTranslator>
|
|
||||||
#include <QtCore/QObject>
|
|
||||||
#include <QtCore/QThread>
|
|
||||||
#include <QtWidgets/QApplication>
|
|
||||||
#include <QDir>
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
#ifdef WITH_OMEMO
|
||||||
{
|
#include <QXmppOmemoStorage.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
qRegisterMetaType<Shared::Message>("Shared::Message");
|
qRegisterMetaType<Shared::Message>("Shared::Message");
|
||||||
qRegisterMetaType<Shared::MessageInfo>("Shared::MessageInfo");
|
qRegisterMetaType<Shared::MessageInfo>("Shared::MessageInfo");
|
||||||
qRegisterMetaType<Shared::VCard>("Shared::VCard");
|
qRegisterMetaType<Shared::VCard>("Shared::VCard");
|
||||||
qRegisterMetaType<std::list<Shared::Message>>("std::list<Shared::Message>");
|
qRegisterMetaType<std::list<Shared::Message>>("std::list<Shared::Message>");
|
||||||
qRegisterMetaType<std::list<Shared::MessageInfo>>("std::list<Shared::MessageInfo>");
|
qRegisterMetaType<std::list<Shared::MessageInfo>>("std::list<Shared::MessageInfo>");
|
||||||
|
qRegisterMetaType<std::list<QString>>("std::list<QString>");
|
||||||
|
qRegisterMetaType<std::set<QString>>("std::set<QString>");
|
||||||
|
qRegisterMetaType<std::list<Shared::Identity>>("std::list<Shared::Identity>");
|
||||||
qRegisterMetaType<QSet<QString>>("QSet<QString>");
|
qRegisterMetaType<QSet<QString>>("QSet<QString>");
|
||||||
qRegisterMetaType<Shared::ConnectionState>("Shared::ConnectionState");
|
qRegisterMetaType<Shared::ConnectionState>("Shared::ConnectionState");
|
||||||
qRegisterMetaType<Shared::Availability>("Shared::Availability");
|
qRegisterMetaType<Shared::Availability>("Shared::Availability");
|
||||||
|
qRegisterMetaType<Shared::EncryptionProtocol>("Shared::EncryptionProtocol");
|
||||||
|
qRegisterMetaType<Shared::KeyInfo>("Shared::KeyInfo");
|
||||||
|
qRegisterMetaType<Shared::Info>("Shared::Info");
|
||||||
|
qRegisterMetaType<Shared::TrustLevel>("Shared::TrustLevel");
|
||||||
|
#ifdef WITH_OMEMO
|
||||||
|
qRegisterMetaType<QXmppOmemoStorage::OwnDevice>("QXmppOmemoStorage::OwnDevice");
|
||||||
|
qRegisterMetaTypeStreamOperators<QXmppOmemoStorage::OwnDevice>("QXmppOmemoStorage::OwnDevice");
|
||||||
|
qRegisterMetaType<QXmppOmemoStorage::Device>("QXmppOmemoStorage::Device");
|
||||||
|
#endif
|
||||||
|
|
||||||
QApplication app(argc, argv);
|
Root app(argc, argv);
|
||||||
SignalCatcher sc(&app);
|
if (!app.initializeSettings())
|
||||||
|
|
||||||
QApplication::setApplicationName("squawk");
|
|
||||||
QApplication::setOrganizationName("macaw.me");
|
|
||||||
QApplication::setApplicationDisplayName("Squawk");
|
|
||||||
QApplication::setApplicationVersion("0.2.3");
|
|
||||||
app.setDesktopFileName("squawk");
|
|
||||||
|
|
||||||
QTranslator qtTranslator;
|
|
||||||
qtTranslator.load("qt_" + QLocale::system().name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath));
|
|
||||||
app.installTranslator(&qtTranslator);
|
|
||||||
|
|
||||||
QTranslator myappTranslator;
|
|
||||||
QStringList shares = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation);
|
|
||||||
bool found = false;
|
|
||||||
for (QString share : shares) {
|
|
||||||
found = myappTranslator.load(QLocale(), QLatin1String("squawk"), ".", share + "/l10n");
|
|
||||||
if (found) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
myappTranslator.load(QLocale(), QLatin1String("squawk"), ".", QCoreApplication::applicationDirPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
app.installTranslator(&myappTranslator);
|
|
||||||
|
|
||||||
QIcon icon;
|
|
||||||
icon.addFile(":images/logo.svg", QSize(16, 16));
|
|
||||||
icon.addFile(":images/logo.svg", QSize(24, 24));
|
|
||||||
icon.addFile(":images/logo.svg", QSize(32, 32));
|
|
||||||
icon.addFile(":images/logo.svg", QSize(48, 48));
|
|
||||||
icon.addFile(":images/logo.svg", QSize(64, 64));
|
|
||||||
icon.addFile(":images/logo.svg", QSize(96, 96));
|
|
||||||
icon.addFile(":images/logo.svg", QSize(128, 128));
|
|
||||||
icon.addFile(":images/logo.svg", QSize(256, 256));
|
|
||||||
icon.addFile(":images/logo.svg", QSize(512, 512));
|
|
||||||
QApplication::setWindowIcon(icon);
|
|
||||||
|
|
||||||
new Shared::Global(); //translates enums
|
|
||||||
|
|
||||||
QSettings settings;
|
|
||||||
QVariant vs = settings.value("style");
|
|
||||||
if (vs.isValid()) {
|
|
||||||
QString style = vs.toString().toLower();
|
|
||||||
if (style != "system") {
|
|
||||||
Shared::Global::setStyle(style);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (Shared::Global::supported("colorSchemeTools")) {
|
|
||||||
QVariant vt = settings.value("theme");
|
|
||||||
if (vt.isValid()) {
|
|
||||||
QString theme = vt.toString();
|
|
||||||
if (theme.toLower() != "system") {
|
|
||||||
Shared::Global::setTheme(theme);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
QString path = Shared::downloadsPathCheck();
|
|
||||||
if (path.size() > 0) {
|
|
||||||
settings.setValue("downloadsPath", path);
|
|
||||||
} else {
|
|
||||||
qDebug() << "couldn't initialize directory for downloads, quitting";
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
Core::Squawk* squawk = new Core::Squawk();
|
return app.run();
|
||||||
QThread* coreThread = new QThread();
|
|
||||||
squawk->moveToThread(coreThread);
|
|
||||||
|
|
||||||
Application application(squawk);
|
|
||||||
|
|
||||||
QObject::connect(&sc, &SignalCatcher::interrupt, &application, &Application::quit);
|
|
||||||
|
|
||||||
QObject::connect(coreThread, &QThread::started, squawk, &Core::Squawk::start);
|
|
||||||
QObject::connect(&application, &Application::quitting, squawk, &Core::Squawk::stop);
|
|
||||||
//QObject::connect(&app, &QApplication::aboutToQuit, &w, &QMainWindow::close);
|
|
||||||
QObject::connect(squawk, &Core::Squawk::quit, squawk, &Core::Squawk::deleteLater);
|
|
||||||
QObject::connect(squawk, &Core::Squawk::destroyed, coreThread, &QThread::quit, Qt::QueuedConnection);
|
|
||||||
QObject::connect(coreThread, &QThread::finished, &app, &QApplication::quit, Qt::QueuedConnection);
|
|
||||||
|
|
||||||
coreThread->start();
|
|
||||||
int result = app.exec();
|
|
||||||
|
|
||||||
if (coreThread->isRunning()) {
|
|
||||||
//coreThread->wait();
|
|
||||||
//todo if I uncomment that, the app will not quit if it has reconnected at least once
|
|
||||||
//it feels like a symptom of something badly desinged in the core thread
|
|
||||||
//need to investigate;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
190
main/root.cpp
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
// 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 "root.h"
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QThread>
|
||||||
|
#include <QLibraryInfo>
|
||||||
|
#include <QStandardPaths>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <shared/pathcheck.h>
|
||||||
|
|
||||||
|
const std::vector<unsigned int> Root::appIconSizes({
|
||||||
|
16, 24, 32, 48, 64, 96, 128, 256, 512
|
||||||
|
});
|
||||||
|
|
||||||
|
Root::Root(int& argc, char *argv[]) :
|
||||||
|
QApplication(argc, argv),
|
||||||
|
signalCatcher(this),
|
||||||
|
defaultTranslator(),
|
||||||
|
currentTranslator(),
|
||||||
|
appIcon(),
|
||||||
|
settings(),
|
||||||
|
componentsInitialized(false),
|
||||||
|
global(nullptr),
|
||||||
|
coreThread(nullptr),
|
||||||
|
core(nullptr),
|
||||||
|
gui(nullptr)
|
||||||
|
{
|
||||||
|
setApplicationName("squawk");
|
||||||
|
setOrganizationName("macaw.me");
|
||||||
|
setApplicationDisplayName("Squawk");
|
||||||
|
setApplicationVersion("0.2.3");
|
||||||
|
setDesktopFileName("squawk");
|
||||||
|
|
||||||
|
initializeTranslation();
|
||||||
|
initializeAppIcon();
|
||||||
|
|
||||||
|
global = new Shared::Global(); //important to instantiate after initialization of translations;
|
||||||
|
}
|
||||||
|
|
||||||
|
Root::~Root() {
|
||||||
|
if (componentsInitialized) {
|
||||||
|
delete gui;
|
||||||
|
if (core != nullptr)
|
||||||
|
delete core;
|
||||||
|
delete coreThread;
|
||||||
|
}
|
||||||
|
delete global;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Root::initializeTranslation() {
|
||||||
|
defaultTranslator.load("qt_" + QLocale::system().name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath));
|
||||||
|
installTranslator(&defaultTranslator);
|
||||||
|
|
||||||
|
QStringList shares = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation);
|
||||||
|
bool found = false;
|
||||||
|
for (QString share : shares) {
|
||||||
|
found = currentTranslator.load(QLocale(), QLatin1String("squawk"), ".", share + "/l10n");
|
||||||
|
if (found) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
currentTranslator.load(QLocale(), QLatin1String("squawk"), ".", QCoreApplication::applicationDirPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
installTranslator(¤tTranslator);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Root::initializeAppIcon() {
|
||||||
|
for (std::vector<unsigned int>::size_type i = 0; i < appIconSizes.size(); ++i)
|
||||||
|
appIcon.addFile(":images/logo.svg", QSize(appIconSizes[i], appIconSizes[i]));
|
||||||
|
|
||||||
|
Root::setWindowIcon(appIcon);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Root::initializeSettings() {
|
||||||
|
QVariant vs = settings.value("style");
|
||||||
|
if (vs.isValid()) {
|
||||||
|
QString style = vs.toString().toLower();
|
||||||
|
if (style != "system") {
|
||||||
|
Shared::Global::setStyle(style);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Shared::Global::supported("colorSchemeTools")) {
|
||||||
|
QVariant vt = settings.value("theme");
|
||||||
|
if (vt.isValid()) {
|
||||||
|
QString theme = vt.toString();
|
||||||
|
if (theme.toLower() != "system") {
|
||||||
|
Shared::Global::setTheme(theme);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString path = Shared::downloadsPathCheck();
|
||||||
|
if (path.size() > 0) {
|
||||||
|
settings.setValue("downloadsPath", path);
|
||||||
|
} else {
|
||||||
|
qDebug() << "couldn't initialize directory for downloads, quitting";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Root::run() {
|
||||||
|
if (!componentsInitialized)
|
||||||
|
initializeComponents();
|
||||||
|
|
||||||
|
coreThread->start();
|
||||||
|
int result = exec();
|
||||||
|
qDebug("Event loop stopped");
|
||||||
|
|
||||||
|
if (result == 0) {
|
||||||
|
processEvents(); //I dont like all of this mess
|
||||||
|
if (coreThread->isRunning()) { //but it's the best solution for now
|
||||||
|
if (core != nullptr) { //Ideally, following line should never appear in the log
|
||||||
|
qDebug() << "Core is still seems to be running, killing manually";
|
||||||
|
core->deleteLater();
|
||||||
|
coreThread->quit();
|
||||||
|
processEvents();
|
||||||
|
core = nullptr;
|
||||||
|
}
|
||||||
|
coreThread->wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Root::initializeComponents() {
|
||||||
|
core = new Core::Squawk();
|
||||||
|
coreThread = new QThread();
|
||||||
|
core->moveToThread(coreThread);
|
||||||
|
gui = new Application(core);
|
||||||
|
|
||||||
|
QObject::connect(&signalCatcher, &SignalCatcher::interrupt, gui, &Application::quit);
|
||||||
|
|
||||||
|
QObject::connect(coreThread, &QThread::started, core, &Core::Squawk::start);
|
||||||
|
QObject::connect(gui, &Application::quitting, core, &Core::Squawk::stop);
|
||||||
|
|
||||||
|
QObject::connect(core, &Core::Squawk::quit, core, &Core::Squawk::deleteLater);
|
||||||
|
QObject::connect(core, &Core::Squawk::destroyed, this, &Root::onCoreDestroyed);
|
||||||
|
QObject::connect(core, &Core::Squawk::destroyed, coreThread, &QThread::quit, Qt::QueuedConnection);
|
||||||
|
QObject::connect(coreThread, &QThread::finished, this, &Root::quit, Qt::QueuedConnection);
|
||||||
|
|
||||||
|
componentsInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Root::notify(QObject* receiver, QEvent* e) {
|
||||||
|
try {
|
||||||
|
return QApplication::notify(receiver, e);
|
||||||
|
} catch(const std::runtime_error& e) {
|
||||||
|
qDebug() << "std::runtime_error in thread:" << QThread::currentThreadId();
|
||||||
|
qDebug() << "error message:" << e.what();
|
||||||
|
} catch(const std::exception& e) {
|
||||||
|
qDebug() << "std::exception in thread:" << QThread::currentThreadId();
|
||||||
|
qDebug() << "error message:" << e.what();
|
||||||
|
} catch(const int& e) {
|
||||||
|
qDebug() << "integer exception in thread:" << QThread::currentThreadId();
|
||||||
|
qDebug() << "thrown integer:" << std::to_string(e).c_str();
|
||||||
|
} catch(...) {
|
||||||
|
qDebug() << "unhandled exception thread:" << QThread::currentThreadId();
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "Squawk is crashing...";
|
||||||
|
exit(1);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Root::onCoreDestroyed() {
|
||||||
|
core = nullptr;
|
||||||
|
}
|
70
main/root.h
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
#ifndef ROOT_H
|
||||||
|
#define ROOT_H
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QTranslator>
|
||||||
|
#include <QIcon>
|
||||||
|
#include <QSettings>
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <core/squawk.h>
|
||||||
|
#include <core/signalcatcher.h>
|
||||||
|
|
||||||
|
#include <shared/global.h>
|
||||||
|
|
||||||
|
#include "application.h"
|
||||||
|
|
||||||
|
class Root : public QApplication {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
Root(int& argc, char* argv[]);
|
||||||
|
~Root();
|
||||||
|
bool notify(QObject* receiver, QEvent* e) override;
|
||||||
|
int run();
|
||||||
|
|
||||||
|
bool initializeSettings();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onCoreDestroyed();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void initializeTranslation();
|
||||||
|
void initializeAppIcon();
|
||||||
|
void initializeComponents();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const std::vector<unsigned int> appIconSizes;
|
||||||
|
|
||||||
|
SignalCatcher signalCatcher;
|
||||||
|
QTranslator defaultTranslator;
|
||||||
|
QTranslator currentTranslator;
|
||||||
|
QIcon appIcon;
|
||||||
|
QSettings settings;
|
||||||
|
bool componentsInitialized;
|
||||||
|
|
||||||
|
Shared::Global* global;
|
||||||
|
QThread* coreThread;
|
||||||
|
Core::Squawk* core;
|
||||||
|
Application* gui;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ROOT_H
|
@ -1,12 +1,12 @@
|
|||||||
# Maintainer: Yury Gubich <blue@macaw.me>
|
# Maintainer: Yury Gubich <blue@macaw.me>
|
||||||
pkgname=squawk
|
pkgname=squawk
|
||||||
pkgver=0.2.2
|
pkgver=0.2.3
|
||||||
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' 'lmdb' 'qxmpp>=1.1.0')
|
depends=('hicolor-icon-theme' 'desktop-file-utils' 'lmdbal' 'qxmpp>=1.1.0')
|
||||||
makedepends=('cmake>=3.3' 'imagemagick' 'qt5-tools' 'boost')
|
makedepends=('cmake>=3.3' 'imagemagick' 'qt5-tools' 'boost')
|
||||||
optdepends=('kwallet: secure password storage (requires rebuild)'
|
optdepends=('kwallet: secure password storage (requires rebuild)'
|
||||||
'kconfig: system themes support (requires rebuild)'
|
'kconfig: system themes support (requires rebuild)'
|
||||||
@ -18,9 +18,9 @@ sha256sums=('e4fa2174a3ba95159cc3b0bac3f00550c9e0ce971c55334e2662696a4543fc7e')
|
|||||||
build() {
|
build() {
|
||||||
cd "$srcdir/squawk"
|
cd "$srcdir/squawk"
|
||||||
cmake . -D CMAKE_INSTALL_PREFIX=/usr -D CMAKE_BUILD_TYPE=Release
|
cmake . -D CMAKE_INSTALL_PREFIX=/usr -D CMAKE_BUILD_TYPE=Release
|
||||||
cmake --build . -j $nproc
|
cmake --build .
|
||||||
}
|
}
|
||||||
package() {
|
package() {
|
||||||
cd "$srcdir/squawk"
|
cd "$srcdir/squawk"
|
||||||
DESTDIR="$pkgdir/" cmake --build . --target install
|
DESTDIR="$pkgdir/" cmake --install .
|
||||||
}
|
}
|
||||||
|
13
resources/images/fallback/dark/big/lock.svg
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22">
|
||||||
|
<defs id="defs3051">
|
||||||
|
<style type="text/css" id="current-color-scheme">
|
||||||
|
.ColorScheme-Text {
|
||||||
|
color:#232629;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<path style="fill:currentColor;fill-opacity:1;stroke:none"
|
||||||
|
d="M 11,3 C 8.784,3 7,4.784 7,7 l 0,4 -2,0 c 0,2.666667 0,5.333333 0,8 4,0 8,0 12,0 l 0,-8 c -0.666667,0 -1.333333,0 -2,0 L 15,7 C 15,4.784 13.216,3 11,3 m 0,1 c 1.662,0 3,1.561 3,3.5 L 14,11 8,11 8,7.5 C 8,5.561 9.338,4 11,4"
|
||||||
|
class="ColorScheme-Text"
|
||||||
|
/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 558 B |
13
resources/images/fallback/dark/big/shield.svg
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||||
|
<defs id="defs3051">
|
||||||
|
<style type="text/css" id="current-color-scheme">
|
||||||
|
.ColorScheme-Text {
|
||||||
|
color:#232629;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<path
|
||||||
|
style="fill:currentColor;fill-opacity:1;stroke:none"
|
||||||
|
d="M 8,2 C 8,2 6.5,3.9931391 2,4.4931641 2,4.4931641 2,11.493575 8,14 14,11.493575 14,4.4931641 14,4.4931641 9.5,3.9931391 8,2 8,2 Z m 0,1.0327148 c 1.1902463,1.008525 2.90787,1.6813196 5.134277,2.0200196 C 13.013333,6.1366343 12.897371,6.9523225 12.617188,7.7407227 12.02837,9.3975477 11.341831,10.405496 10.726074,11.130371 9.7719035,12.253646 8.905394,12.708244 8,13.160644 7.094606,12.708244 6.2280961,12.253646 5.2739258,11.130371 4.658169,10.405496 3.97163,9.3975477 3.3828125,7.7407227 3.102629,6.9523225 2.9866669,6.1366343 2.8657227,5.0527344 5.0921299,4.7140344 6.8097538,4.0412398 8,3.0327148 Z M 8,3.9321289 C 6.6923817,4.8398539 5.2233869,5.2995548 3.7490234,5.6123046 4.4471579,9.5738045 5.9510862,11.267813 8,12.328613 10.048914,11.267813 11.552843,9.5738045 12.250977,5.6123046 10.776613,5.2995547 9.3076183,4.8398539 8,3.9321289 Z"
|
||||||
|
class="ColorScheme-Text"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
14
resources/images/fallback/dark/big/unlock.svg
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22">
|
||||||
|
<defs id="defs3051">
|
||||||
|
<style type="text/css" id="current-color-scheme">
|
||||||
|
.ColorScheme-Text {
|
||||||
|
color:#232629;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<path
|
||||||
|
style="fill:currentColor;fill-opacity:1;stroke:none"
|
||||||
|
d="m11 3c-2.216 0-4 1.784-4 4v1h1v-.5c0-1.939 1.338-3.5 3-3.5 1.662 0 3 1.561 3 3.5v3.5h-5-1-1-1-1v1 7h1 10 1v-8h-1-1v-4c0-2.216-1.784-4-4-4m-5 9h10v6h-10v-6"
|
||||||
|
class="ColorScheme-Text"
|
||||||
|
/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 491 B |
13
resources/images/fallback/dark/small/lock.svg
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||||
|
<defs id="defs3051">
|
||||||
|
<style type="text/css" id="current-color-scheme">
|
||||||
|
.ColorScheme-Text {
|
||||||
|
color:#232629;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<path style="fill:currentColor;fill-opacity:1;stroke:none"
|
||||||
|
d="M 8,2 C 6.3431375,2 5,3.3431372 5,5 l 0,3 -2,0 0,6 10,0 0,-6 -2,0 0,-3 C 11,3.3431372 9.6568625,2 8,2 Z m 0,1 c 1.1045695,0 2,0.8954305 2,2 L 10,8 6,8 6,5 C 6,3.8954305 6.8954305,3 8,3 Z"
|
||||||
|
class="ColorScheme-Text"
|
||||||
|
/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 522 B |
13
resources/images/fallback/dark/small/shield.svg
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||||
|
<defs id="defs3051">
|
||||||
|
<style type="text/css" id="current-color-scheme">
|
||||||
|
.ColorScheme-Text {
|
||||||
|
color:#232629;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<path
|
||||||
|
style="fill:currentColor;fill-opacity:1;stroke:none"
|
||||||
|
d="M 8,2 C 8,2 6.5,3.9931391 2,4.4931641 2,4.4931641 2,11.493575 8,14 14,11.493575 14,4.4931641 14,4.4931641 9.5,3.9931391 8,2 8,2 Z m 0,1.0327148 c 1.1902463,1.008525 2.90787,1.6813196 5.134277,2.0200196 C 13.013333,6.1366343 12.897371,6.9523225 12.617188,7.7407227 12.02837,9.3975477 11.341831,10.405496 10.726074,11.130371 9.7719035,12.253646 8.905394,12.708244 8,13.160644 7.094606,12.708244 6.2280961,12.253646 5.2739258,11.130371 4.658169,10.405496 3.97163,9.3975477 3.3828125,7.7407227 3.102629,6.9523225 2.9866669,6.1366343 2.8657227,5.0527344 5.0921299,4.7140344 6.8097538,4.0412398 8,3.0327148 Z M 8,3.9321289 C 6.6923817,4.8398539 5.2233869,5.2995548 3.7490234,5.6123046 4.4471579,9.5738045 5.9510862,11.267813 8,12.328613 10.048914,11.267813 11.552843,9.5738045 12.250977,5.6123046 10.776613,5.2995547 9.3076183,4.8398539 8,3.9321289 Z"
|
||||||
|
class="ColorScheme-Text"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
13
resources/images/fallback/dark/small/unlock.svg
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||||
|
<defs id="defs3051">
|
||||||
|
<style type="text/css" id="current-color-scheme">
|
||||||
|
.ColorScheme-Text {
|
||||||
|
color:#232629;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<path style="fill:currentColor;fill-opacity:1;stroke:none"
|
||||||
|
d="M 8 2 C 6.3431375 2 5 3.3431371 5 5 L 5 6 L 6 6 L 6 5 C 6 3.8954305 6.8954305 3 8 3 C 9.1045695 3 10 3.8954305 10 5 L 10 8 L 7 8 L 6 8 L 5 8 L 3 8 L 3 14 L 13 14 L 13 8 L 11 8 L 11 5 C 11 3.3431371 9.6568625 2 8 2 z M 4 9 L 12 9 L 12 13 L 4 13 L 4 9 z "
|
||||||
|
class="ColorScheme-Text"
|
||||||
|
/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 588 B |
13
resources/images/fallback/light/big/lock.svg
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22">
|
||||||
|
<defs id="defs3051">
|
||||||
|
<style type="text/css" id="current-color-scheme">
|
||||||
|
.ColorScheme-Text {
|
||||||
|
color:#eff0f1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<path style="fill:currentColor;fill-opacity:1;stroke:none"
|
||||||
|
d="M 11,3 C 8.784,3 7,4.784 7,7 l 0,4 -2,0 c 0,2.666667 0,5.333333 0,8 4,0 8,0 12,0 l 0,-8 c -0.666667,0 -1.333333,0 -2,0 L 15,7 C 15,4.784 13.216,3 11,3 m 0,1 c 1.662,0 3,1.561 3,3.5 L 14,11 8,11 8,7.5 C 8,5.561 9.338,4 11,4"
|
||||||
|
class="ColorScheme-Text"
|
||||||
|
/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 558 B |
13
resources/images/fallback/light/big/shield.svg
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||||
|
<defs id="defs3051">
|
||||||
|
<style type="text/css" id="current-color-scheme">
|
||||||
|
.ColorScheme-Text {
|
||||||
|
color:#eff0f1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<path
|
||||||
|
style="fill:currentColor;fill-opacity:1;stroke:none"
|
||||||
|
d="M 8,2 C 8,2 6.5,3.9931391 2,4.4931641 2,4.4931641 2,11.493575 8,14 14,11.493575 14,4.4931641 14,4.4931641 9.5,3.9931391 8,2 8,2 Z m 0,1.0327148 c 1.1902463,1.008525 2.90787,1.6813196 5.134277,2.0200196 C 13.013333,6.1366343 12.897371,6.9523225 12.617188,7.7407227 12.02837,9.3975477 11.341831,10.405496 10.726074,11.130371 9.7719035,12.253646 8.905394,12.708244 8,13.160644 7.094606,12.708244 6.2280961,12.253646 5.2739258,11.130371 4.658169,10.405496 3.97163,9.3975477 3.3828125,7.7407227 3.102629,6.9523225 2.9866669,6.1366343 2.8657227,5.0527344 5.0921299,4.7140344 6.8097538,4.0412398 8,3.0327148 Z M 8,3.9321289 C 6.6923817,4.8398539 5.2233869,5.2995548 3.7490234,5.6123046 4.4471579,9.5738045 5.9510862,11.267813 8,12.328613 10.048914,11.267813 11.552843,9.5738045 12.250977,5.6123046 10.776613,5.2995547 9.3076183,4.8398539 8,3.9321289 Z"
|
||||||
|
class="ColorScheme-Text"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
14
resources/images/fallback/light/big/unlock.svg
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22">
|
||||||
|
<defs id="defs3051">
|
||||||
|
<style type="text/css" id="current-color-scheme">
|
||||||
|
.ColorScheme-Text {
|
||||||
|
color:#eff0f1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<path
|
||||||
|
style="fill:currentColor;fill-opacity:1;stroke:none"
|
||||||
|
d="m11 3c-2.216 0-4 1.784-4 4v1h1v-.5c0-1.939 1.338-3.5 3-3.5 1.662 0 3 1.561 3 3.5v3.5h-5-1-1-1-1v1 7h1 10 1v-8h-1-1v-4c0-2.216-1.784-4-4-4m-5 9h10v6h-10v-6"
|
||||||
|
class="ColorScheme-Text"
|
||||||
|
/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 491 B |
13
resources/images/fallback/light/small/lock.svg
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||||
|
<defs id="defs3051">
|
||||||
|
<style type="text/css" id="current-color-scheme">
|
||||||
|
.ColorScheme-Text {
|
||||||
|
color:#eff0f1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<path style="fill:currentColor;fill-opacity:1;stroke:none"
|
||||||
|
d="M 8,2 C 6.3431375,2 5,3.3431372 5,5 l 0,3 -2,0 0,6 10,0 0,-6 -2,0 0,-3 C 11,3.3431372 9.6568625,2 8,2 Z m 0,1 c 1.1045695,0 2,0.8954305 2,2 L 10,8 6,8 6,5 C 6,3.8954305 6.8954305,3 8,3 Z"
|
||||||
|
class="ColorScheme-Text"
|
||||||
|
/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 522 B |
13
resources/images/fallback/light/small/shield.svg
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||||
|
<defs id="defs3051">
|
||||||
|
<style type="text/css" id="current-color-scheme">
|
||||||
|
.ColorScheme-Text {
|
||||||
|
color:#eff0f1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<path
|
||||||
|
style="fill:currentColor;fill-opacity:1;stroke:none"
|
||||||
|
d="M 8,2 C 8,2 6.5,3.9931391 2,4.4931641 2,4.4931641 2,11.493575 8,14 14,11.493575 14,4.4931641 14,4.4931641 9.5,3.9931391 8,2 8,2 Z m 0,1.0327148 c 1.1902463,1.008525 2.90787,1.6813196 5.134277,2.0200196 C 13.013333,6.1366343 12.897371,6.9523225 12.617188,7.7407227 12.02837,9.3975477 11.341831,10.405496 10.726074,11.130371 9.7719035,12.253646 8.905394,12.708244 8,13.160644 7.094606,12.708244 6.2280961,12.253646 5.2739258,11.130371 4.658169,10.405496 3.97163,9.3975477 3.3828125,7.7407227 3.102629,6.9523225 2.9866669,6.1366343 2.8657227,5.0527344 5.0921299,4.7140344 6.8097538,4.0412398 8,3.0327148 Z M 8,3.9321289 C 6.6923817,4.8398539 5.2233869,5.2995548 3.7490234,5.6123046 4.4471579,9.5738045 5.9510862,11.267813 8,12.328613 10.048914,11.267813 11.552843,9.5738045 12.250977,5.6123046 10.776613,5.2995547 9.3076183,4.8398539 8,3.9321289 Z"
|
||||||
|
class="ColorScheme-Text"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
13
resources/images/fallback/light/small/unlock.svg
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||||
|
<defs id="defs3051">
|
||||||
|
<style type="text/css" id="current-color-scheme">
|
||||||
|
.ColorScheme-Text {
|
||||||
|
color:#eff0f1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<path style="fill:currentColor;fill-opacity:1;stroke:none"
|
||||||
|
d="M 8 2 C 6.3431375 2 5 3.3431371 5 5 L 5 6 L 6 6 L 6 5 C 6 3.8954305 6.8954305 3 8 3 C 9.1045695 3 10 3.8954305 10 5 L 10 8 L 7 8 L 6 8 L 5 8 L 3 8 L 3 14 L 13 14 L 13 8 L 11 8 L 11 5 C 11 3.3431371 9.6568625 2 8 2 z M 4 9 L 12 9 L 12 13 L 4 13 L 4 9 z "
|
||||||
|
class="ColorScheme-Text"
|
||||||
|
/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 588 B |
@ -42,6 +42,9 @@
|
|||||||
<file>images/fallback/dark/big/add.svg</file>
|
<file>images/fallback/dark/big/add.svg</file>
|
||||||
<file>images/fallback/dark/big/folder.svg</file>
|
<file>images/fallback/dark/big/folder.svg</file>
|
||||||
<file>images/fallback/dark/big/document-preview.svg</file>
|
<file>images/fallback/dark/big/document-preview.svg</file>
|
||||||
|
<file>images/fallback/dark/big/shield.svg</file>
|
||||||
|
<file>images/fallback/dark/big/lock.svg</file>
|
||||||
|
<file>images/fallback/dark/big/unlock.svg</file>
|
||||||
|
|
||||||
|
|
||||||
<file>images/fallback/dark/small/absent.svg</file>
|
<file>images/fallback/dark/small/absent.svg</file>
|
||||||
@ -84,6 +87,9 @@
|
|||||||
<file>images/fallback/dark/small/add.svg</file>
|
<file>images/fallback/dark/small/add.svg</file>
|
||||||
<file>images/fallback/dark/small/folder.svg</file>
|
<file>images/fallback/dark/small/folder.svg</file>
|
||||||
<file>images/fallback/dark/small/document-preview.svg</file>
|
<file>images/fallback/dark/small/document-preview.svg</file>
|
||||||
|
<file>images/fallback/dark/small/shield.svg</file>
|
||||||
|
<file>images/fallback/dark/small/lock.svg</file>
|
||||||
|
<file>images/fallback/dark/small/unlock.svg</file>
|
||||||
|
|
||||||
|
|
||||||
<file>images/fallback/light/big/absent.svg</file>
|
<file>images/fallback/light/big/absent.svg</file>
|
||||||
@ -126,6 +132,9 @@
|
|||||||
<file>images/fallback/light/big/add.svg</file>
|
<file>images/fallback/light/big/add.svg</file>
|
||||||
<file>images/fallback/light/big/folder.svg</file>
|
<file>images/fallback/light/big/folder.svg</file>
|
||||||
<file>images/fallback/light/big/document-preview.svg</file>
|
<file>images/fallback/light/big/document-preview.svg</file>
|
||||||
|
<file>images/fallback/light/big/shield.svg</file>
|
||||||
|
<file>images/fallback/light/big/lock.svg</file>
|
||||||
|
<file>images/fallback/light/big/unlock.svg</file>
|
||||||
|
|
||||||
|
|
||||||
<file>images/fallback/light/small/absent.svg</file>
|
<file>images/fallback/light/small/absent.svg</file>
|
||||||
@ -168,5 +177,8 @@
|
|||||||
<file>images/fallback/light/small/add.svg</file>
|
<file>images/fallback/light/small/add.svg</file>
|
||||||
<file>images/fallback/light/small/folder.svg</file>
|
<file>images/fallback/light/small/folder.svg</file>
|
||||||
<file>images/fallback/light/small/document-preview.svg</file>
|
<file>images/fallback/light/small/document-preview.svg</file>
|
||||||
|
<file>images/fallback/light/small/shield.svg</file>
|
||||||
|
<file>images/fallback/light/small/lock.svg</file>
|
||||||
|
<file>images/fallback/light/small/unlock.svg</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
@ -1,21 +1,45 @@
|
|||||||
target_sources(squawk PRIVATE
|
set(SOURCE_FILES
|
||||||
enums.h
|
|
||||||
global.cpp
|
global.cpp
|
||||||
global.h
|
|
||||||
exception.cpp
|
exception.cpp
|
||||||
exception.h
|
|
||||||
icons.cpp
|
icons.cpp
|
||||||
icons.h
|
|
||||||
message.cpp
|
message.cpp
|
||||||
message.h
|
|
||||||
messageinfo.cpp
|
messageinfo.cpp
|
||||||
messageinfo.h
|
|
||||||
order.h
|
|
||||||
shared.h
|
|
||||||
utils.cpp
|
utils.cpp
|
||||||
utils.h
|
|
||||||
vcard.cpp
|
vcard.cpp
|
||||||
vcard.h
|
|
||||||
pathcheck.cpp
|
pathcheck.cpp
|
||||||
|
clientinfo.cpp
|
||||||
|
identity.cpp
|
||||||
|
form.cpp
|
||||||
|
field.cpp
|
||||||
|
keyinfo.cpp
|
||||||
|
info.cpp
|
||||||
|
clientid.cpp
|
||||||
|
trustsummary.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(HEADER_FILES
|
||||||
|
shared.h
|
||||||
|
enums.h
|
||||||
|
global.h
|
||||||
|
exception.h
|
||||||
|
icons.h
|
||||||
|
message.h
|
||||||
|
messageinfo.h
|
||||||
|
utils.h
|
||||||
|
vcard.h
|
||||||
pathcheck.h
|
pathcheck.h
|
||||||
)
|
clientinfo.h
|
||||||
|
identity.h
|
||||||
|
form.h
|
||||||
|
field.h
|
||||||
|
keyinfo.h
|
||||||
|
info.h
|
||||||
|
clientid.h
|
||||||
|
trustsummary.h
|
||||||
|
defines.h
|
||||||
|
)
|
||||||
|
|
||||||
|
target_sources(squawk PRIVATE
|
||||||
|
${SOURCE_FILES}
|
||||||
|
${HEADER_FILES}
|
||||||
|
)
|
||||||
|
167
shared/clientid.cpp
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
// 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 "clientid.h"
|
||||||
|
|
||||||
|
Shared::ClientId::ClientId():
|
||||||
|
node(),
|
||||||
|
verification(),
|
||||||
|
hash()
|
||||||
|
{}
|
||||||
|
|
||||||
|
Shared::ClientId::ClientId(const QString& p_node, const QString& p_ver, const QString& p_hash):
|
||||||
|
node(p_node),
|
||||||
|
verification(p_ver),
|
||||||
|
hash(p_hash)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
Shared::ClientId::ClientId(const Shared::ClientId& other):
|
||||||
|
node(other.node),
|
||||||
|
verification(other.verification),
|
||||||
|
hash(other.hash)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Shared::ClientId & Shared::ClientId::operator=(const Shared::ClientId& other) {
|
||||||
|
node = other.node;
|
||||||
|
verification = other.verification;
|
||||||
|
hash = other.hash;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Shared::ClientId::operator==(const Shared::ClientId& other) const {
|
||||||
|
return hash == other.hash && verification == other.verification && node == other.node;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Shared::ClientId::operator!=(const Shared::ClientId& other) const {
|
||||||
|
return hash != other.hash && verification != other.verification && node != other.node;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Shared::ClientId::operator<(const Shared::ClientId& other) const {
|
||||||
|
if (hash < other.hash)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (hash > other.hash)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (verification < other.verification)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (verification > other.verification)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (node < other.node)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Shared::ClientId::operator>(const Shared::ClientId& other) const {
|
||||||
|
if (hash > other.hash)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (hash < other.hash)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (verification > other.verification)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (verification < other.verification)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (node > other.node)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Shared::ClientId::operator<=(const Shared::ClientId& other) const {
|
||||||
|
if (hash < other.hash)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (hash > other.hash)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (verification < other.verification)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (verification > other.verification)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (node < other.node)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (node > other.node)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Shared::ClientId::operator>=(const Shared::ClientId& other) const {
|
||||||
|
if (hash > other.hash)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (hash < other.hash)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (verification > other.verification)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (verification < other.verification)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (node > other.node)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (node < other.node)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Shared::ClientId::getId() const {
|
||||||
|
return node + "/" + verification;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Shared::ClientId::valid() const {
|
||||||
|
return node.size() > 0 && verification.size() > 0 && hash.size() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDataStream & Shared::ClientId::operator<<(QDataStream& stream) {
|
||||||
|
stream >> node;
|
||||||
|
stream >> verification;
|
||||||
|
stream >> hash;
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDataStream & Shared::ClientId::operator>>(QDataStream& stream) const {
|
||||||
|
stream << node;
|
||||||
|
stream << verification;
|
||||||
|
stream << hash;
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDataStream & operator<<(QDataStream& stream, const Shared::ClientId& info) {
|
||||||
|
info >> stream;
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDataStream & operator>>(QDataStream& stream, Shared::ClientId& info) {
|
||||||
|
info << stream;
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
58
shared/clientid.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
#ifndef SHARED_CLIENTID_H
|
||||||
|
#define SHARED_CLIENTID_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include <QDataStream>
|
||||||
|
|
||||||
|
namespace Shared {
|
||||||
|
|
||||||
|
class ClientId {
|
||||||
|
public:
|
||||||
|
ClientId();
|
||||||
|
ClientId(const QString& node, const QString& verification, const QString& hash);
|
||||||
|
ClientId(const ClientId& other);
|
||||||
|
ClientId& operator = (const ClientId& other);
|
||||||
|
|
||||||
|
bool operator == (const ClientId& other) const;
|
||||||
|
bool operator != (const ClientId& other) const;
|
||||||
|
bool operator < (const ClientId& other) const;
|
||||||
|
bool operator > (const ClientId& other) const;
|
||||||
|
bool operator <= (const ClientId& other) const;
|
||||||
|
bool operator >= (const ClientId& other) const;
|
||||||
|
|
||||||
|
bool valid() const;
|
||||||
|
QString getId() const;
|
||||||
|
|
||||||
|
QDataStream& operator << (QDataStream& stream);
|
||||||
|
QDataStream& operator >> (QDataStream& stream) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
QString node;
|
||||||
|
QString verification;
|
||||||
|
QString hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(Shared::ClientId)
|
||||||
|
|
||||||
|
QDataStream& operator << (QDataStream& stream, const Shared::ClientId& info);
|
||||||
|
QDataStream& operator >> (QDataStream& stream, Shared::ClientId& info);
|
||||||
|
|
||||||
|
#endif // SHARED_CLIENTID_H
|
116
shared/clientinfo.cpp
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
// 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 "clientinfo.h"
|
||||||
|
|
||||||
|
const std::map<QString, QCryptographicHash::Algorithm> Shared::ClientInfo::hashes = {
|
||||||
|
//md2 is missing
|
||||||
|
{"md5", QCryptographicHash::Md5},
|
||||||
|
{"sha-1", QCryptographicHash::Sha1},
|
||||||
|
{"sha-224", QCryptographicHash::Sha224},
|
||||||
|
{"sha-256", QCryptographicHash::Sha256},
|
||||||
|
{"sha-384", QCryptographicHash::Sha384},
|
||||||
|
{"sha-512", QCryptographicHash::Sha512},
|
||||||
|
//shake128 is missing
|
||||||
|
//shake256 is missing
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
Shared::ClientInfo::ClientInfo():
|
||||||
|
identities(),
|
||||||
|
extensions(),
|
||||||
|
id(),
|
||||||
|
specificPresence() {}
|
||||||
|
|
||||||
|
Shared::ClientInfo::ClientInfo(const QString& p_node, const QString& p_ver, const QString& p_hash) :
|
||||||
|
identities(),
|
||||||
|
extensions(),
|
||||||
|
id(p_node, p_ver, p_hash),
|
||||||
|
specificPresence() {}
|
||||||
|
|
||||||
|
Shared::ClientInfo::ClientInfo(const Shared::ClientId& p_id) :
|
||||||
|
identities(),
|
||||||
|
extensions(),
|
||||||
|
id(p_id),
|
||||||
|
specificPresence() {}
|
||||||
|
|
||||||
|
QString Shared::ClientInfo::getId() const {
|
||||||
|
return id.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
QDataStream & Shared::ClientInfo::operator >> (QDataStream& stream) const {
|
||||||
|
stream << id;
|
||||||
|
stream << (quint8)identities.size();
|
||||||
|
for (const Shared::Identity& identity : identities) {
|
||||||
|
stream << identity;
|
||||||
|
}
|
||||||
|
stream << (quint8)extensions.size();
|
||||||
|
for (const QString& ext : extensions) {
|
||||||
|
stream << ext;
|
||||||
|
}
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDataStream & Shared::ClientInfo::operator << (QDataStream& stream) {
|
||||||
|
stream >> id;
|
||||||
|
|
||||||
|
quint8 size;
|
||||||
|
stream >> size;
|
||||||
|
for (quint8 i = 0; i < size; ++i) {
|
||||||
|
Shared::Identity identity;
|
||||||
|
stream >> identity;
|
||||||
|
identities.insert(identity);
|
||||||
|
}
|
||||||
|
|
||||||
|
stream >> size;
|
||||||
|
for (quint8 i = 0; i < size; ++i) {
|
||||||
|
QString ext;
|
||||||
|
stream >> ext;
|
||||||
|
extensions.insert(ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Shared::ClientInfo::valid() const {
|
||||||
|
std::map<QString, QCryptographicHash::Algorithm>::const_iterator itr = hashes.find(id.hash);
|
||||||
|
if (itr == hashes.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QCryptographicHash calc(itr->second);
|
||||||
|
QString validationString = "";
|
||||||
|
for (const Identity& identity : identities) {
|
||||||
|
calc.addData((identity.category + "/" + identity.type + "/" + identity.language + "/" + identity.name + "<").toUtf8());
|
||||||
|
}
|
||||||
|
for (const QString& ext : extensions) {
|
||||||
|
calc.addData((ext + "<").toUtf8());
|
||||||
|
}
|
||||||
|
|
||||||
|
QString result = calc.result().toBase64();
|
||||||
|
|
||||||
|
return result == id.verification;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDataStream& operator << (QDataStream& stream, const Shared::ClientInfo& info) {
|
||||||
|
info >> stream;
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
QDataStream& operator >> (QDataStream& stream, Shared::ClientInfo& info) {
|
||||||
|
info << stream;
|
||||||
|
return stream;
|
||||||
|
}
|
58
shared/clientinfo.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
#ifndef SHARED_CLIENTINFO_H
|
||||||
|
#define SHARED_CLIENTINFO_H
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include <QDataStream>
|
||||||
|
#include <QString>
|
||||||
|
#include <QCryptographicHash>
|
||||||
|
|
||||||
|
#include <shared/identity.h>
|
||||||
|
#include <shared/clientid.h>
|
||||||
|
|
||||||
|
namespace Shared {
|
||||||
|
|
||||||
|
class ClientInfo {
|
||||||
|
public:
|
||||||
|
ClientInfo();
|
||||||
|
ClientInfo(const ClientId& id);
|
||||||
|
ClientInfo(const QString& node, const QString& verification, const QString& hash);
|
||||||
|
|
||||||
|
QString getId() const;
|
||||||
|
bool valid() const;
|
||||||
|
|
||||||
|
QDataStream& operator << (QDataStream& stream);
|
||||||
|
QDataStream& operator >> (QDataStream& stream) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::set<Identity> identities;
|
||||||
|
std::set<QString> extensions;
|
||||||
|
ClientId id;
|
||||||
|
QString specificPresence;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const std::map<QString, QCryptographicHash::Algorithm> hashes;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QDataStream& operator << (QDataStream& stream, const Shared::ClientInfo& info);
|
||||||
|
QDataStream& operator >> (QDataStream& stream, Shared::ClientInfo& info);
|
||||||
|
|
||||||
|
#endif // SHARED_CLIENTINFO_H
|
24
shared/defines.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SHARED_DEFINES_H
|
||||||
|
#define SHARED_DEFINES_H
|
||||||
|
|
||||||
|
#define SHARED_UNUSED(x) (void)(x)
|
||||||
|
|
||||||
|
#endif
|
@ -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 SHARED_ENUMS_H
|
#pragma once
|
||||||
#define SHARED_ENUMS_H
|
|
||||||
|
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
|
||||||
@ -29,12 +28,13 @@ Q_NAMESPACE
|
|||||||
|
|
||||||
enum class ConnectionState {
|
enum class ConnectionState {
|
||||||
disconnected,
|
disconnected,
|
||||||
|
scheduled,
|
||||||
connecting,
|
connecting,
|
||||||
connected,
|
connected,
|
||||||
error
|
error
|
||||||
};
|
};
|
||||||
Q_ENUM_NS(ConnectionState)
|
Q_ENUM_NS(ConnectionState)
|
||||||
static const std::deque<QString> connectionStateThemeIcons = {"state-offline", "state-sync", "state-ok", "state-error"};
|
static const std::deque<QString> connectionStateThemeIcons = {"state-offline", "state-sync", "state-sync", "state-ok", "state-error"};
|
||||||
static const ConnectionState ConnectionStateHighest = ConnectionState::error;
|
static const ConnectionState ConnectionStateHighest = ConnectionState::error;
|
||||||
static const ConnectionState ConnectionStateLowest = ConnectionState::disconnected;
|
static const ConnectionState ConnectionStateLowest = ConnectionState::disconnected;
|
||||||
|
|
||||||
@ -117,5 +117,63 @@ Q_ENUM_NS(AccountPassword)
|
|||||||
static const AccountPassword AccountPasswordHighest = AccountPassword::kwallet;
|
static const AccountPassword AccountPasswordHighest = AccountPassword::kwallet;
|
||||||
static const AccountPassword AccountPasswordLowest = AccountPassword::plain;
|
static const AccountPassword AccountPasswordLowest = AccountPassword::plain;
|
||||||
|
|
||||||
|
enum class EntryType {
|
||||||
|
none,
|
||||||
|
ownAccount,
|
||||||
|
contact,
|
||||||
|
conference,
|
||||||
|
presence,
|
||||||
|
participant
|
||||||
|
};
|
||||||
|
Q_ENUM_NS(EntryType)
|
||||||
|
static const EntryType EntryTypeHighest = EntryType::participant;
|
||||||
|
static const EntryType EntryTypeLowest = EntryType::none;
|
||||||
|
|
||||||
|
enum class Support {
|
||||||
|
unknown,
|
||||||
|
supported,
|
||||||
|
unsupported
|
||||||
|
};
|
||||||
|
Q_ENUM_NS(Support)
|
||||||
|
|
||||||
|
enum class Possible {
|
||||||
|
unknown,
|
||||||
|
discovering,
|
||||||
|
present,
|
||||||
|
abscent
|
||||||
|
};
|
||||||
|
Q_ENUM_NS(Possible)
|
||||||
|
|
||||||
|
enum class TrustLevel {
|
||||||
|
/// The key's trust is not decided.
|
||||||
|
undecided,
|
||||||
|
/// The key is automatically distrusted (e.g., by the security policy TOAKAFA).
|
||||||
|
/// \see SecurityPolicy
|
||||||
|
automaticallyDistrusted,
|
||||||
|
/// The key is manually distrusted (e.g., by clicking a button or \xep{0450, Automatic Trust
|
||||||
|
/// Management (ATM)}).
|
||||||
|
manuallyDistrusted,
|
||||||
|
/// The key is automatically trusted (e.g., by the client for all keys of a bare JID until one
|
||||||
|
/// of it is authenticated).
|
||||||
|
automaticallyTrusted,
|
||||||
|
/// The key is manually trusted (e.g., by clicking a button).
|
||||||
|
manuallyTrusted,
|
||||||
|
/// The key is authenticated (e.g., by QR code scanning or \xep{0450, Automatic Trust
|
||||||
|
/// Management (ATM)}).
|
||||||
|
authenticated
|
||||||
|
};
|
||||||
|
Q_ENUM_NS(TrustLevel)
|
||||||
|
static const TrustLevel TrustLevelHighest = TrustLevel::undecided;
|
||||||
|
static const TrustLevel TrustLevelLowest = TrustLevel::authenticated;
|
||||||
|
|
||||||
|
enum class EncryptionProtocol {
|
||||||
|
none,
|
||||||
|
omemo,
|
||||||
|
omemo1,
|
||||||
|
omemo2
|
||||||
|
};
|
||||||
|
Q_ENUM_NS(EncryptionProtocol)
|
||||||
|
static const EncryptionProtocol EncryptionProtocolHighest = EncryptionProtocol::none;
|
||||||
|
static const EncryptionProtocol EncryptionProtocolLowest = EncryptionProtocol::omemo2;
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif // SHARED_ENUMS_H
|
|
||||||
|
@ -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 EXCEPTION_H
|
#pragma once
|
||||||
#define EXCEPTION_H
|
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -36,5 +35,3 @@ namespace Utils
|
|||||||
const char* what() const noexcept( true );
|
const char* what() const noexcept( true );
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // EXCEPTION_H
|
|
||||||
|
28
shared/field.cpp
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// 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 "field.h"
|
||||||
|
|
||||||
|
Shared::Field::Field(Shared::Field::Type fieldTtype):
|
||||||
|
type(fieldTtype),
|
||||||
|
key(),
|
||||||
|
label(),
|
||||||
|
description(),
|
||||||
|
required(false),
|
||||||
|
options(),
|
||||||
|
value()
|
||||||
|
{
|
||||||
|
}
|
61
shared/field.h
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
#ifndef SHARED_FIELD_H
|
||||||
|
#define SHARED_FIELD_H
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include <QVariant>
|
||||||
|
|
||||||
|
namespace Shared {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @todo write docs
|
||||||
|
*/
|
||||||
|
class Field
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class Type {
|
||||||
|
boolean,
|
||||||
|
fixed,
|
||||||
|
hidden,
|
||||||
|
jidMultiple,
|
||||||
|
jidSingle,
|
||||||
|
listMultiple,
|
||||||
|
listSingle,
|
||||||
|
textMultiple,
|
||||||
|
textPrivate,
|
||||||
|
textSingle
|
||||||
|
};
|
||||||
|
|
||||||
|
Field(Type fieldType);
|
||||||
|
|
||||||
|
public:
|
||||||
|
const Type type;
|
||||||
|
QString key;
|
||||||
|
QString label;
|
||||||
|
QString description;
|
||||||
|
bool required;
|
||||||
|
std::list<std::pair<QString, QString>> options;
|
||||||
|
QVariant value;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // SHARED_FIELD_H
|
23
shared/form.cpp
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// 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 "form.h"
|
||||||
|
|
||||||
|
Shared::Form::Form(Shared::Form::Type formType):
|
||||||
|
type(formType),
|
||||||
|
title(),
|
||||||
|
instructions(),
|
||||||
|
fields() {}
|
48
shared/form.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
#ifndef SHARED_FORM_H
|
||||||
|
#define SHARED_FORM_H
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
#include <shared/field.h>
|
||||||
|
|
||||||
|
namespace Shared {
|
||||||
|
|
||||||
|
class Form
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class Type {
|
||||||
|
none,
|
||||||
|
form,
|
||||||
|
submit,
|
||||||
|
cancel,
|
||||||
|
result
|
||||||
|
};
|
||||||
|
|
||||||
|
Form(Type formType);
|
||||||
|
|
||||||
|
public:
|
||||||
|
const Type type;
|
||||||
|
QString title;
|
||||||
|
QString instructions;
|
||||||
|
std::list<Field> fields;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // SHARED_FORM_H
|
@ -17,9 +17,34 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
|
#include <QFontDatabase>
|
||||||
|
|
||||||
#include "enums.h"
|
#include "enums.h"
|
||||||
#include "ui/models/roster.h"
|
#include "ui/models/roster.h"
|
||||||
|
#ifdef WITH_OMEMO
|
||||||
|
constexpr bool OMEMO_SUPPORT = true;
|
||||||
|
#else
|
||||||
|
constexpr bool OMEMO_SUPPORT = false
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QFont getFont (QFontDatabase::SystemFont type, bool bold = false, bool italic = false, qreal factor = 1.0) {
|
||||||
|
QFont font = QFontDatabase::systemFont(type);
|
||||||
|
if (bold)
|
||||||
|
font.setBold(true);
|
||||||
|
if (italic)
|
||||||
|
font.setItalic(true);
|
||||||
|
|
||||||
|
if (factor != 1.0) {
|
||||||
|
float ps = font.pointSizeF();
|
||||||
|
if (ps != -1) {
|
||||||
|
font.setPointSizeF(ps * factor);
|
||||||
|
} else {
|
||||||
|
font.setPointSize(font.pointSize() * factor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
|
||||||
Shared::Global* Shared::Global::instance = 0;
|
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"};
|
||||||
@ -37,64 +62,92 @@ Shared::Global::ColorSchemeName Shared::Global::colorSchemeName = 0;
|
|||||||
Shared::Global::CreatePalette Shared::Global::createPalette = 0;
|
Shared::Global::CreatePalette Shared::Global::createPalette = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Shared::Global::Global():
|
Shared::Global::Global():
|
||||||
availability({
|
availability({
|
||||||
tr("Online", "Availability"),
|
QCoreApplication::translate("Global", "Online", "Availability"),
|
||||||
tr("Away", "Availability"),
|
QCoreApplication::translate("Global", "Away", "Availability"),
|
||||||
tr("Absent", "Availability"),
|
QCoreApplication::translate("Global", "Absent", "Availability"),
|
||||||
tr("Busy", "Availability"),
|
QCoreApplication::translate("Global", "Busy", "Availability"),
|
||||||
tr("Chatty", "Availability"),
|
QCoreApplication::translate("Global", "Chatty", "Availability"),
|
||||||
tr("Invisible", "Availability"),
|
QCoreApplication::translate("Global", "Invisible", "Availability"),
|
||||||
tr("Offline", "Availability")
|
QCoreApplication::translate("Global", "Offline", "Availability")
|
||||||
}),
|
}),
|
||||||
connectionState({
|
connectionState({
|
||||||
tr("Disconnected", "ConnectionState"),
|
QCoreApplication::translate("Global", "Disconnected", "ConnectionState"),
|
||||||
tr("Connecting", "ConnectionState"),
|
QCoreApplication::translate("Global", "Scheduled", "ConnectionState"),
|
||||||
tr("Connected", "ConnectionState"),
|
QCoreApplication::translate("Global", "Connecting", "ConnectionState"),
|
||||||
tr("Error", "ConnectionState")
|
QCoreApplication::translate("Global", "Connected", "ConnectionState"),
|
||||||
|
QCoreApplication::translate("Global", "Error", "ConnectionState")
|
||||||
}),
|
}),
|
||||||
subscriptionState({
|
subscriptionState({
|
||||||
tr("None", "SubscriptionState"),
|
QCoreApplication::translate("Global", "None", "SubscriptionState"),
|
||||||
tr("From", "SubscriptionState"),
|
QCoreApplication::translate("Global", "From", "SubscriptionState"),
|
||||||
tr("To", "SubscriptionState"),
|
QCoreApplication::translate("Global", "To", "SubscriptionState"),
|
||||||
tr("Both", "SubscriptionState"),
|
QCoreApplication::translate("Global", "Both", "SubscriptionState"),
|
||||||
tr("Unknown", "SubscriptionState")
|
QCoreApplication::translate("Global", "Unknown", "SubscriptionState")
|
||||||
}),
|
}),
|
||||||
affiliation({
|
affiliation({
|
||||||
tr("Unspecified", "Affiliation"),
|
QCoreApplication::translate("Global", "Unspecified", "Affiliation"),
|
||||||
tr("Outcast", "Affiliation"),
|
QCoreApplication::translate("Global", "Outcast", "Affiliation"),
|
||||||
tr("Nobody", "Affiliation"),
|
QCoreApplication::translate("Global", "Nobody", "Affiliation"),
|
||||||
tr("Member", "Affiliation"),
|
QCoreApplication::translate("Global", "Member", "Affiliation"),
|
||||||
tr("Admin", "Affiliation"),
|
QCoreApplication::translate("Global", "Admin", "Affiliation"),
|
||||||
tr("Owner", "Affiliation")
|
QCoreApplication::translate("Global", "Owner", "Affiliation")
|
||||||
}),
|
}),
|
||||||
role({
|
role({
|
||||||
tr("Unspecified", "Role"),
|
QCoreApplication::translate("Global", "Unspecified", "Role"),
|
||||||
tr("Nobody", "Role"),
|
QCoreApplication::translate("Global", "Nobody", "Role"),
|
||||||
tr("Visitor", "Role"),
|
QCoreApplication::translate("Global", "Visitor", "Role"),
|
||||||
tr("Participant", "Role"),
|
QCoreApplication::translate("Global", "Participant", "Role"),
|
||||||
tr("Moderator", "Role")
|
QCoreApplication::translate("Global", "Moderator", "Role")
|
||||||
}),
|
}),
|
||||||
messageState({
|
messageState({
|
||||||
tr("Pending", "MessageState"),
|
QCoreApplication::translate("Global", "Pending", "MessageState"),
|
||||||
tr("Sent", "MessageState"),
|
QCoreApplication::translate("Global", "Sent", "MessageState"),
|
||||||
tr("Delivered", "MessageState"),
|
QCoreApplication::translate("Global", "Delivered", "MessageState"),
|
||||||
tr("Error", "MessageState")
|
QCoreApplication::translate("Global", "Error", "MessageState")
|
||||||
}),
|
}),
|
||||||
accountPassword({
|
accountPassword({
|
||||||
tr("Plain", "AccountPassword"),
|
QCoreApplication::translate("Global", "Plain", "AccountPassword"),
|
||||||
tr("Jammed", "AccountPassword"),
|
QCoreApplication::translate("Global", "Jammed", "AccountPassword"),
|
||||||
tr("Always Ask", "AccountPassword"),
|
QCoreApplication::translate("Global", "Always Ask", "AccountPassword"),
|
||||||
tr("KWallet", "AccountPassword")
|
QCoreApplication::translate("Global", "KWallet", "AccountPassword")
|
||||||
|
}),
|
||||||
|
trustLevel({
|
||||||
|
QCoreApplication::translate("Global", "Undecided", "TrustLevel"),
|
||||||
|
QCoreApplication::translate("Global", "Automatically distrusted", "TrustLevel"),
|
||||||
|
QCoreApplication::translate("Global", "Manually distrusted", "TrustLevel"),
|
||||||
|
QCoreApplication::translate("Global", "Automatically trusted", "TrustLevel"),
|
||||||
|
QCoreApplication::translate("Global", "Manually trusted", "TrustLevel"),
|
||||||
|
QCoreApplication::translate("Global", "Authenticated", "TrustLevel")
|
||||||
|
}),
|
||||||
|
encryptionProtocols({
|
||||||
|
QCoreApplication::translate("Global", "None", "EncryptionProtocol"),
|
||||||
|
QCoreApplication::translate("Global", "OMEMO 0", "EncryptionProtocol"),
|
||||||
|
QCoreApplication::translate("Global", "OMEMO 1", "EncryptionProtocol"),
|
||||||
|
QCoreApplication::translate("Global", "OMEMO 2", "EncryptionProtocol")
|
||||||
}),
|
}),
|
||||||
accountPasswordDescription({
|
accountPasswordDescription({
|
||||||
tr("Your password is going to be stored in config file in plain text", "AccountPasswordDescription"),
|
QCoreApplication::translate("Global", "Your password is going to be stored in config file in plain text", "AccountPasswordDescription"),
|
||||||
tr("Your password is going to be stored in config file but jammed with constant encryption key you can find in program source code. It might look like encryption but it's not", "AccountPasswordDescription"),
|
QCoreApplication::translate("Global", "Your password is going to be stored in config file but jammed with constant encryption key you can find in program source code. It might look like encryption but it's not", "AccountPasswordDescription"),
|
||||||
tr("Squawk is going to query you for the password on every start of the program", "AccountPasswordDescription"),
|
QCoreApplication::translate("Global", "Squawk is going to query you for the password on every start of the program", "AccountPasswordDescription"),
|
||||||
tr("Your password is going to be stored in KDE wallet storage (KWallet). You're going to be queried for permissions", "AccountPasswordDescription")
|
QCoreApplication::translate("Global", "Your password is going to be stored in KDE wallet storage (KWallet). You're going to be queried for permissions", "AccountPasswordDescription")
|
||||||
}),
|
}),
|
||||||
defaultSystemStyle(QApplication::style()->objectName()),
|
defaultSystemStyle(QApplication::style()->objectName()),
|
||||||
defaultSystemPalette(QApplication::palette()),
|
defaultSystemPalette(QApplication::palette()),
|
||||||
|
omemoSupport(OMEMO_SUPPORT),
|
||||||
|
defaultFont(QFontDatabase::systemFont(QFontDatabase::GeneralFont)),
|
||||||
|
monospaceFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)),
|
||||||
|
smallFont(getFont(QFontDatabase::SmallestReadableFont, false, true)),
|
||||||
|
headerFont(getFont(QFontDatabase::TitleFont, true, false, 1.1)),
|
||||||
|
titleFont(getFont(QFontDatabase::TitleFont, true, false, 1.3)),
|
||||||
|
defaultFontMetrics(defaultFont),
|
||||||
|
monospaceMetrics(monospaceFont),
|
||||||
|
smallFontMetrics(smallFont),
|
||||||
|
headerFontMetrics(headerFont),
|
||||||
|
titleFontMetrics(titleFont),
|
||||||
pluginSupport({
|
pluginSupport({
|
||||||
{"KWallet", false},
|
{"KWallet", false},
|
||||||
{"openFileManagerWindowJob", false},
|
{"openFileManagerWindowJob", false},
|
||||||
@ -181,56 +234,54 @@ Shared::Global::FileInfo Shared::Global::getFileInfo(const QString& path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Shared::Global * Shared::Global::getInstance()
|
Shared::Global * Shared::Global::getInstance() {
|
||||||
{
|
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Shared::Global::getName(Message::State rl)
|
QString Shared::Global::getName(Message::State rl) {
|
||||||
{
|
|
||||||
return instance->messageState[static_cast<int>(rl)];
|
return instance->messageState[static_cast<int>(rl)];
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Shared::Global::getName(Shared::Affiliation af)
|
QString Shared::Global::getName(Shared::Affiliation af) {
|
||||||
{
|
|
||||||
return instance->affiliation[static_cast<int>(af)];
|
return instance->affiliation[static_cast<int>(af)];
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Shared::Global::getName(Shared::Availability av)
|
QString Shared::Global::getName(Shared::Availability av) {
|
||||||
{
|
|
||||||
return instance->availability[static_cast<int>(av)];
|
return instance->availability[static_cast<int>(av)];
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Shared::Global::getName(Shared::ConnectionState cs)
|
QString Shared::Global::getName(Shared::ConnectionState cs) {
|
||||||
{
|
|
||||||
return instance->connectionState[static_cast<int>(cs)];
|
return instance->connectionState[static_cast<int>(cs)];
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Shared::Global::getName(Shared::Role rl)
|
QString Shared::Global::getName(Shared::Role rl) {
|
||||||
{
|
|
||||||
return instance->role[static_cast<int>(rl)];
|
return instance->role[static_cast<int>(rl)];
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Shared::Global::getName(Shared::SubscriptionState ss)
|
QString Shared::Global::getName(Shared::SubscriptionState ss) {
|
||||||
{
|
|
||||||
return instance->subscriptionState[static_cast<int>(ss)];
|
return instance->subscriptionState[static_cast<int>(ss)];
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Shared::Global::getName(Shared::AccountPassword ap)
|
QString Shared::Global::getName(Shared::AccountPassword ap) {
|
||||||
{
|
|
||||||
return instance->accountPassword[static_cast<int>(ap)];
|
return instance->accountPassword[static_cast<int>(ap)];
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shared::Global::setSupported(const QString& pluginName, bool support)
|
QString Shared::Global::getName(Shared::TrustLevel tl) {
|
||||||
{
|
return instance->trustLevel[static_cast<int>(tl)];
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Shared::Global::getName(EncryptionProtocol ep) {
|
||||||
|
return instance->encryptionProtocols[static_cast<int>(ep)];
|
||||||
|
}
|
||||||
|
|
||||||
|
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->pluginSupport.find(pluginName);
|
||||||
if (itr != instance->pluginSupport.end()) {
|
if (itr != instance->pluginSupport.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->pluginSupport.find(pluginName);
|
||||||
if (itr != instance->pluginSupport.end()) {
|
if (itr != instance->pluginSupport.end()) {
|
||||||
return itr->second;
|
return itr->second;
|
||||||
@ -238,8 +289,7 @@ bool Shared::Global::supported(const QString& pluginName)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Shared::Global::getDescription(Shared::AccountPassword ap)
|
QString Shared::Global::getDescription(Shared::AccountPassword ap) {
|
||||||
{
|
|
||||||
return instance->accountPasswordDescription[static_cast<int>(ap)];
|
return instance->accountPasswordDescription[static_cast<int>(ap)];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,8 +355,7 @@ void Shared::Global::highlightInFileManager(const QString& path)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QIcon Shared::Global::createThemePreview(const QString& path)
|
QIcon Shared::Global::createThemePreview(const QString& path) {
|
||||||
{
|
|
||||||
if (supported("colorSchemeTools")) {
|
if (supported("colorSchemeTools")) {
|
||||||
QIcon* icon = createPreview(path);
|
QIcon* icon = createPreview(path);
|
||||||
QIcon localIcon = *icon;
|
QIcon localIcon = *icon;
|
||||||
@ -317,8 +366,7 @@ QIcon Shared::Global::createThemePreview(const QString& path)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Shared::Global::getColorSchemeName(const QString& path)
|
QString Shared::Global::getColorSchemeName(const QString& path) {
|
||||||
{
|
|
||||||
if (supported("colorSchemeTools")) {
|
if (supported("colorSchemeTools")) {
|
||||||
QString res;
|
QString res;
|
||||||
colorSchemeName(path, res);
|
colorSchemeName(path, res);
|
||||||
@ -328,8 +376,7 @@ QString Shared::Global::getColorSchemeName(const QString& path)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shared::Global::setTheme(const QString& path)
|
void Shared::Global::setTheme(const QString& path) {
|
||||||
{
|
|
||||||
if (supported("colorSchemeTools")) {
|
if (supported("colorSchemeTools")) {
|
||||||
if (path.toLower() == "system") {
|
if (path.toLower() == "system") {
|
||||||
QApplication::setPalette(getInstance()->defaultSystemPalette);
|
QApplication::setPalette(getInstance()->defaultSystemPalette);
|
||||||
@ -341,8 +388,7 @@ void Shared::Global::setTheme(const QString& path)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
@ -354,7 +400,7 @@ void Shared::Global::setStyle(const QString& style)
|
|||||||
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); \
|
||||||
@ -370,3 +416,5 @@ FROM_INT_INPL(Shared::SubscriptionState)
|
|||||||
FROM_INT_INPL(Shared::AccountPassword)
|
FROM_INT_INPL(Shared::AccountPassword)
|
||||||
FROM_INT_INPL(Shared::Avatar)
|
FROM_INT_INPL(Shared::Avatar)
|
||||||
FROM_INT_INPL(Shared::Availability)
|
FROM_INT_INPL(Shared::Availability)
|
||||||
|
FROM_INT_INPL(Shared::TrustLevel)
|
||||||
|
FROM_INT_INPL(Shared::EncryptionProtocol)
|
||||||
|