89 Commits

Author SHA1 Message Date
Blue 1706b93b59 Merge pull request 'Add Brazilian Portuguese translations' (#49) from brunofontes/squawk:ptBR_translations into master 3 days ago
Bruno F. Fontes 87c216b491
Add Brazilian Portuguese translations 2 months ago
Blue ef1a9846bf found a way to avoid requesting all the MUCs history alltogether on startup 1 year ago
Blue 3a120c773a reconnection issues 1 year ago
Blue 5f64321c2a fix compilation on older qt versions 1 year ago
Blue a543eb1aef 0.1.5 1 year ago
Blue 480c78cf61 non lower cased jids error handled 1 year ago
Blue 0dcfc5eedc some better cleanup and restore state on connect disconnect, workaround for that wired undefined condition error on every other reconnection 1 year ago
Blue 87426ee20f account refactoring 1 year ago
Blue 20bcae5ab2 finally history works in mucs 1 year ago
Blue 6b65910ded stanzaId based muc archive request, account object refactoring 1 year ago
Blue 9ca4aa29d4 started account refactoring 1 year ago
Blue a625ecb47b Merge pull request 'rosterReferences' (#39) from rosterReferences into master 1 year ago
Blue 55ae5858b5 some workaround about disconnection segfault 1 year ago
Blue 9c855553c5 referencing seems to be working now 1 year ago
Blue 83a2e6af85 first prototype 1 year ago
Blue 494afcf2b5 initial class reference 1 year ago
Blue a8698cc94f minor bugfixes 1 year ago
Blue b50ce146b8 attaching messages fix, bad alloc fix 1 year ago
Blue 6657dc79ce qxmpp bump, ifdef to assemble on lower versions 1 year ago
Blue bdca0aa6b1 Merge pull request 'safePasswords' (#36) from safePasswords into master 1 year ago
Blue cb44b12a7e 0.1.4 kwallet optimisation related fix, DnD files into convs, visual fixes 1 year ago
Blue 21c7d65027 offline avatars in mucs 1 year ago
Blue 29c7d31c89 context menu now doesn't select items, just temporarily, statuses and messahes html wrapping fix 1 year ago
Blue a77dfd191a single window mode 1 year ago
Blue b95028e33e testing, ability to build without kwallet, translations, disabling unsupported storage types in combobox 1 year ago
Blue 543538fc56 first working prototype of dynamically loaded kwallet storage 1 year ago
Blue 7ce27d1c11 pasword storing options: jammed an alwaysAsk, external lib for password jamming, changelog 1 year ago
Blue 95f0d4008a minor fix about updating muc avatars 1 year ago
Blue 3477226367 first moves to safe pasword storing, preparing the structure 1 year ago
Blue ddfb3419cc Shared namespace refactoring, enum class refactoring, going offline related crash fix 1 year ago
Blue b309100f99 0.1.3 release 2 years ago
Blue c793f56647 a little bit of restyling, now the integration with transparent themes is supposed to be better 2 years ago
Blue ff2c9831cf corrected messages now are supposed to display correctly 2 years ago
Blue fe1ae8567a Message receipt manager not takes care of the message reception, switched on embedded reconnect 2 years ago
Blue 57d6e3adab Message error handling as state, errorText to store, fake ID for message without 2 years ago
Blue 91cc851bfc delivery statuses now actually mean something for MUC messages 2 years ago
Blue 6d1b83d0f8 ui logick of changing message, not connected yet 2 years ago
Blue ed56cca2e7 some visual tweaks, moving on message delivery statuses 2 years ago
Blue a4136ff9fe progress spinner fix, new lines in messages now display again 2 years ago
Blue 565449f176 bug with selection, some right padding to the avatars 2 years ago
Blue 626227db93 file comment fix, avatar dropping bug fix, url detection bug fix 2 years ago
Blue 13a1970047 a method for setting states to messages 2 years ago
Blue ad1977f05f badges and screenshots in readme typo 2 years ago
Blue 0a4c4aa042 badges and screenshots in readme typo 2 years ago
Blue 5e7c247bb4 badges and screenshots in readme 2 years ago
Blue 5a59d54b18 first thoughts on message states 2 years ago
Blue 52efc2b1a4 now we have avatars in muc chats 2 years ago
Blue 55703c2007 muc participant avatars 2 years ago
Blue efc90e18c3 verion bump 2 years ago
Blue 3e594c7e13 connectivity, roster position size and state, expanded anccounts and groups restoration with the settings 2 years ago
Blue 0bcfd779b8 some bugs and corner cases 2 years ago
Blue dd62f84acc pal avatars in one on one dialogs 2 years ago
Blue f13b43d38b some bug fixes, initial work on avatars in dialog windows 2 years ago
Blue 867c3a18e9 avatars for mucs, some tooltip tweaks 2 years ago
Blue f367502b8e Merge branch 'master' of git.macaw.me:blue/squawk 2 years ago
Blue fe27955689 uploading multiple messages fix, some warnings fix 2 years ago
Blue 0c33d81c59 insignifican fixes about urls parsing 2 years ago
Blue 0cb25a25cf uploading multiple messages fix, some warnings fix 2 years ago
Blue 09a946c204 Merge branch 'fileUpload' of blue/squawk into master 2 years ago
Blue ae3a1c97e3 uploading message destruction bug, optimisations for release warnings for debug, packaging, readme 2 years ago
Blue 326eef864b some fixes about uploading, some error handling 2 years ago
Blue 166a7ac83a first working prototype of file upload 2 years ago
Blue a6e48599aa some progress on upload 2 years ago
Blue 3f710e26d0 some more work about uploading, not done yet 2 years ago
Blue 09749bac51 Merge branch 'master' into fileUpload 2 years ago
Blue 0b78470aaa Merge branch 'vCard' of blue/squawk into master 2 years ago
Blue dfa4d10c36 some VCard polishing, missing icons and translations 2 years ago
Blue 2c13f0d77c phones now also saveble 2 years ago
Blue c1c1de1b7b backend adapter for vCard phones list 2 years ago
Blue 5bbacad84a VCard: email list now displays and stores on server vcard 2 years ago
Blue 0b57e6a77f Refactoring of signal/slots connection to new qt syntax 2 years ago
Blue 9d491e9e93 deprecation fix about qxmpp, beginning of adding email addresses in VCards 2 years ago
Blue c067835b00 button to add addresses phones and emails, yet dummy 2 years ago
Blue e924715a57 progress for VCard widget, date of receiving 2 years ago
Blue f3515f1104 refactored progress 2 years ago
Blue 566fc1f2fb new fallback icons, new fields in vCard, fix about recreation new avatar on each request 2 years ago
Blue 36c71968bc basic avatar/vcard changes uploads and roster reaction 2 years ago
Blue 652381b067 changing avatar in local vcard, no uploading yet 2 years ago
Blue 2a37f36b83 first primitive vcard in graphic interface 2 years ago
Blue c4d22c9c14 some methods to cVard 2 years ago
Blue e7be046e9f vcard ui file 2 years ago
Blue d050cd82dd some lines to vCard object 2 years ago
Blue 46e74ad5e8 initial vCard class, signal-slots refactoring 2 years ago
Blue dc1ec1c9d4 receiving account owner vCard, displaying avatars in roster 2 years ago
Blue 64e33b6139 receiving avatars, generating missing avatars, storing state of avatars, global color palette 2 years ago
Blue c678a790e5 some more methods for archive to store avatar states 2 years ago
Blue 323a549eca got rid of organization name, made building with system qxmpp by default 2 years ago
Blue 7c32056918 working on file upload 2 years ago
  1. 98
      CHANGELOG.md
  2. 82
      CMakeLists.txt
  3. 62
      README.md
  4. 18
      core/CMakeLists.txt
  5. 1398
      core/account.cpp
  6. 143
      core/account.h
  7. 275
      core/adapterFuctions.cpp
  8. 744
      core/archive.cpp
  9. 67
      core/archive.h
  10. 205
      core/conference.cpp
  11. 17
      core/conference.h
  12. 32
      core/contact.cpp
  13. 1
      core/contact.h
  14. 371
      core/handlers/messagehandler.cpp
  15. 76
      core/handlers/messagehandler.h
  16. 599
      core/handlers/rosterhandler.cpp
  17. 115
      core/handlers/rosterhandler.h
  18. 471
      core/networkaccess.cpp
  19. 27
      core/networkaccess.h
  20. 37
      core/passwordStorageEngines/CMakeLists.txt
  21. 230
      core/passwordStorageEngines/kwallet.cpp
  22. 112
      core/passwordStorageEngines/kwallet.h
  23. 33
      core/passwordStorageEngines/wrappers/kwallet.cpp
  24. 302
      core/rosteritem.cpp
  25. 34
      core/rosteritem.h
  26. 400
      core/squawk.cpp
  27. 67
      core/squawk.h
  28. 29
      core/storage.cpp
  29. 1
      core/storage.h
  30. 2
      external/qxmpp
  31. 16
      external/simpleCrypt/CMakeLists.txt
  32. 248
      external/simpleCrypt/simplecrypt.cpp
  33. 226
      external/simpleCrypt/simplecrypt.h
  34. 148
      main.cpp
  35. 2
      order.h
  36. 20
      packaging/Archlinux/PKGBUILD
  37. 2
      packaging/squawk.desktop
  38. 14
      resources/images/fallback/dark/big/add.svg
  39. 14
      resources/images/fallback/dark/big/copy.svg
  40. 14
      resources/images/fallback/dark/big/edit-rename.svg
  41. 14
      resources/images/fallback/dark/big/favorite.svg
  42. 14
      resources/images/fallback/dark/big/group-new.svg
  43. 14
      resources/images/fallback/dark/big/group.svg
  44. 14
      resources/images/fallback/dark/big/unfavorite.svg
  45. 14
      resources/images/fallback/dark/big/user-properties.svg
  46. 13
      resources/images/fallback/dark/small/add.svg
  47. 13
      resources/images/fallback/dark/small/copy.svg
  48. 13
      resources/images/fallback/dark/small/edit-rename.svg
  49. 14
      resources/images/fallback/dark/small/favorite.svg
  50. 13
      resources/images/fallback/dark/small/group-new.svg
  51. 13
      resources/images/fallback/dark/small/group.svg
  52. 14
      resources/images/fallback/dark/small/unfavorite.svg
  53. 13
      resources/images/fallback/dark/small/user-properties.svg
  54. 14
      resources/images/fallback/light/big/add.svg
  55. 14
      resources/images/fallback/light/big/copy.svg
  56. 14
      resources/images/fallback/light/big/edit-rename.svg
  57. 14
      resources/images/fallback/light/big/favorite.svg
  58. 14
      resources/images/fallback/light/big/group-new.svg
  59. 14
      resources/images/fallback/light/big/group.svg
  60. 14
      resources/images/fallback/light/big/unfavorite.svg
  61. 14
      resources/images/fallback/light/big/user-properties.svg
  62. 13
      resources/images/fallback/light/small/add.svg
  63. 13
      resources/images/fallback/light/small/copy.svg
  64. 13
      resources/images/fallback/light/small/edit-rename.svg
  65. 14
      resources/images/fallback/light/small/favorite.svg
  66. 13
      resources/images/fallback/light/small/group-new.svg
  67. 13
      resources/images/fallback/light/small/group.svg
  68. 14
      resources/images/fallback/light/small/unfavorite.svg
  69. 13
      resources/images/fallback/light/small/user-properties.svg
  70. 32
      resources/resources.qrc
  71. 29
      shared.h
  72. 121
      shared/enums.h
  73. 174
      shared/global.cpp
  74. 93
      shared/global.h
  75. 96
      shared/icons.cpp
  76. 177
      shared/icons.h
  77. 245
      shared/message.cpp
  78. 130
      shared/message.h
  79. 48
      shared/utils.cpp
  80. 74
      shared/utils.h
  81. 288
      shared/vcard.cpp
  82. 152
      shared/vcard.h
  83. 6
      signalcatcher.cpp
  84. 795
      translations/squawk.pt_BR.ts
  85. 527
      translations/squawk.ru.ts
  86. 14
      ui/CMakeLists.txt
  87. 12
      ui/models/abstractparticipant.cpp
  88. 6
      ui/models/abstractparticipant.h
  89. 89
      ui/models/account.cpp
  90. 20
      ui/models/account.h
  91. 6
      ui/models/accounts.cpp
  92. 157
      ui/models/contact.cpp
  93. 21
      ui/models/contact.h
  94. 46
      ui/models/group.cpp
  95. 6
      ui/models/group.h
  96. 173
      ui/models/item.cpp
  97. 32
      ui/models/item.h
  98. 64
      ui/models/participant.cpp
  99. 11
      ui/models/participant.h
  100. 14
      ui/models/presence.cpp

98
CHANGELOG.md

@ -0,0 +1,98 @@
# Changelog
## Squawk 0.2.0 (Unreleased)
### Bug fixes
- carbon copies switches on again after reconnection
- requesting the history of the current chat after reconnection
- global availability (in drop down list) gets restored after reconnection
- status icon in active chat changes when presence of the pen pal changes
### Improvements
- slightly reduced the traffic on the startup by not requesting history of all MUCs
## Squawk 0.1.5 (Jul 29, 2020)
### Bug fixes
- error with sending attached files to the conference
- error with building on lower versions of QXmpp
- error on the first access to the conference database
- quit now actually quits the app
- history in MUC now works properly and requests messages from server
- error with handling non lower cased JIDs
- some workaround upon reconnection
## Squawk 0.1.4 (Apr 14, 2020)
### New features
- message line now is in the same window with roster (new window dialog is still able to opened on context menu)
- several new ways to manage your account password:
- store it in plain text with the config (like it always was)
- store it in config jammed (local hashing with the constant seed, not secure at all but might look like it is)
- ask the account password on each program launch
- store it in KWallet which is dynamically loaded
- dragging into conversation now attach files
### Bug fixes
- never updating MUC avatars now get updated
- going offline related segfault fix
- statuses now behave better: they wrap if they don't fit, you can select them, you can follow links from there
- messages and statuses don't loose content if you use < ore > symbols
- now avatars of those who are not in the MUC right now but was also display next to the message
- fix crash on attempt to attach the same file for the second time
## Squawk 0.1.3 (Mar 31, 2020)
### New features
- delivery states for the messages
- delivery receipts now work for real
- avatars in conferences
- edited messages now display correctly
- restyling to get better look with different desktop themes
### Bug fixes
- clickable links now detects better
- fixed lost messages that came with no ID
- avatar related fixes
- message carbons now get turned on only if the server supports them
- progress spinner fix
- files in dialog now have better comment
## Squawk 0.1.2 (Dec 25, 2019)
### New features
- icons in roster for conferences
- pal avatar in dialog window
- avatars next to every message in dialog windows (not in conferences yet)
- roster window position and size now are stored in config
- expanded accounts and groups are stored in config
- availability (from top combobox) now is stored in config
### Bug fixes
- segfault when sending more then one attached file
- wrong path and name of saving file
- wrong message syntax when attaching file and writing text in the save message
- problem with links highlighting in dialog
- project building fixes
## Squawk 0.1.1 (Nov 16, 2019)
A lot of bug fixes, memory leaks fixes
### New features
- exchange files via HTTP File Upload
- download VCards of your contacts
- upload your VCard with information about your contact phones email addresses, names, career information and avatar
- avatars of your contacts in roster and in notifications
## Squawk 0.0.5 (Oct 10, 2019)
### Features
- chat directly
- have multiple accounts
- add contacts
- remove contacts
- assign contact to different groups
- chat in MUCs
- join MUCs, leave them, keep them subscribed or unsubscribed
- download attachmets
- local history
- desktop notifications of new messages

82
CMakeLists.txt

@ -2,22 +2,48 @@ cmake_minimum_required(VERSION 3.0)
project(squawk)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
include(GNUInstallDirs)
include_directories(.)
find_package(Qt5Widgets CONFIG REQUIRED)
find_package(Qt5LinguistTools)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Debug)
endif()
set(CMAKE_CXX_FLAGS_DEBUG "-g -Wall -Wextra")
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
message("Build type: ${CMAKE_BUILD_TYPE}")
set(squawk_SRC
main.cpp
global.cpp
exception.cpp
signalcatcher.cpp
shared/global.cpp
shared/utils.cpp
shared/message.cpp
shared/vcard.cpp
shared/icons.cpp
)
set(squawk_HEAD
exception.h
signalcatcher.h
shared.h
shared/enums.h
shared/message.h
shared/global.h
shared/utils.h
shared/vcard.h
shared/icons.h
)
configure_file(resources/images/logo.svg squawk.svg COPYONLY)
@ -36,17 +62,43 @@ add_custom_target(translations ALL DEPENDS ${QM_FILES})
qt5_add_resources(RCC resources/resources.qrc)
add_executable(squawk ${squawk_SRC} ${RCC})
option(SYSTEM_QXMPP "Use system qxmpp lib" ON)
option(WITH_KWALLET "Build KWallet support module" ON)
if (SYSTEM_QXMPP)
find_package(QXmpp CONFIG)
if (NOT QXmpp_FOUND)
set(SYSTEM_QXMPP OFF)
message("QXmpp package wasn't found, trying to build with bundled QXmpp")
else()
message("Building with system QXmpp")
endif()
endif()
if(NOT SYSTEM_QXMPP)
add_subdirectory(external/qxmpp)
endif()
if (WITH_KWALLET)
find_package(KF5Wallet CONFIG)
if (NOT KF5Wallet_FOUND)
set(WITH_KWALLET OFF)
message("KWallet package wasn't found, KWallet support module wouldn't be built")
else()
add_definitions(-DWITH_KWALLET)
message("Building with support of KWallet")
endif()
endif()
add_executable(squawk ${squawk_SRC} ${squawk_HEAD} ${RCC})
target_link_libraries(squawk Qt5::Widgets)
add_subdirectory(ui)
add_subdirectory(core)
option(SYSTEM_QXMPP "Use system qxmpp lib" OFF)
if(NOT SYSTEM_QXMPP)
add_subdirectory(external/qxmpp)
endif()
add_subdirectory(external/simpleCrypt)
target_link_libraries(squawk squawkUI)
target_link_libraries(squawk squawkCORE)
@ -56,10 +108,10 @@ add_dependencies(${CMAKE_PROJECT_NAME} translations)
# Install the executable
install(TARGETS squawk DESTINATION ${CMAKE_INSTALL_BINDIR})
install(FILES ${QM_FILES} DESTINATION ${CMAKE_INSTALL_DATADIR}/Macaw/Squawk/l10n)
install(FILES squawk.svg DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps)
install(FILES squawk48.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/48x48/apps RENAME squawk.png)
install(FILES squawk64.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/64x64/apps RENAME squawk.png)
install(FILES squawk128.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/128x128/apps RENAME squawk.png)
install(FILES squawk256.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/256x256/apps RENAME squawk.png)
install(FILES squawk.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications)
install(FILES ${QM_FILES} DESTINATION ${CMAKE_INSTALL_DATADIR}/squawk/l10n)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/squawk.svg DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/squawk48.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/48x48/apps RENAME squawk.png)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/squawk64.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/64x64/apps RENAME squawk.png)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/squawk128.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/128x128/apps RENAME squawk.png)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/squawk256.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/256x256/apps RENAME squawk.png)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/squawk.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications)

62
README.md

@ -1,6 +1,10 @@
# Sqwawk
# Squawk - a compact XMPP desktop messenger
A compact XMPP desktop messenger
[![AUR license](https://img.shields.io/aur/license/squawk?style=flat-square)](https://git.macaw.me/blue/squawk/raw/branch/master/LICENSE.md)
[![AUR version](https://img.shields.io/aur/version/squawk?style=flat-square)](https://aur.archlinux.org/packages/squawk/)
[![Liberapay patrons](https://img.shields.io/liberapay/patrons/macaw.me?logo=liberapay&style=flat-square)](https://liberapay.com/macaw.me)
![Squawk screenshot](https://macaw.me/images/squawk/0.1.4.png)
### Prerequisites
@ -8,24 +12,62 @@ A compact XMPP desktop messenger
- uuid _(usually included in some other package, for example it's ***libutil-linux*** in archlinux)_
- lmdb
- CMake 3.0 or higher
- qxmpp 1.1.0 or higher
- kwallet (optional)
### Getting
The easiest way to get the Squawk is to install it from AUR (if you use Archlinux like distribution)
Here is the [link](https://aur.archlinux.org/packages/squawk/) for the AUR package
You can also install it from console if you use some AUR wrapper. Here what it's going to look like with *pacaur*
```
$ pacaur -S squawk
```
### Building
You can also clone the repo and build it from source
Squawk requires Qt with SSL enabled. It uses CMake as build system.
Squawk uses upstream version of QXmpp library so first we need to pull it
There are two ways to build, it depends whether you have qxmpp installed in your system
#### Building with system qxmpp
Here is what you do
```
git submodule update --init --recursive
$ git clone https://git.macaw.me/blue/squawk
$ cd squawk
$ mkdir build
$ cd build
$ cmake ..
$ cmake --build .
```
Then create a folder for the build, go there and build the project using CMake
#### Building with bundled qxmpp
Here is what you do
```
mkdir build
cd build
cmake ..
cmake --build .
$ git clone --recurse-submodules https://git.macaw.me/blue/squawk
$ cd squawk
$ mkdir build
$ cd build
$ cmake .. -D SYSTEM_QXMPP=False
$ cmake --build .
```
### List of keys
Here is the list of keys you can pass to configuration phase of `cmake ..`.
- `CMAKE_BUILD_TYPE` - `Debug` just builds showing all warnings, `Release` builds with no warnings and applies optimizations (default is `Debug`)
- `SYSTEM_QXMPP` - `True` tries to link against `qxmpp` installed in the system, `False` builds bundled `qxmpp` library (default is `True`)
- `WITH_KWALLET` - `True` builds the `KWallet` capability module if `KWallet` is installed and if not goes to `False`. `False` disables `KWallet` support (default is `True`)
## License
This project is licensed under the GPLv3 License - see the [LICENSE.md](LICENSE.md) file for details

18
core/CMakeLists.txt

@ -3,8 +3,10 @@ project(squawkCORE)
set(CMAKE_AUTOMOC ON)
find_package(Qt5Widgets CONFIG REQUIRED)
find_package(Qt5Core CONFIG REQUIRED)
find_package(Qt5Gui CONFIG REQUIRED)
find_package(Qt5Network CONFIG REQUIRED)
find_package(Qt5Xml CONFIG REQUIRED)
set(squawkCORE_SRC
squawk.cpp
@ -15,20 +17,30 @@ set(squawkCORE_SRC
conference.cpp
storage.cpp
networkaccess.cpp
adapterFuctions.cpp
handlers/messagehandler.cpp
handlers/rosterhandler.cpp
)
add_subdirectory(passwordStorageEngines)
# Tell CMake to create the helloworld executable
add_library(squawkCORE ${squawkCORE_SRC})
if(SYSTEM_QXMPP)
find_package(QXmpp CONFIG REQUIRED)
get_target_property(QXMPP_INTERFACE_INCLUDE_DIRECTORIES QXmpp::QXmpp INTERFACE_INCLUDE_DIRECTORIES)
target_include_directories(squawkCORE PUBLIC ${QXMPP_INTERFACE_INCLUDE_DIRECTORIES})
endif()
# Use the Widgets module from Qt 5.
target_link_libraries(squawkCORE Qt5::Core)
target_link_libraries(squawkCORE Qt5::Network)
target_link_libraries(squawkCORE Qt5::Gui)
target_link_libraries(squawkCORE Qt5::Xml)
target_link_libraries(squawkCORE qxmpp)
target_link_libraries(squawkCORE lmdb)
target_link_libraries(squawkCORE simpleCrypt)
if (WITH_KWALLET)
target_link_libraries(squawkCORE kwalletPSE)
endif()

1398
core/account.cpp
File diff suppressed because it is too large
View File

143
core/account.h

@ -19,20 +19,37 @@
#ifndef CORE_ACCOUNT_H
#define CORE_ACCOUNT_H
#include <QtCore/QObject>
#include <QObject>
#include <QCryptographicHash>
#include <QFile>
#include <QMimeDatabase>
#include <QStandardPaths>
#include <QDir>
#include <QTimer>
#include <map>
#include <set>
#include <QXmppRosterManager.h>
#include <QXmppCarbonManager.h>
#include <QXmppDiscoveryManager.h>
#include <QXmppMamManager.h>
#include <QXmppMucManager.h>
#include <QXmppClient.h>
#include <QXmppBookmarkManager.h>
#include <QXmppBookmarkSet.h>
#include "../global.h"
#include <QXmppUploadRequestManager.h>
#include <QXmppVCardIq.h>
#include <QXmppVCardManager.h>
#include <QXmppMessageReceiptManager.h>
#include "shared.h"
#include "contact.h"
#include "conference.h"
#include "networkaccess.h"
#include "handlers/messagehandler.h"
#include "handlers/rosterhandler.h"
namespace Core
{
@ -40,21 +57,27 @@ namespace Core
class Account : public QObject
{
Q_OBJECT
friend class MessageHandler;
friend class RosterHandler;
public:
Account(const QString& p_login, const QString& p_server, const QString& p_password, const QString& p_name, QObject* parent = 0);
Account(
const QString& p_login,
const QString& p_server,
const QString& p_password,
const QString& p_name,
NetworkAccess* p_net,
QObject* parent = 0);
~Account();
void connect();
void disconnect();
void reconnect();
Shared::ConnectionState getState() const;
QString getName() const;
QString getLogin() const;
QString getServer() const;
QString getPassword() const;
QString getResource() const;
QString getAvatarPath() const;
Shared::Availability getAvailability() const;
Shared::AccountPassword getPasswordType() const;
void setName(const QString& p_name);
void setLogin(const QString& p_login);
@ -62,10 +85,11 @@ public:
void setPassword(const QString& p_password);
void setResource(const QString& p_resource);
void setAvailability(Shared::Availability avail);
void setPasswordType(Shared::AccountPassword pt);
QString getFullJid() const;
void sendMessage(const Shared::Message& data);
void sendMessage(const Shared::Message& data, const QString& path);
void requestArchive(const QString& jid, int count, const QString& before);
void setReconnectTimes(unsigned int times);
void subscribeToContact(const QString& jid, const QString& reason);
void unsubscribeFromContact(const QString& jid, const QString& reason);
void removeContactRequest(const QString& jid);
@ -78,10 +102,18 @@ public:
void setRoomAutoJoin(const QString& jid, bool joined);
void removeRoomRequest(const QString& jid);
void addRoomRequest(const QString& jid, const QString& nick, const QString& password, bool autoJoin);
void uploadVCard(const Shared::VCard& card);
public slots:
void connect();
void disconnect();
void reconnect();
void requestVCard(const QString& jid);
signals:
void connectionStateChanged(int);
void availabilityChanged(int);
void changed(const QMap<QString, QVariant>& data);
void connectionStateChanged(Shared::ConnectionState);
void availabilityChanged(Shared::Availability);
void addGroup(const QString& name);
void removeGroup(const QString& name);
void addRoom(const QString& jid, const QMap<QString, QVariant>& data);
@ -94,90 +126,71 @@ signals:
void addPresence(const QString& jid, const QString& name, const QMap<QString, QVariant>& data);
void removePresence(const QString& jid, const QString& name);
void message(const Shared::Message& data);
void changeMessage(const QString& jid, const QString& id, const QMap<QString, QVariant>& data);
void responseArchive(const QString& jid, const std::list<Shared::Message>& list);
void error(const QString& text);
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 removeRoomParticipant(const QString& jid, const QString& nickName);
void receivedVCard(const QString& jid, const Shared::VCard& card);
void uploadFile(const QFileInfo& file, const QUrl& set, const QUrl& get, QMap<QString, QString> headers);
void uploadFileError(const QString& messageId, const QString& error);
private:
QString name;
std::map<QString, QString> achiveQueries;
std::map<QString, QString> archiveQueries;
QXmppClient client;
QXmppConfiguration config;
QXmppPresence presence;
Shared::ConnectionState state;
std::map<QString, std::set<QString>> groups;
QXmppCarbonManager* cm;
QXmppMamManager* am;
QXmppMucManager* mm;
QXmppBookmarkManager* bm;
std::map<QString, Contact*> contacts;
std::map<QString, Conference*> conferences;
unsigned int maxReconnectTimes;
unsigned int reconnectTimes;
QXmppRosterManager* rm;
QXmppVCardManager* vm;
QXmppUploadRequestManager* um;
QXmppDiscoveryManager* dm;
QXmppMessageReceiptManager* rcpm;
bool reconnectScheduled;
QTimer* reconnectTimer;
std::map<QString, QString> queuedContacts;
std::set<QString> outOfRosterContacts;
std::set<QString> pendingVCardRequests;
QString avatarHash;
QString avatarType;
bool ownVCardRequestInProgress;
NetworkAccess* network;
Shared::AccountPassword passwordType;
MessageHandler* mh;
RosterHandler* rh;
private slots:
void onClientConnected();
void onClientDisconnected();
void onClientStateChange(QXmppClient::State state);
void onClientError(QXmppClient::Error err);
void onRosterReceived();
void onRosterItemAdded(const QString& bareJid);
void onRosterItemChanged(const QString& bareJid);
void onRosterItemRemoved(const QString& bareJid);
void onRosterPresenceChanged(const QString& bareJid, const QString& resource);
void onPresenceReceived(const QXmppPresence& presence);
void onMessageReceived(const QXmppMessage& message);
void onCarbonMessageReceived(const QXmppMessage& message);
void onCarbonMessageSent(const QXmppMessage& message);
void onContactNeedHistory(const QString& before, const QString& after, const QDateTime& at);
void onMamMessageReceived(const QString& bareJid, const QXmppMessage& message);
void onMamResultsReceived(const QString &queryId, const QXmppResultSetReply &resultSetReply, bool complete);
void onMucRoomAdded(QXmppMucRoom* room);
void onMucJoinedChanged(bool joined);
void onMucAutoJoinChanged(bool autoJoin);
void onMucNickNameChanged(const QString& nickName);
void onMucSubjectChanged(const QString& subject);
void onMucAddParticipant(const QString& nickName, const QMap<QString, QVariant>& data);
void onMucChangeParticipant(const QString& nickName, const QMap<QString, QVariant>& data);
void onMucRemoveParticipant(const QString& nickName);
void bookmarksReceived(const QXmppBookmarkSet& bookmarks);
void onContactGroupAdded(const QString& group);
void onContactGroupRemoved(const QString& group);
void onContactNameChanged(const QString& name);
void onContactSubscriptionStateChanged(Shared::SubscriptionState state);
void onContactHistoryResponse(const std::list<Shared::Message>& list);
void onContactNeedHistory(const QString& before, const QString& after, const QDateTime& at);
void onMamLog(QXmppLogger::MessageType type, const QString &msg);
void onVCardReceived(const QXmppVCardIq& card);
void onOwnVCardReceived(const QXmppVCardIq& card);
void onDiscoveryItemsReceived (const QXmppDiscoveryIq& items);
void onDiscoveryInfoReceived (const QXmppDiscoveryIq& info);
private:
void addedAccount(const QString &bareJid);
void handleNewContact(Contact* contact);
void handleNewRosterItem(RosterItem* contact);
void handleNewConference(Conference* contact);
bool handleChatMessage(const QXmppMessage& msg, bool outgoing = false, bool forwarded = false, bool guessing = false);
bool handleGroupMessage(const QXmppMessage& msg, bool outgoing = false, bool forwarded = false, bool guessing = false);
void addNewRoom(const QString& jid, const QString& nick, const QString& roomName, bool autoJoin);
void addToGroup(const QString& jid, const QString& group);
void removeFromGroup(const QString& jid, const QString& group);
void initializeMessage(Shared::Message& target, const QXmppMessage& source, bool outgoing = false, bool forwarded = false, bool guessing = false) const;
Shared::SubscriptionState castSubscriptionState(QXmppRosterIq::Item::SubscriptionType qs) const;
void logMessage(const QXmppMessage& msg, const QString& reason = "Message wasn't handled: ");
void storeConferences();
void clearConferences();
void handleDisconnection();
void onReconnectTimer();
};
void initializeVCard(Shared::VCard& vCard, const QXmppVCardIq& card);
void initializeQXmppVCard(QXmppVCardIq& card, const Shared::VCard& vCard);
}

275
core/adapterFuctions.cpp

@ -0,0 +1,275 @@
/*
* 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_ADAPTER_FUNCTIONS_H
#define CORE_ADAPTER_FUNCTIONS_H
#include "account.h"
void Core::initializeVCard(Shared::VCard& vCard, const QXmppVCardIq& card)
{
vCard.setFullName(card.fullName());
vCard.setFirstName(card.firstName());
vCard.setMiddleName(card.middleName());
vCard.setLastName(card.lastName());
vCard.setBirthday(card.birthday());
vCard.setNickName(card.nickName());
vCard.setDescription(card.description());
vCard.setUrl(card.url());
QXmppVCardOrganization org = card.organization();
vCard.setOrgName(org.organization());
vCard.setOrgRole(org.role());
vCard.setOrgUnit(org.unit());
vCard.setOrgTitle(org.title());
QList<QXmppVCardEmail> emails = card.emails();
std::deque<Shared::VCard::Email>& myEmails = vCard.getEmails();
for (const QXmppVCardEmail& em : emails) {
QString addr = em.address();
if (addr.size() != 0) {
QXmppVCardEmail::Type et = em.type();
bool prefered = false;
bool accounted = false;
if (et & QXmppVCardEmail::Preferred) {
prefered = true;
}
if (et & QXmppVCardEmail::Home) {
myEmails.emplace_back(addr, Shared::VCard::Email::home, prefered);
accounted = true;
}
if (et & QXmppVCardEmail::Work) {
myEmails.emplace_back(addr, Shared::VCard::Email::work, prefered);
accounted = true;
}
if (!accounted) {
myEmails.emplace_back(addr, Shared::VCard::Email::none, prefered);
}
}
}
QList<QXmppVCardPhone> phones = card.phones();
std::deque<Shared::VCard::Phone>& myPhones = vCard.getPhones();
for (const QXmppVCardPhone& ph : phones) {
QString num = ph.number();
if (num.size() != 0) {
QXmppVCardPhone::Type pt = ph.type();
bool prefered = false;
bool accounted = false;
if (pt & QXmppVCardPhone::Preferred) {
prefered = true;
}
bool home = false;
bool work = false;
if (pt & QXmppVCardPhone::Home) {
home = true;
}
if (pt & QXmppVCardPhone::Work) {
work = true;
}
if (pt & QXmppVCardPhone::Fax) {
if (home || work) {
if (home) {
myPhones.emplace_back(num, Shared::VCard::Phone::fax, Shared::VCard::Phone::home, prefered);
}
if (work) {
myPhones.emplace_back(num, Shared::VCard::Phone::fax, Shared::VCard::Phone::work, prefered);
}
} else {
myPhones.emplace_back(num, Shared::VCard::Phone::fax, Shared::VCard::Phone::none, prefered);
}
accounted = true;
}
if (pt & QXmppVCardPhone::Voice) {
if (home || work) {
if (home) {
myPhones.emplace_back(num, Shared::VCard::Phone::voice, Shared::VCard::Phone::home, prefered);
}
if (work) {
myPhones.emplace_back(num, Shared::VCard::Phone::voice, Shared::VCard::Phone::work, prefered);
}
} else {
myPhones.emplace_back(num, Shared::VCard::Phone::voice, Shared::VCard::Phone::none, prefered);
}
accounted = true;
}
if (pt & QXmppVCardPhone::Pager) {
if (home || work) {
if (home) {
myPhones.emplace_back(num, Shared::VCard::Phone::pager, Shared::VCard::Phone::home, prefered);
}
if (work) {
myPhones.emplace_back(num, Shared::VCard::Phone::pager, Shared::VCard::Phone::work, prefered);
}
} else {
myPhones.emplace_back(num, Shared::VCard::Phone::pager, Shared::VCard::Phone::none, prefered);
}
accounted = true;
}
if (pt & QXmppVCardPhone::Cell) {
if (home || work) {
if (home) {
myPhones.emplace_back(num, Shared::VCard::Phone::cell, Shared::VCard::Phone::home, prefered);
}
if (work) {
myPhones.emplace_back(num, Shared::VCard::Phone::cell, Shared::VCard::Phone::work, prefered);
}
} else {
myPhones.emplace_back(num, Shared::VCard::Phone::cell, Shared::VCard::Phone::none, prefered);
}
accounted = true;
}
if (pt & QXmppVCardPhone::Video) {
if (home || work) {
if (home) {
myPhones.emplace_back(num, Shared::VCard::Phone::video, Shared::VCard::Phone::home, prefered);
}
if (work) {
myPhones.emplace_back(num, Shared::VCard::Phone::video, Shared::VCard::Phone::work, prefered);
}
} else {
myPhones.emplace_back(num, Shared::VCard::Phone::video, Shared::VCard::Phone::none, prefered);
}
accounted = true;
}
if (pt & QXmppVCardPhone::Modem) {
if (home || work) {
if (home) {
myPhones.emplace_back(num, Shared::VCard::Phone::modem, Shared::VCard::Phone::home, prefered);
}
if (work) {
myPhones.emplace_back(num, Shared::VCard::Phone::modem, Shared::VCard::Phone::work, prefered);
}
} else {
myPhones.emplace_back(num, Shared::VCard::Phone::modem, Shared::VCard::Phone::none, prefered);
}
accounted = true;
}
if (!accounted) {
if (home || work) {
if (home) {
myPhones.emplace_back(num, Shared::VCard::Phone::other, Shared::VCard::Phone::home, prefered);
}
if (work) {
myPhones.emplace_back(num, Shared::VCard::Phone::other, Shared::VCard::Phone::work, prefered);
}
} else {
myPhones.emplace_back(num, Shared::VCard::Phone::other, Shared::VCard::Phone::none, prefered);
}
}
}
}
}
void Core::initializeQXmppVCard(QXmppVCardIq& iq, const Shared::VCard& card) {
iq.setFullName(card.getFullName());
iq.setFirstName(card.getFirstName());
iq.setMiddleName(card.getMiddleName());
iq.setLastName(card.getLastName());
iq.setNickName(card.getNickName());
iq.setBirthday(card.getBirthday());
iq.setDescription(card.getDescription());
iq.setUrl(card.getUrl());
QXmppVCardOrganization org;
org.setOrganization(card.getOrgName());
org.setUnit(card.getOrgUnit());
org.setRole(card.getOrgRole());
org.setTitle(card.getOrgTitle());
iq.setOrganization(org);
const std::deque<Shared::VCard::Email>& myEmails = card.getEmails();
QList<QXmppVCardEmail> emails;
for (const Shared::VCard::Email& mEm : myEmails) {
QXmppVCardEmail em;
QXmppVCardEmail::Type t = QXmppVCardEmail::Internet;
if (mEm.prefered) {
t = t | QXmppVCardEmail::Preferred;
}
if (mEm.role == Shared::VCard::Email::home) {
t = t | QXmppVCardEmail::Home;
} else if (mEm.role == Shared::VCard::Email::work) {
t = t | QXmppVCardEmail::Work;
}
em.setType(t);
em.setAddress(mEm.address);
emails.push_back(em);
}
std::map<QString, QXmppVCardPhone> phones;
QList<QXmppVCardPhone> phs;
const std::deque<Shared::VCard::Phone>& myPhones = card.getPhones();
for (const Shared::VCard::Phone& mPh : myPhones) {
std::map<QString, QXmppVCardPhone>::iterator itr = phones.find(mPh.number);
if (itr == phones.end()) {
itr = phones.emplace(mPh.number, QXmppVCardPhone()).first;
}
QXmppVCardPhone& phone = itr->second;
phone.setNumber(mPh.number);
switch (mPh.type) {
case Shared::VCard::Phone::fax:
phone.setType(phone.type() | QXmppVCardPhone::Fax);
break;
case Shared::VCard::Phone::pager:
phone.setType(phone.type() | QXmppVCardPhone::Pager);
break;
case Shared::VCard::Phone::voice:
phone.setType(phone.type() | QXmppVCardPhone::Voice);
break;
case Shared::VCard::Phone::cell:
phone.setType(phone.type() | QXmppVCardPhone::Cell);
break;
case Shared::VCard::Phone::video:
phone.setType(phone.type() | QXmppVCardPhone::Video);
break;
case Shared::VCard::Phone::modem:
phone.setType(phone.type() | QXmppVCardPhone::Modem);
break;
case Shared::VCard::Phone::other:
phone.setType(phone.type() | QXmppVCardPhone::PCS); //loss of information, but I don't even know what the heck is this type of phone!
break;
}
switch (mPh.role) {
case Shared::VCard::Phone::home:
phone.setType(phone.type() | QXmppVCardPhone::Home);
break;
case Shared::VCard::Phone::work:
phone.setType(phone.type() | QXmppVCardPhone::Work);
break;
default:
break;
}
if (mPh.prefered) {
phone.setType(phone.type() | QXmppVCardPhone::Preferred);
}
}
for (const std::pair<QString, QXmppVCardPhone>& phone : phones) {
phs.push_back(phone.second);
}
iq.setEmails(emails);
iq.setPhones(phs);
}
#endif // CORE_ADAPTER_FUNCTIONS_H

744
core/archive.cpp

@ -32,7 +32,8 @@ Core::Archive::Archive(const QString& p_jid, QObject* parent):
environment(),
main(),
order(),
stats()
stats(),
avatars()
{
}
@ -56,7 +57,7 @@ void Core::Archive::open(const QString& account)
}
}
mdb_env_set_maxdbs(environment, 4);
mdb_env_set_maxdbs(environment, 5);
mdb_env_set_mapsize(environment, 512UL * 1024UL * 1024UL);
mdb_env_open(environment, path.toStdString().c_str(), 0, 0664);
@ -65,8 +66,33 @@ void Core::Archive::open(const QString& account)
mdb_dbi_open(txn, "main", MDB_CREATE, &main);
mdb_dbi_open(txn, "order", MDB_CREATE | MDB_INTEGERKEY, &order);
mdb_dbi_open(txn, "stats", MDB_CREATE, &stats);
mdb_dbi_open(txn, "avatars", MDB_CREATE, &avatars);
mdb_dbi_open(txn, "sid", MDB_CREATE, &sid);
mdb_txn_commit(txn);
fromTheBeginning = _isFromTheBeginning();
mdb_txn_begin(environment, NULL, MDB_RDONLY, &txn);
try {
fromTheBeginning = getStatBoolValue("beginning", txn);
} catch (const NotFound& e) {
fromTheBeginning = false;
}
std::string sJid = jid.toStdString();
AvatarInfo info;
bool hasAvatar = readAvatarInfo(info, sJid, txn);
mdb_txn_abort(txn);
if (hasAvatar) {
QFile ava(path + "/" + sJid.c_str() + "." + info.type);
if (!ava.exists()) {
bool success = dropAvatar(sJid);
if (!success) {
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";
}
}
}
opened = true;
}
}
@ -74,6 +100,8 @@ void Core::Archive::open(const QString& account)
void Core::Archive::close()
{
if (opened) {
mdb_dbi_close(environment, sid);
mdb_dbi_close(environment, avatars);
mdb_dbi_close(environment, stats);
mdb_dbi_close(environment, order);
mdb_dbi_close(environment, main);
@ -113,12 +141,36 @@ bool Core::Archive::addElement(const Shared::Message& message)
mdb_txn_abort(txn);
return false;
} else {
rc = mdb_txn_commit(txn);
if (rc) {
qDebug() << "A transaction error: " << mdb_strerror(rc);
return false;
if (message.getStanzaId().size() > 0) {
const std::string& szid = message.getStanzaId().toStdString();
lmdbKey.mv_size = szid.size();
lmdbKey.mv_data = (char*)szid.c_str();
lmdbData.mv_size = id.size();
lmdbData.mv_data = (uint8_t*)id.data();
rc = mdb_put(txn, sid, &lmdbKey, &lmdbData, MDB_NOOVERWRITE);
if (rc) {
qDebug() << "An element stanzaId to id pair couldn't be inserted into the archive" << mdb_strerror(rc);
mdb_txn_abort(txn);
return false;
} else {
rc = mdb_txn_commit(txn);
if (rc) {
qDebug() << "A transaction error: " << mdb_strerror(rc);
return false;
}
return true;
}
} else {
rc = mdb_txn_commit(txn);
if (rc) {
qDebug() << "A transaction error: " << mdb_strerror(rc);
return false;
}
return true;
}
return true;
}
} else {
qDebug() << "An element couldn't been added to the archive, skipping" << mdb_strerror(rc);
@ -138,44 +190,146 @@ void Core::Archive::clear()
mdb_drop(txn, main, 0);
mdb_drop(txn, order, 0);
mdb_drop(txn, stats, 0);
mdb_drop(txn, avatars, 0);
mdb_drop(txn, sid, 0);
mdb_txn_commit(txn);
}
Shared::Message Core::Archive::getElement(const QString& id)
Shared::Message Core::Archive::getElement(const QString& id) const
{
if (!opened) {
throw Closed("getElement", jid.toStdString());
}
std::string strKey = id.toStdString();
MDB_txn *txn;
mdb_txn_begin(environment, NULL, MDB_RDONLY, &txn);
MDB_val lmdbKey, lmdbData;
lmdbKey.mv_size = strKey.size();
lmdbKey.mv_data = (char*)strKey.c_str();
try {
Shared::Message msg = getMessage(id.toStdString(), txn);
mdb_txn_abort(txn);
return msg;
} catch (...) {
mdb_txn_abort(txn);
throw;
}
}
bool Core::Archive::hasElement(const QString& id) const
{
if (!opened) {
throw Closed("hasElement", jid.toStdString());
}
MDB_txn *txn;
int rc;
mdb_txn_begin(environment, NULL, MDB_RDONLY, &txn);
rc = mdb_get(txn, main, &lmdbKey, &lmdbData);
if (rc) {
qDebug() <<"Get error: " << mdb_strerror(rc);
mdb_txn_abort(txn);
throw NotFound(id.toStdString(), jid.toStdString());
} else {
bool has;
MDB_val lmdbKey, lmdbData;
lmdbKey.mv_size = id.size();
lmdbKey.mv_data = (char*)id.toStdString().c_str();
int rc = mdb_get(txn, main, &lmdbKey, &lmdbData);
has = rc == 0;
mdb_txn_abort(txn);
return has;
}
Shared::Message Core::Archive::getMessage(const std::string& id, MDB_txn* txn) const
{
MDB_val lmdbKey, lmdbData;
lmdbKey.mv_size = id.size();
lmdbKey.mv_data = (char*)id.c_str();
int rc = mdb_get(txn, main, &lmdbKey, &lmdbData);
if (rc == 0) {
QByteArray ba((char*)lmdbData.mv_data, lmdbData.mv_size);
QDataStream ds(&ba, QIODevice::ReadOnly);
Shared::Message msg;
msg.deserialize(ds);
mdb_txn_abort(txn);
return msg;
} else if (rc == MDB_NOTFOUND) {
throw NotFound(id, jid.toStdString());
} else {
throw Unknown(jid.toStdString(), mdb_strerror(rc));
}
}
void Core::Archive::changeMessage(const QString& id, const QMap<QString, QVariant>& data)
{
if (!opened) {
throw Closed("setMessageState", jid.toStdString());
}
MDB_txn *txn;
mdb_txn_begin(environment, NULL, 0, &txn);
std::string strId(id.toStdString());
try {
Shared::Message msg = getMessage(strId, txn);
bool hadStanzaId = msg.getStanzaId().size() > 0;
QDateTime oTime = msg.getTime();
bool idChange = msg.change(data);
MDB_val lmdbKey, lmdbData;
QByteArray ba;
QDataStream ds(&ba, QIODevice::WriteOnly);
msg.serialize(ds);
lmdbKey.mv_size = strId.size();
lmdbKey.mv_data = (char*)strId.c_str();
int rc;
if (idChange) {
rc = mdb_del(txn, main, &lmdbKey, &lmdbData);
if (rc == 0) {
strId = msg.getId().toStdString();
lmdbKey.mv_size = strId.size();
lmdbKey.mv_data = (char*)strId.c_str();
quint64 stamp = oTime.toMSecsSinceEpoch();
lmdbData.mv_data = (quint8*)&stamp;
lmdbData.mv_size = 8;
rc = mdb_put(txn, order, &lmdbData, &lmdbKey, 0);
if (rc != 0) {
throw Unknown(jid.toStdString(), mdb_strerror(rc));
}
} else {
throw Unknown(jid.toStdString(), mdb_strerror(rc));
}
}
if (msg.getStanzaId().size() > 0 && (idChange || !hadStanzaId)) {
const std::string& szid = msg.getStanzaId().toStdString();
lmdbData.mv_size = szid.size();
lmdbData.mv_data = (char*)szid.c_str();
rc = mdb_put(txn, sid, &lmdbData, &lmdbKey, 0);
if (rc != 0) {
throw Unknown(jid.toStdString(), mdb_strerror(rc));
}
};
lmdbData.mv_size = ba.size();
lmdbData.mv_data = (uint8_t*)ba.data();
rc = mdb_put(txn, main, &lmdbKey, &lmdbData, 0);
if (rc == 0) {
rc = mdb_txn_commit(txn);
} else {
throw Unknown(jid.toStdString(), mdb_strerror(rc));
}
} catch (...) {
mdb_txn_abort(txn);
throw;
}
}
Shared::Message Core::Archive::newest()
{
QString id = newestId();
return getElement(id);
return edge(true);
}
QString Core::Archive::newestId()
@ -183,25 +337,8 @@ QString Core::Archive::newestId()
if (!opened) {
throw Closed("newestId", jid.toStdString());
}
MDB_txn *txn;
int rc;
rc = mdb_txn_begin(environment, NULL, MDB_RDONLY, &txn);
MDB_cursor* cursor;
rc = mdb_cursor_open(txn, order, &cursor);
MDB_val lmdbKey, lmdbData;
rc = mdb_cursor_get(cursor, &lmdbKey, &lmdbData, MDB_LAST);
if (rc) {
qDebug() << "Error geting newestId " << mdb_strerror(rc);
mdb_cursor_close(cursor);
mdb_txn_abort(txn);
throw Empty(jid.toStdString());
} else {
std::string sId((char*)lmdbData.mv_data, lmdbData.mv_size);
mdb_cursor_close(cursor);
mdb_txn_abort(txn);
return sId.c_str();
}
Shared::Message msg = newest();
return msg.getId();
}
QString Core::Archive::oldestId()
@ -209,30 +346,79 @@ QString Core::Archive::oldestId()
if (!opened) {
throw Closed("oldestId", jid.toStdString());
}
Shared::Message msg = oldest();
return msg.getId();
}
Shared::Message Core::Archive::oldest()
{
return edge(false);
}
Shared::Message Core::Archive::edge(bool end)
{
QString name;
MDB_cursor_op begin;
MDB_cursor_op iteration;
if (end) {
name = "newest";
begin = MDB_LAST;
iteration = MDB_PREV;
} else {
name = "oldest";
begin = MDB_FIRST;
iteration = MDB_NEXT;
}
if (!opened) {
throw Closed(name.toStdString(), jid.toStdString());
}
MDB_txn *txn;
MDB_cursor* cursor;
MDB_val lmdbKey, lmdbData;
int rc;
rc = mdb_txn_begin(environment, NULL, MDB_RDONLY, &txn);
MDB_cursor* cursor;
rc = mdb_cursor_open(txn, order, &cursor);
MDB_val lmdbKey, lmdbData;
rc = mdb_cursor_get(cursor, &lmdbKey, &lmdbData, begin);
Shared::Message msg = getStoredMessage(txn, cursor, iteration, &lmdbKey, &lmdbData, rc);
mdb_cursor_close(cursor);
mdb_txn_abort(txn);
rc = mdb_cursor_get(cursor, &lmdbKey, &lmdbData, MDB_FIRST);
if (rc) {
qDebug() << "Error geting oldestId " << mdb_strerror(rc);
mdb_cursor_close(cursor);
mdb_txn_abort(txn);
qDebug() << "Error geting" << name << "message" << mdb_strerror(rc);
throw Empty(jid.toStdString());
} else {
std::string sId((char*)lmdbData.mv_data, lmdbData.mv_size);
mdb_cursor_close(cursor);
mdb_txn_abort(txn);
return sId.c_str();
return msg;
}
}
Shared::Message Core::Archive::oldest()
Shared::Message Core::Archive::getStoredMessage(MDB_txn *txn, MDB_cursor* cursor, MDB_cursor_op op, MDB_val* key, MDB_val* value, int& rc)
{
return getElement(oldestId());
Shared::Message msg;
std::string sId;
while (true) {
if (rc) {
break;
}
sId = std::string((char*)value->mv_data, value->mv_size);
try {
msg = getMessage(sId, txn);
if (msg.serverStored()) {
break;
} else {
rc = mdb_cursor_get(cursor, key, value, op);
}
} catch (...) {
break;
}
}
return msg;
}
unsigned int Core::Archive::addElements(const std::list<Shared::Message>& messages)
@ -271,7 +457,20 @@ unsigned int Core::Archive::addElements(const std::list<Shared::Message>& messag
if (rc) {
qDebug() <<