diff options
author | Kitsune Ral <Kitsune-Ral@users.sf.net> | 2021-01-15 08:19:22 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-01-15 08:19:22 +0100 |
commit | 544ec34b4563aacac6fd5b2f4aa64813096cd4b8 (patch) | |
tree | 878a6db1895d75c89292b8278731d63fadf248e1 | |
parent | 17d6e00597fdc1c8f25808735cbc728c4a6b3506 (diff) | |
parent | b0d3ecc774ca4aec24bceb5ec1f1ded844a7213a (diff) | |
download | libquotient-544ec34b4563aacac6fd5b2f4aa64813096cd4b8.tar.gz libquotient-544ec34b4563aacac6fd5b2f4aa64813096cd4b8.zip |
Merge branch 'master' into dfaure/stricter-flags
96 files changed, 1508 insertions, 1657 deletions
diff --git a/.clang-format b/.clang-format index 7cc0f46e..4df5ae84 100644 --- a/.clang-format +++ b/.clang-format @@ -92,7 +92,7 @@ IncludeCategories: #IncludeIsMainRegex: '(_test)?$' #IncludeIsMainSourceRegex: '' #IndentCaseLabels: false -IndentGotoLabels: false +#IndentGotoLabels: false # Uncomment once on ClangFormat 10 IndentPPDirectives: AfterHash #IndentWidth: 4 #IndentWrappedFunctionNames: false @@ -122,7 +122,7 @@ SortUsingDeclarations: false #SpaceBeforeInheritanceColon: true #SpaceBeforeParens: ControlStatements SpaceBeforeRangeBasedForLoopColon: true -SpaceInEmptyBlock: false +#SpaceInEmptyBlock: false # Uncomment once on ClangFormat 10 #SpaceInEmptyParentheses: false #SpacesBeforeTrailingComments: 1 #SpacesInAngles: false diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..201a4186 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,114 @@ +name: CI + +on: + push: + pull_request: + types: [opened, reopened] + +defaults: + run: + shell: bash + +jobs: + CI: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + max-parallel: 1 + matrix: + os: [ubuntu-18.04, macos-10.15] + compiler: [ GCC, Clang ] + # Not using binary values here, to make the job captions more readable + e2ee: [ '', 'E2EE' ] + update-api: [ '', 'update-api' ] + exclude: + - os: macos-10.15 + compiler: GCC + - e2ee: '' # Somewhat reduce the number of combinations to check + update-api: 'update-api' + + steps: + - uses: actions/checkout@v2 + with: + submodules: ${{ matrix.e2ee != '' }} + + - name: Cache Qt + id: cache-qt + uses: actions/cache@v2 + with: + path: ${{ runner.workspace }}/Qt + key: ${{ runner.os }}-QtCache + + - name: Install Qt + uses: jurplel/install-qt-action@v2.11.1 + with: + version: '5.9.9' + cached: ${{ steps.cache-qt.outputs.cache-hit }} + + - name: Install Valgrind + if: contains(matrix.os, 'ubuntu') + run: | + sudo apt-get install valgrind + echo "VALGRIND=valgrind --tool=memcheck --leak-check=yes --gen-suppressions=all --suppressions=tests/.valgrind.supp" >>$GITHUB_ENV + + - name: Setup build environment + run: | + if [ "${{ matrix.compiler }}" == "GCC" ]; then + if [ -n "${{ matrix.update-api }}" ]; then VERSION_POSTFIX='-8'; fi + echo "CC=gcc$VERSION_POSTFIX" >>$GITHUB_ENV + echo "CXX=g++$VERSION_POSTFIX" >>$GITHUB_ENV + else + echo "CC=clang" >>$GITHUB_ENV + echo "CXX=clang++" >>$GITHUB_ENV + fi + echo "QUOTEST_ORIGIN=${{ runner.os }}/${{ matrix.compiler }}" >>$GITHUB_ENV + echo "DESTDIR=${{ runner.workspace }}" >>$GITHUB_ENV + echo "CMAKE_ARGS=-DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_PREFIX_PATH=${{ runner.workspace }}/usr" >>$GITHUB_ENV + cmake -E make_directory ${{ runner.workspace }}/build + + - name: Build and install olm + if: matrix.e2ee + run: | + cd ${{ runner.workspace }} + git clone https://gitlab.matrix.org/matrix-org/olm.git + pushd olm + cmake . -B build $CMAKE_ARGS + cmake --build build --target install + popd + echo "QUOTEST_ORIGIN=$QUOTEST_ORIGIN with E2EE" >>$GITHUB_ENV + + - name: Pull CS API and build GTAD + if: matrix.update-api + run: | + cd ${{ runner.workspace }} + git clone https://github.com/matrix-org/matrix-doc.git + git clone --recursive https://github.com/KitsuneRal/gtad.git + pushd gtad + cmake . $CMAKE_ARGS + cmake --build . + popd + echo "CMAKE_ARGS=$CMAKE_ARGS -DMATRIX_DOC_PATH=${{ runner.workspace }}/matrix-doc -DGTAD_PATH=${{ runner.workspace }}/gtad/gtad" >>$GITHUB_ENV + echo "QUOTEST_ORIGIN=$QUOTEST_ORIGIN and API files regeneration" >>$GITHUB_ENV + + - name: Configure libQuotient + run: cmake -S $GITHUB_WORKSPACE -B build $CMAKE_ARGS -DQuotient_ENABLE_E2EE=${{ matrix.e2ee }} + + - name: Regenerate API code + if: matrix.update-api + run: cmake --build build --target update-api + + - name: Build and install libQuotient + run: cmake --build build --target install + + - name: Build tests + run: | + cmake tests -Bbuild-test $CMAKE_ARGS + cmake --build build-test --target all + + - name: Run tests + env: + TEST_USER: ${{ secrets.TEST_USER }} + TEST_PWD: ${{ secrets.TEST_PWD }} + run: | + [[ -z "$TEST_USER" ]] || $VALGRIND build-test/quotest "$TEST_USER" "$TEST_PWD" quotest-gha '#quotest:matrix.org' "$QUOTEST_ORIGIN" + timeout-minutes: 5 # quotest is supposed to finish within 3 minutes, actually @@ -1,3 +1,8 @@ +path_classifiers: + library: + - 3rdparty/* + test: + - exclude: tests/quotest.cpp # Let alerts from this come up too extraction: cpp: prepare: diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 9982be30..00000000 --- a/.travis.yml +++ /dev/null @@ -1,116 +0,0 @@ -language: cpp -dist: bionic - -git: - depth: false - -addons: - apt: - packages: - - ninja-build - - qt5-default - - qtmultimedia5-dev - - valgrind - - g++-8 - -env: - global: - - DESTDIR="$TRAVIS_BUILD_DIR/install" - - CMAKE_ARGS="-DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_PREFIX_PATH=$DESTDIR/usr" - - VALGRIND="valgrind --tool=memcheck --leak-check=yes --gen-suppressions=all --suppressions=tests/.valgrind.supp $VALGRIND_OPTIONS" - -matrix: # TODO: consider parallel execution, this thing takes an hour to run - include: - - os: linux - compiler: gcc - - os: linux - compiler: clang - - os: osx - osx_image: xcode10.1 - env: [ 'E2EE=1', 'VALGRIND=' ] - addons: - homebrew: - update: true - packages: - - qt5 - before_cache: - - brew cleanup - cache: - directories: - - $HOME/Library/Caches/Homebrew - # Check a few more advanced configurations - - os: linux - compiler: gcc - env: [ E2EE=1, UPDATE_API=1 ] # Check UPDATE_API with one of fatter options - - os: linux - compiler: clang - env: [ E2EE=1 ] - - os: linux - compiler: gcc - env: [ E2EE=1 ] - -before_install: -- if [ -f "$(which ninja)" ]; then export CMAKE_ARGS="$CMAKE_ARGS -GNinja"; fi -- if [ "$TRAVIS_OS_NAME" = "osx" ]; then export PATH=/usr/local/opt/qt/bin:$PATH; fi -# The recent GTAD uses std::filesystem that's not available in stock bionic -- | - if [ -n "$UPDATE_API" ]; then - export CC=gcc-8 CXX=g++-8 - export CMAKE_UPDATE_API_ARGS="-DMATRIX_DOC_PATH=../matrix-doc -DGTAD_PATH=../gtad/gtad" - fi -- | - if [ -n "$E2EE" ]; then - export CMAKE_E2EE_ARGS="-DQuotient_ENABLE_E2EE=ON" - export QMAKE_E2EE_ARGS='"DEFINES += Quotient_E2EE_ENABLED USE_INTREE_LIBQOLM" "INCLUDEPATH += olm/include" "LIBS += -Lolm/build"' - export LIB_PATH_E2EE=olm/build - fi -# RPM spec-style: swallow a command with default parameters into an alias -# and add/override parameters further in the code if/as necessary -- shopt -s expand_aliases -- alias _cmake_config='cmake $CMAKE_ARGS . -Bbuild' -- alias _cmake_build='cmake --build build' - -install: -- pushd .. # Go out of libQuotient source tree -- | - if [ -n "$E2EE" ]; then - git clone https://gitlab.matrix.org/matrix-org/olm.git - pushd olm - _cmake_config - _cmake_build --target install - popd - fi - -- | - if [ -n "$UPDATE_API" ]; then - git clone https://github.com/matrix-org/matrix-doc.git - git clone --recursive https://github.com/KitsuneRal/gtad.git - pushd gtad - cmake $CMAKE_ARGS . - cmake --build . - popd - fi -- popd # back to libQuotient source tree - -before_script: -- _cmake_config $CMAKE_UPDATE_API_ARGS $CMAKE_E2EE_ARGS -- if [ -n "$UPDATE_API" ]; then _cmake_build --target update-api; fi - -script: -- _cmake_build --target install -# Build quotest with the installed libQuotient -- cmake $CMAKE_ARGS tests -Bbuild-test -- cmake --build build-test --target all -# Build with qmake -- qmake -Wall quotest.pro "CONFIG += debug" "CONFIG -= app_bundle" "QMAKE_CC = $CC" "QMAKE_CXX = $CXX" -- $QMAKE_E2EE_ARGS -- make all -# Run the qmake-compiled quotest under valgrind -- if [ "$TEST_USER" != "" ]; then LD_LIBRARY_PATH="$LIB_PATH_E2EE" $VALGRIND ./quotest "$TEST_USER" "$TEST_PWD" quotest-travis '#quotest:matrix.org' "Travis CI job $TRAVIS_JOB_NUMBER"; fi - -notifications: - webhooks: - urls: - - "https://scalar.vector.im/api/neb/services/hooks/dHJhdmlzLWNpLyU0MGtpdHN1bmUlM0FtYXRyaXgub3JnLyUyMVBDelV0eHRPalV5U3hTZWxvZiUzQW1hdHJpeC5vcmc" - on_success: change # always|never|change - on_failure: always - on_start: never diff --git a/CMakeLists.txt b/CMakeLists.txt index 4bb2bd31..29dea14a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,33 +6,19 @@ endif() set(API_VERSION "0.7") project(Quotient VERSION "${API_VERSION}.0" LANGUAGES CXX) -option(${PROJECT_NAME}_INSTALL_TESTS "install quotest (former qmc-example) application" ON) -# https://github.com/quotient-im/libQuotient/issues/369 -option(${PROJECT_NAME}_ENABLE_E2EE "end-to-end encryption (E2EE) support" OFF) +message(STATUS) +message(STATUS "Configuring ${PROJECT_NAME} ${PROJECT_VERSION} ==>") -include(CheckCXXCompilerFlag) -if (WIN32) - if (NOT CMAKE_INSTALL_LIBDIR) - set(CMAKE_INSTALL_LIBDIR ".") - endif () - - if (NOT CMAKE_INSTALL_BINDIR) - set(CMAKE_INSTALL_BINDIR ".") - endif () +include(FeatureSummary) - if (NOT CMAKE_INSTALL_INCLUDEDIR) - set(CMAKE_INSTALL_INCLUDEDIR "include") - endif () -else() - include(GNUInstallDirs) - set(INCLUDEDIR_INIT ${PROJECT_NAME}) -endif(WIN32) -set(${PROJECT_NAME}_INSTALL_INCLUDEDIR - "${CMAKE_INSTALL_INCLUDEDIR}/${INCLUDEDIR_INIT}" CACHE PATH - "directory to install ${PROJECT_NAME} include files to") +option(${PROJECT_NAME}_INSTALL_TESTS "install quotest (former qmc-example) application" ON) +add_feature_info(InstallQuotest ${PROJECT_NAME}_INSTALL_TESTS + "the library functional test suite") -# Instruct CMake to run moc automatically when needed. -set(CMAKE_AUTOMOC ON) +# https://github.com/quotient-im/libQuotient/issues/369 +option(${PROJECT_NAME}_ENABLE_E2EE "end-to-end encryption (E2EE) support" OFF) +add_feature_info(EnableE2EE ${PROJECT_NAME}_ENABLE_E2EE + "end-to-end encryption (WORK IN PROGRESS)") # Set a default build type if none was specified if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) @@ -42,7 +28,12 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") endif() +if (CMAKE_BUILD_TYPE) + message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") +endif(CMAKE_BUILD_TYPE) +message(STATUS "Using compiler: ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}" ) +include(CheckCXXCompilerFlag) if (MSVC) add_compile_options(/EHsc /W4 /wd4100 /wd4127 /wd4242 /wd4244 /wd4245 /wd4267 /wd4365 /wd4456 /wd4459 @@ -59,8 +50,34 @@ else() endforeach () endif() -find_package(Qt5 5.9 REQUIRED Network Gui Multimedia Test) +if (WIN32) + if (NOT CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR ".") + endif () + + if (NOT CMAKE_INSTALL_BINDIR) + set(CMAKE_INSTALL_BINDIR ".") + endif () + + if (NOT CMAKE_INSTALL_INCLUDEDIR) + set(CMAKE_INSTALL_INCLUDEDIR "include") + endif () +else() + include(GNUInstallDirs) + set(INCLUDEDIR_INIT ${PROJECT_NAME}) +endif(WIN32) +set(${PROJECT_NAME}_INSTALL_INCLUDEDIR + "${CMAKE_INSTALL_INCLUDEDIR}/${INCLUDEDIR_INIT}" CACHE PATH + "directory to install ${PROJECT_NAME} include files to") +message(STATUS "Install Prefix: ${CMAKE_INSTALL_PREFIX}") +message(STATUS " Header files will be installed to ${CMAKE_INSTALL_PREFIX}/${${PROJECT_NAME}_INSTALL_INCLUDEDIR}") + +# Instruct CMake to run moc automatically when needed. +set(CMAKE_AUTOMOC ON) + +find_package(Qt5 5.9 REQUIRED Core Network Gui Multimedia Test) get_filename_component(Qt5_Prefix "${Qt5_DIR}/../../../.." ABSOLUTE) +message(STATUS "Using Qt ${Qt5_VERSION} at ${Qt5_Prefix}") if (${PROJECT_NAME}_ENABLE_E2EE) if ((NOT DEFINED USE_INTREE_LIBQOLM OR USE_INTREE_LIBQOLM) @@ -71,19 +88,30 @@ if (${PROJECT_NAME}_ENABLE_E2EE) set (USE_INTREE_LIBQOLM 1) endif () endif () - if (NOT USE_INTREE_LIBQOLM) + if (USE_INTREE_LIBQOLM) + message( STATUS "Using in-tree libQtOlm") + find_package(Git QUIET) + if (GIT_FOUND) + execute_process(COMMAND + "${GIT_EXECUTABLE}" rev-parse -q HEAD + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/3rdparty/libQtOlm + OUTPUT_VARIABLE QTOLM_GIT_SHA1 + OUTPUT_STRIP_TRAILING_WHITESPACE) + message( STATUS " Library git SHA1: ${QTOLM_GIT_SHA1}") + endif (GIT_FOUND) + else () set(SAVED_CMAKE_INSTALL_INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR}) set(CMAKE_INSTALL_INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR}) find_package(QtOlm 3.0.1 REQUIRED) - if (NOT QtOlm_FOUND) - message( WARNING "libQtOlm not found; configuration will most likely fail.") - message( WARNING "Make sure you have installed libQtOlm development files") - message( WARNING "as a package or checked out the library sources in lib/.") - message( WARNING "See also BUILDING.md") - endif () + set_package_properties(QtOlm PROPERTIES + DESCRIPTION "QtOlm is a Qt wrapper around libOlm" + PURPOSE "libQtOlm is required to support end-to-end encryption. See also BUILDING.md" + URL "https://gitlab.com/b0/libqtolm" + ) + if (QtOlm_FOUND) + message(STATUS "Using libQtOlm ${QtOlm_VERSION} at ${QtOlm_DIR}") + endif() endif () -else () - message( STATUS "End-to-end encryption (E2EE) support is turned off.") endif () if (GTAD_PATH) @@ -93,52 +121,28 @@ if (MATRIX_DOC_PATH) get_filename_component(ABS_API_DEF_PATH "${MATRIX_DOC_PATH}/api" REALPATH) endif () if (ABS_GTAD_PATH AND ABS_API_DEF_PATH) + message( STATUS "Using GTAD at ${ABS_GTAD_PATH}" ) + message( STATUS "Using API files at ${ABS_API_DEF_PATH}" ) + set(API_GENERATION_ENABLED 1) if (NOT CLANG_FORMAT) set(CLANG_FORMAT clang-format) endif() get_filename_component(ABS_CLANG_FORMAT "${CLANG_FORMAT}" PROGRAM) -endif() - -message( STATUS ) -message( STATUS "=============================================================================" ) -message( STATUS " ${PROJECT_NAME} Build Information" ) -message( STATUS "=============================================================================" ) -message( STATUS "Version: ${PROJECT_VERSION}, API version: ${API_VERSION}") -if (CMAKE_BUILD_TYPE) - message( STATUS "Build type: ${CMAKE_BUILD_TYPE}") -endif(CMAKE_BUILD_TYPE) -message( STATUS "Using compiler: ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}" ) -message( STATUS "Install Prefix: ${CMAKE_INSTALL_PREFIX}" ) -message( STATUS " Header files will be installed to ${CMAKE_INSTALL_PREFIX}/${${PROJECT_NAME}_INSTALL_INCLUDEDIR}" ) -message( STATUS "Using Qt ${Qt5_VERSION} at ${Qt5_Prefix}" ) -if (ABS_API_DEF_PATH AND ABS_GTAD_PATH) - message( STATUS "Generating API stubs enabled (use --target update-api)" ) - message( STATUS " Using GTAD at ${ABS_GTAD_PATH}" ) - message( STATUS " Using API files at ${ABS_API_DEF_PATH}" ) if (ABS_CLANG_FORMAT) + set(API_FORMATTING_ENABLED 1) message( STATUS "clang-format is at ${ABS_CLANG_FORMAT}") else () message( STATUS "${CLANG_FORMAT} is NOT FOUND; API files won't be reformatted") endif () -endif () -find_package(Git) -if (${PROJECT_NAME}_ENABLE_E2EE) - if (USE_INTREE_LIBQOLM) - message( STATUS "Using in-tree libQtOlm") - if (GIT_FOUND) - execute_process(COMMAND - "${GIT_EXECUTABLE}" rev-parse -q HEAD - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/3rdparty/libQtOlm - OUTPUT_VARIABLE QTOLM_GIT_SHA1 - OUTPUT_STRIP_TRAILING_WHITESPACE) - message( STATUS " Library git SHA1: ${QTOLM_GIT_SHA1}") - endif (GIT_FOUND) - else () - message( STATUS "Using libQtOlm ${QtOlm_VERSION} at ${QtOlm_DIR}") - endif () -endif () -message( STATUS "=============================================================================" ) -message( STATUS ) +endif() +add_feature_info(EnableApiCodeGeneration "${API_GENERATION_ENABLED}" + "build target update-api") +add_feature_info(EnableApiFormatting "${API_FORMATTING_ENABLED}" + "formatting of generated API files with clang-format") + +message(STATUS) +feature_summary(WHAT ENABLED_FEATURES DISABLED_FEATURES + FATAL_ON_MISSING_REQUIRED_PACKAGES) # Set up source files set(lib_SRCS @@ -179,6 +183,7 @@ set(lib_SRCS lib/events/encryptionevent.cpp lib/events/encryptedevent.cpp lib/events/roomkeyevent.cpp + lib/events/stickerevent.cpp lib/jobs/requestdata.cpp lib/jobs/basejob.cpp lib/jobs/syncjob.cpp @@ -326,7 +331,7 @@ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}/${PROJECT_NAME}ConfigVersion.cmake" DESTINATION ${ConfigFilesLocation} ) -install(EXPORT_ANDROID_MK ${PROJECT_NAME}Targets DESTINATION share/ndk-modules) +install(EXPORT_ANDROID_MK ${PROJECT_NAME}Targets DESTINATION ${CMAKE_INSTALL_DATADIR}/ndk-modules) if (WIN32) install(FILES mime/packages/freedesktop.org.xml DESTINATION mime/packages) @@ -340,3 +345,5 @@ if (UNIX AND NOT APPLE) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) endif() + +message(STATUS "<== End of libQuotient configuration") diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 281ab5b5..bda004df 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -195,9 +195,10 @@ Additional considerations: `std::deque` for a timeline). Exposing STL containers or iterators in API intended for usage by QML code (e.g. in `Q_PROPERTY`) is unlikely to work and therefore unlikely to be accepted into `master`. -* Although `std::unique_ptr<>` gives slightly stronger guarantees, - `QScopedPointer<>` is better supported by Qt Creator's debugger UI and - therefore is preferred. + * Prefer using `std::unique_ptr<>` over `QScopedPointer<>` as it gives + stronger guarantees. Earlier revisions of this text recommended using + `QScopedPointer<>` because Qt Creator's debugger UI had a display helper + for it; it now has helpers for both. * Use `QVector` instead of `QList` where possible - see the [great article by Marc Mutz on Qt containers](https://marcmutz.wordpress.com/effective-qt/containers/) for details. @@ -228,17 +229,17 @@ an empty doc-comment line. For in-code comments, the advice is as follows: * Don't restate what's happening in the code unless it's not really obvious. We assume the readers to have at least some command of C++ and Qt. If your - code is not obvious, consider rewriting it for clarity. + code is not obvious, consider making it clearer itself before commenting. * Both C++ and Qt still come with their arcane features and dark corners, and we don't want to limit anybody who feels they have a case for - variable templates, raw literals, or use `qAsConst` to avoid container + variable templates, raw literals, or use `std::as_const` to avoid container detachment. Use your experience to figure what might be less well-known to readers and comment such cases (references to web pages, Quotient wiki etc. - are very much ok). + are very much ok, the previous bullet notwithstanding). * Make sure to document not so much "what" but more "why" certain code is done the way it is. In the worst case, the logic of the code can be - reverse-engineered; you rarely can reverse-engineer the line of reasoning and - the pitfalls avoided. + reverse-engineered; but you can almost never reverse-engineer the line of + reasoning and the pitfalls avoided. ### Automated tests @@ -301,15 +302,23 @@ can produce noticeable GUI freezing or stuttering. When you don't see a way to reduce algorithmic complexity, embed occasional `processEvents()` invocations in heavy loops (see `Connection::saveState()` to get the idea). -Having said that, there's always a trade-off between various attributes; in particular, readability and maintainability of the code is more important than squeezing every bit out of that clumsy algorithm. Beware of premature optimization and have profiling data around before going into some hardcore optimization. - -Speaking of profiling logs (see README.md on how to turn them on) - in order -to reduce small timespan logging spam, there's a default limit of at least -200 microseconds to log most operations with the `PROFILER` -(aka `quotient.profile.debug`) logging category. You can override this -limit by passing the new value (in microseconds) in `PROFILER_LOG_USECS` -definition to the compiler. If you happen to need to change it in runtime, -let me (`@kitsune`) know. +Having said that, there's always a trade-off between various attributes; +in particular, readability and maintainability of the code is more important +than squeezing every bit out of that clumsy algorithm. Beware of premature +optimization and profile the code before before diving into hardcore tweaking +that might not give the benefits you think it would. + +Speaking of profiling logs (see README.md on how to turn them on) - if you +expect some code to take considerable (more than 10k "simple operations") time +you might want to setup a `QElapsedTimer` and drop the elapsed time into logs +under `PROFILER` logging category (see the existing code for examples - +`room.cpp` has quite a few). In order to reduce small timespan logging spam, +`PROFILER` log lines are usually guarded by a check that the timer counted +some considerable time (200 microseconds by default, 20 microseconds for +tighter parts). It's possible to override this limit library-wide by passing +the new value (in microseconds) in `PROFILER_LOG_USECS` definition to +the compiler; I don't think anybody ever used this facility. If you used it, +and are reading this text - let me (`@kitsune`) know. ### Generated C++ code for CS API The code in `lib/csapi`, `lib/identity` and `lib/application-service`, although @@ -317,15 +326,9 @@ it resides in Git, is actually generated from the official Swagger/OpenAPI definition files. If you're unhappy with something in there and want to improve the code, you have to understand the way these files are produced and setup some additional tooling. The shortest possible procedure resembling -the below text can be found in .travis.yml (our Travis CI configuration -actually regenerates those files upon every build). As described below, -there is a handy build target for CMake; patches with a similar target -for qmake are (you guessed it) very welcome. -BACKUP - You can edit C++ files in these directories by hand but be -aware that any `make update-api` invocation will overwrite your changes. -If you also happen to change the API definition files, you should place the new -revision of the generated C++ files in a separate commit. +the below text can be found in .travis.yml (our CI configuration actually +regenerates those files upon every build). As described below, there is also +a handy build target for CMake. #### Why generate the code at all? Because otherwise we have to do monkey business of writing boilerplate code, @@ -414,31 +417,37 @@ The following warnings configuration is applied with GCC and Clang when using CM (the last one is to mute a warning triggered by Qt code for debug logging). We don't turn most of the warnings to errors but please treat them as such. If you use Qt Creator, the following line can be used with the Clang code model: -`-Weverything -Werror=return-type -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-unused-macros -Wno-newline-eof -Wno-exit-time-destructors -Wno-global-constructors -Wno-gnu-zero-variadic-macro-arguments -Wno-documentation -Wno-missing-prototypes -Wno-shadow-field-in-constructor -Wno-padded -Wno-weak-vtables -Wno-unknown-attributes -Wno-comma`. +`-Weverything -Werror=return-type -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-unused-macros -Wno-newline-eof -Wno-exit-time-destructors -Wno-global-constructors -Wno-gnu-zero-variadic-macro-arguments -Wno-documentation -Wno-missing-prototypes -Wno-shadow-field-in-constructor -Wno-padded -Wno-weak-vtables -Wno-unknown-attributes -Wno-comma -Wno-string-conversion -Wno-return-std-move-in-c++11`. ### Continuous Integration -We use Travis CI to check buildability and smoke-testing on Linux (GCC, Clang) and MacOS (Clang), and AppVeyor CI to build on Windows (MSVC). Every PR will go through these, and you'll see the traffic lights from them on the PR page. If your PR fails on any platform double-check that it's not your code causing it - and fix it if it is. +We use CI to check buildability and smoke-testing on Linux (GCC, Clang), +MacOS (Clang), and Windows (MSVC). Every PR will go through these, and you'll +see the traffic lights from them on the PR page. If your PR fails +on any platform double-check that it's not your code causing it - and fix +(or ask how to fix if you don't know) if it is. ### clang-format We strongly recommend using clang-format or, even better, use an IDE that -supports it. This will lay a tedious task of following the assumed -code style from your shoulders over to your computer. +supports it. This will lay over a tedious task of following the assumed +code style from your shoulders (and fingers) to your computer. ### Other tools Recent versions of Qt Creator and CLion can automatically run your code through -clang-tidy. The following list of clang-tidy checks slows Qt Creator analysis -quite considerably but gives a good insight without too many false positives: -`-*,bugprone-argument-comment,bugprone-assert-side-effect,bugprone-bool-pointer-implicit-conversion,bugprone-copy-constructor-init,bugprone-dangling-handle,bugprone-fold-init-type,bugprone-forward-declaration-namespace,bugprone-inaccurate-erase,bugprone-integer-division,bugprone-move-forwarding-reference,bugprone-string-constructor,bugprone-undefined-memory-manipulation,bugprone-use-after-move,bugprone-virtual-near-miss,cert-dcl03-c,cert-dcl21-cpp,cert-dcl50-cpp,cert-dcl54-cpp,cert-dcl58-cpp,cert-env33-c,cert-err09-cpp,cert-err34-c,cert-err52-cpp,cert-err60-cpp,cert-err61-cpp,cert-fio38-c,cert-flp30-c,cert-msc30-c,cert-msc50-cpp,cert-oop11-cpp,cppcoreguidelines-c-copy-assignment-signature,cppcoreguidelines-pro-type-cstyle-cast,cppcoreguidelines-slicing,hicpp-deprecated-headers,hicpp-invalid-access-moved,hicpp-member-init,hicpp-move-const-arg,hicpp-named-parameter,hicpp-new-delete-operators,hicpp-static-assert,hicpp-undelegated-constructor,hicpp-use-*,misc-misplaced-const,misc-new-delete-overloads,misc-non-copyable-objects,misc-redundant-expression,misc-static-assert,misc-throw-by-value-catch-by-reference,misc-unconventional-assign-operator,misc-uniqueptr-reset-release,misc-unused-*,modernize-loop-convert,modernize-pass-by-value,modernize-return-braced-init-list,modernize-shrink-to-fit,modernize-unary-static-assert,modernize-use-*,performance-faster-string-find,performance-for-range-copy,performance-implicit-conversion-in-loop,performance-inefficient-*,performance-move-*,performance-type-promotion-in-math-fn,performance-unnecessary-*,readability-delete-null-pointer,readability-else-after-return,readability-inconsistent-declaration-parameter-name,readability-misleading-indentation,readability-redundant-*,readability-simplify-boolean-expr,readability-static-definition-in-anonymous-namespace,readability-uniqueptr-delete-release`. +clang-tidy. The following list of clang-tidy checks gives a good insight +without too many false positives: +`-*,bugprone-argument-comment,bugprone-assert-side-effect,bugprone-bool-pointer-implicit-conversion,bugprone-copy-constructor-init,bugprone-dangling-handle,bugprone-fold-init-type,bugprone-forward-declaration-namespace,bugprone-forwarding-reference-overload,bugprone-inaccurate-erase,bugprone-integer-division,bugprone-lambda-function-name,bugprone-macro-*,bugprone-move-forwarding-reference,bugprone-multiple-statement-macro,bugprone-parent-virtual-call,bugprone-signed-char-misuse,bugprone-sizeof-*,bugprone-string-constructor,bugprone-string-integer-assignment,bugprone-suspicious-*,bugprone-terminating-continue,bugprone-undefined-memory-manipulation,bugprone-undelegated-constructor,bugprone-unused-*,bugprone-use-after-move,bugprone-virtual-near-miss,cert-dcl03-c,cert-dcl21-cpp,cert-dcl50-cpp,cert-dcl54-cpp,cert-dcl58-cpp,cert-env33-c,cert-err09-cpp,cert-err34-c,cert-err52-cpp,cert-err60-cpp,cert-err61-cpp,cert-fio38-c,cert-flp30-c,cert-msc30-c,cert-msc50-cpp,cert-oop11-cpp,clang-analyzer-apiModeling.StdCLibraryFunctions,clang-analyzer-core.CallAndMessage,clang-analyzer-core.NullDereference,clang-analyzer-cplusplus.*,clang-analyzer-optin.cplusplus.*,cppcoreguidelines-c-copy-assignment-signature,cppcoreguidelines-non-private-member-variables-in-classes,cppcoreguidelines-pro-type-cstyle-cast,cppcoreguidelines-slicing,hicpp-deprecated-headers,hicpp-invalid-access-moved,hicpp-member-init,hicpp-move-const-arg,hicpp-new-delete-operators,hicpp-static-assert,hicpp-undelegated-constructor,hicpp-use-*,misc-*,-misc-definitions-in-headers,-misc-no-recursion,-misc-non-private-member-variables-in-classes,modernize-loop-convert,modernize-pass-by-value,modernize-return-braced-init-list,modernize-shrink-to-fit,modernize-unary-static-assert,modernize-use-*,-modernize-use-trailing-return-type,performance-*,-performance-no-automatic-move,-performance-noexcept-move-constructor,-performance-unnecessary-*,readability-*,-readability-braces-around-statements,-readability-implicit-bool-conversion,-readability-isolate-declaration,-readability-magic-numbers,-readability-named-parameter,-readability-qualified-auto`. Qt Creator, in addition, knows about clazy, an even deeper Qt-aware static -analysis tool. Even level 1 clazy eats away CPU but produces some very relevant -notices that are easy to overlook otherwise, such as possible unintended copying -of a Qt container, or unguarded null pointers. You can use this time to time +analysis tool that produces some notices about Qt-specific issues that are +easy to overlook otherwise, such as possible unintended copying of +a Qt container, or unguarded null pointers. You can use this time to time (see Analyze menu in Qt Creator) instead of hogging your machine with -deep analysis as you type. +deep analysis as you type (or after each saving, depending on your version +of Qt Creator). Most of clazy checks are relevant to our code, except: +`fully-qualified-moc-types,overloaded-signal,qstring-comparison-to-implicit-char,foreach,non-pod-global-static,qstring-allocations,jni-signatures,qt4-qstring-from-array`. ### Submitting API changes diff --git a/LICENSES/LGPL-2.1-or-later.txt b/LICENSES/LGPL-2.1-or-later.txt new file mode 100644 index 00000000..aaaba168 --- /dev/null +++ b/LICENSES/LGPL-2.1-or-later.txt @@ -0,0 +1,462 @@ +GNU LESSER GENERAL PUBLIC LICENSE + +Version 2.1, February 1999 + +Copyright (C) 1991, 1999 Free Software Foundation, Inc. +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Everyone is permitted to copy and distribute verbatim copies of this license +document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts as +the successor of the GNU Library Public License, version 2, hence the version +number 2.1.] + +Preamble + +The licenses for most software are designed to take away your freedom to share +and change it. By contrast, the GNU General Public Licenses are intended to +guarantee your freedom to share and change free software--to make sure the +software is free for all its users. + +This license, the Lesser General Public License, applies to some specially +designated software packages--typically libraries--of the Free Software Foundation +and other authors who decide to use it. You can use it too, but we suggest +you first think carefully about whether this license or the ordinary General +Public License is the better strategy to use in any particular case, based +on the explanations below. + +When we speak of free software, we are referring to freedom of use, not price. +Our General Public Licenses are designed to make sure that you have the freedom +to distribute copies of free software (and charge for this service if you +wish); that you receive source code or can get it if you want it; that you +can change the software and use pieces of it in new free programs; and that +you are informed that you can do these things. + +To protect your rights, we need to make restrictions that forbid distributors +to deny you these rights or to ask you to surrender these rights. These restrictions +translate to certain responsibilities for you if you distribute copies of +the library or if you modify it. + +For example, if you distribute copies of the library, whether gratis or for +a fee, you must give the recipients all the rights that we gave you. You must +make sure that they, too, receive or can get the source code. If you link +other code with the library, you must provide complete object files to the +recipients, so that they can relink them with the library after making changes +to the library and recompiling it. And you must show them these terms so they +know their rights. + +We protect your rights with a two-step method: (1) we copyright the library, +and (2) we offer you this license, which gives you legal permission to copy, +distribute and/or modify the library. + +To protect each distributor, we want to make it very clear that there is no +warranty for the free library. Also, if the library is modified by someone +else and passed on, the recipients should know that what they have is not +the original version, so that the original author's reputation will not be +affected by problems that might be introduced by others. + +Finally, software patents pose a constant threat to the existence of any free +program. We wish to make sure that a company cannot effectively restrict the +users of a free program by obtaining a restrictive license from a patent holder. +Therefore, we insist that any patent license obtained for a version of the +library must be consistent with the full freedom of use specified in this +license. + +Most GNU software, including some libraries, is covered by the ordinary GNU +General Public License. This license, the GNU Lesser General Public License, +applies to certain designated libraries, and is quite different from the ordinary +General Public License. We use this license for certain libraries in order +to permit linking those libraries into non-free programs. + +When a program is linked with a library, whether statically or using a shared +library, the combination of the two is legally speaking a combined work, a +derivative of the original library. The ordinary General Public License therefore +permits such linking only if the entire combination fits its criteria of freedom. +The Lesser General Public License permits more lax criteria for linking other +code with the library. + +We call this license the "Lesser" General Public License because it does Less +to protect the user's freedom than the ordinary General Public License. It +also provides other free software developers Less of an advantage over competing +non-free programs. These disadvantages are the reason we use the ordinary +General Public License for many libraries. However, the Lesser license provides +advantages in certain special circumstances. + +For example, on rare occasions, there may be a special need to encourage the +widest possible use of a certain library, so that it becomes a de-facto standard. +To achieve this, non-free programs must be allowed to use the library. A more +frequent case is that a free library does the same job as widely used non-free +libraries. In this case, there is little to gain by limiting the free library +to free software only, so we use the Lesser General Public License. + +In other cases, permission to use a particular library in non-free programs +enables a greater number of people to use a large body of free software. For +example, permission to use the GNU C Library in non-free programs enables +many more people to use the whole GNU operating system, as well as its variant, +the GNU/Linux operating system. + +Although the Lesser General Public License is Less protective of the users' +freedom, it does ensure that the user of a program that is linked with the +Library has the freedom and the wherewithal to run that program using a modified +version of the Library. + +The precise terms and conditions for copying, distribution and modification +follow. Pay close attention to the difference between a "work based on the +library" and a "work that uses the library". The former contains code derived +from the library, whereas the latter must be combined with the library in +order to run. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License Agreement applies to any software library or other program +which contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Lesser General +Public License (also called "this License"). Each licensee is addressed as +"you". + +A "library" means a collection of software functions and/or data prepared +so as to be conveniently linked with application programs (which use some +of those functions and data) to form executables. + +The "Library", below, refers to any such software library or work which has +been distributed under these terms. A "work based on the Library" means either +the Library or any derivative work under copyright law: that is to say, a +work containing the Library or a portion of it, either verbatim or with modifications +and/or translated straightforwardly into another language. (Hereinafter, translation +is included without limitation in the term "modification".) + +"Source code" for a work means the preferred form of the work for making modifications +to it. For a library, complete source code means all the source code for all +modules it contains, plus any associated interface definition files, plus +the scripts used to control compilation and installation of the library. + +Activities other than copying, distribution and modification are not covered +by this License; they are outside its scope. The act of running a program +using the Library is not restricted, and output from such a program is covered +only if its contents constitute a work based on the Library (independent of +the use of the Library in a tool for writing it). Whether that is true depends +on what the Library does and what the program that uses the Library does. + +1. You may copy and distribute verbatim copies of the Library's complete source +code as you receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice and disclaimer +of warranty; keep intact all the notices that refer to this License and to +the absence of any warranty; and distribute a copy of this License along with +the Library. + +You may charge a fee for the physical act of transferring a copy, and you +may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Library or any portion of it, +thus forming a work based on the Library, and copy and distribute such modifications +or work under the terms of Section 1 above, provided that you also meet all +of these conditions: + + a) The modified work must itself be a software library. + +b) You must cause the files modified to carry prominent notices stating that +you changed the files and the date of any change. + +c) You must cause the whole of the work to be licensed at no charge to all +third parties under the terms of this License. + +d) If a facility in the modified Library refers to a function or a table of +data to be supplied by an application program that uses the facility, other +than as an argument passed when the facility is invoked, then you must make +a good faith effort to ensure that, in the event an application does not supply +such function or table, the facility still operates, and performs whatever +part of its purpose remains meaningful. + +(For example, a function in a library to compute square roots has a purpose +that is entirely well-defined independent of the application. Therefore, Subsection +2d requires that any application-supplied function or table used by this function +must be optional: if the application does not supply it, the square root function +must still compute square roots.) + +These requirements apply to the modified work as a whole. If identifiable +sections of that work are not derived from the Library, and can be reasonably +considered independent and separate works in themselves, then this License, +and its terms, do not apply to those sections when you distribute them as +separate works. But when you distribute the same sections as part of a whole +which is a work based on the Library, the distribution of the whole must be +on the terms of this License, whose permissions for other licensees extend +to the entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest your +rights to work written entirely by you; rather, the intent is to exercise +the right to control the distribution of derivative or collective works based +on the Library. + +In addition, mere aggregation of another work not based on the Library with +the Library (or with a work based on the Library) on a volume of a storage +or distribution medium does not bring the other work under the scope of this +License. + +3. You may opt to apply the terms of the ordinary GNU General Public License +instead of this License to a given copy of the Library. To do this, you must +alter all the notices that refer to this License, so that they refer to the +ordinary GNU General Public License, version 2, instead of to this License. +(If a newer version than version 2 of the ordinary GNU General Public License +has appeared, then you can specify that version instead if you wish.) Do not +make any other change in these notices. + +Once this change is made in a given copy, it is irreversible for that copy, +so the ordinary GNU General Public License applies to all subsequent copies +and derivative works made from that copy. + +This option is useful when you wish to copy part of the code of the Library +into a program that is not a library. + +4. You may copy and distribute the Library (or a portion or derivative of +it, under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you accompany it with the complete corresponding +machine-readable source code, which must be distributed under the terms of +Sections 1 and 2 above on a medium customarily used for software interchange. + +If distribution of object code is made by offering access to copy from a designated +place, then offering equivalent access to copy the source code from the same +place satisfies the requirement to distribute the source code, even though +third parties are not compelled to copy the source along with the object code. + +5. A program that contains no derivative of any portion of the Library, but +is designed to work with the Library by being compiled or linked with it, +is called a "work that uses the Library". Such a work, in isolation, is not +a derivative work of the Library, and therefore falls outside the scope of +this License. + +However, linking a "work that uses the Library" with the Library creates an +executable that is a derivative of the Library (because it contains portions +of the Library), rather than a "work that uses the library". The executable +is therefore covered by this License. Section 6 states terms for distribution +of such executables. + +When a "work that uses the Library" uses material from a header file that +is part of the Library, the object code for the work may be a derivative work +of the Library even though the source code is not. Whether this is true is +especially significant if the work can be linked without the Library, or if +the work is itself a library. The threshold for this to be true is not precisely +defined by law. + +If such an object file uses only numerical parameters, data structure layouts +and accessors, and small macros and small inline functions (ten lines or less +in length), then the use of the object file is unrestricted, regardless of +whether it is legally a derivative work. (Executables containing this object +code plus portions of the Library will still fall under Section 6.) + +Otherwise, if the work is a derivative of the Library, you may distribute +the object code for the work under the terms of Section 6. Any executables +containing that work also fall under Section 6, whether or not they are linked +directly with the Library itself. + +6. As an exception to the Sections above, you may also combine or link a "work +that uses the Library" with the Library to produce a work containing portions +of the Library, and distribute that work under terms of your choice, provided +that the terms permit modification of the work for the customer's own use +and reverse engineering for debugging such modifications. + +You must give prominent notice with each copy of the work that the Library +is used in it and that the Library and its use are covered by this License. +You must supply a copy of this License. If the work during execution displays +copyright notices, you must include the copyright notice for the Library among +them, as well as a reference directing the user to the copy of this License. +Also, you must do one of these things: + +a) Accompany the work with the complete corresponding machine-readable source +code for the Library including whatever changes were used in the work (which +must be distributed under Sections 1 and 2 above); and, if the work is an +executable linked with the Library, with the complete machine-readable "work +that uses the Library", as object code and/or source code, so that the user +can modify the Library and then relink to produce a modified executable containing +the modified Library. (It is understood that the user who changes the contents +of definitions files in the Library will not necessarily be able to recompile +the application to use the modified definitions.) + +b) Use a suitable shared library mechanism for linking with the Library. A +suitable mechanism is one that (1) uses at run time a copy of the library +already present on the user's computer system, rather than copying library +functions into the executable, and (2) will operate properly with a modified +version of the library, if the user installs one, as long as the modified +version is interface-compatible with the version that the work was made with. + +c) Accompany the work with a written offer, valid for at least three years, +to give the same user the materials specified in Subsection 6a, above, for +a charge no more than the cost of performing this distribution. + +d) If distribution of the work is made by offering access to copy from a designated +place, offer equivalent access to copy the above specified materials from +the same place. + +e) Verify that the user has already received a copy of these materials or +that you have already sent this user a copy. + +For an executable, the required form of the "work that uses the Library" must +include any data and utility programs needed for reproducing the executable +from it. However, as a special exception, the materials to be distributed +need not include anything that is normally distributed (in either source or +binary form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component itself +accompanies the executable. + +It may happen that this requirement contradicts the license restrictions of +other proprietary libraries that do not normally accompany the operating system. +Such a contradiction means you cannot use both them and the Library together +in an executable that you distribute. + +7. You may place library facilities that are a work based on the Library side-by-side +in a single library together with other library facilities not covered by +this License, and distribute such a combined library, provided that the separate +distribution of the work based on the Library and of the other library facilities +is otherwise permitted, and provided that you do these two things: + +a) Accompany the combined library with a copy of the same work based on the +Library, uncombined with any other library facilities. This must be distributed +under the terms of the Sections above. + +b) Give prominent notice with the combined library of the fact that part of +it is a work based on the Library, and explaining where to find the accompanying +uncombined form of the same work. + +8. You may not copy, modify, sublicense, link with, or distribute the Library +except as expressly provided under this License. Any attempt otherwise to +copy, modify, sublicense, link with, or distribute the Library is void, and +will automatically terminate your rights under this License. However, parties +who have received copies, or rights, from you under this License will not +have their licenses terminated so long as such parties remain in full compliance. + +9. You are not required to accept this License, since you have not signed +it. However, nothing else grants you permission to modify or distribute the +Library or its derivative works. These actions are prohibited by law if you +do not accept this License. Therefore, by modifying or distributing the Library +(or any work based on the Library), you indicate your acceptance of this License +to do so, and all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + +10. Each time you redistribute the Library (or any work based on the Library), +the recipient automatically receives a license from the original licensor +to copy, distribute, link with or modify the Library subject to these terms +and conditions. You may not impose any further restrictions on the recipients' +exercise of the rights granted herein. You are not responsible for enforcing +compliance by third parties with this License. + +11. If, as a consequence of a court judgment or allegation of patent infringement +or for any other reason (not limited to patent issues), conditions are imposed +on you (whether by court order, agreement or otherwise) that contradict the +conditions of this License, they do not excuse you from the conditions of +this License. If you cannot distribute so as to satisfy simultaneously your +obligations under this License and any other pertinent obligations, then as +a consequence you may not distribute the Library at all. For example, if a +patent license would not permit royalty-free redistribution of the Library +by all those who receive copies directly or indirectly through you, then the +only way you could satisfy both it and this License would be to refrain entirely +from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents +or other property right claims or to contest validity of any such claims; +this section has the sole purpose of protecting the integrity of the free +software distribution system which is implemented by public license practices. +Many people have made generous contributions to the wide range of software +distributed through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing to +distribute software through any other system and a licensee cannot impose +that choice. + +This section is intended to make thoroughly clear what is believed to be a +consequence of the rest of this License. + +12. If the distribution and/or use of the Library is restricted in certain +countries either by patents or by copyrighted interfaces, the original copyright +holder who places the Library under this License may add an explicit geographical +distribution limitation excluding those countries, so that distribution is +permitted only in or among countries not thus excluded. In such case, this +License incorporates the limitation as if written in the body of this License. + +13. The Free Software Foundation may publish revised and/or new versions of +the Lesser General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to address +new problems or concerns. + +Each version is given a distinguishing version number. If the Library specifies +a version number of this License which applies to it and "any later version", +you have the option of following the terms and conditions either of that version +or of any later version published by the Free Software Foundation. If the +Library does not specify a license version number, you may choose any version +ever published by the Free Software Foundation. + +14. If you wish to incorporate parts of the Library into other free programs +whose distribution conditions are incompatible with these, write to the author +to ask for permission. For software which is copyrighted by the Free Software +Foundation, write to the Free Software Foundation; we sometimes make exceptions +for this. Our decision will be guided by the two goals of preserving the free +status of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + +NO WARRANTY + +15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR +THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE +STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY +"AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE +OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE +THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE +OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA +OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES +OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH +HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Libraries + +If you develop a new library, and you want it to be of the greatest possible +use to the public, we recommend making it free software that everyone can +redistribute and change. You can do so by permitting redistribution under +these terms (or, alternatively, under the terms of the ordinary General Public +License). + +To apply these terms, attach the following notices to the library. It is safest +to attach them to the start of each source file to most effectively convey +the exclusion of warranty; and each file should have at least the "copyright" +line and a pointer to where the full notice is found. + + one line to give the library's name and an idea of what it does. + Copyright (C) year name of author + +This library is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser General Public License as published by the Free +Software Foundation; either version 2.1 of the License, or (at your option) +any later version. + +This library 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 Lesser General Public License for more +details. + +You should have received a copy of the GNU Lesser General Public License along +with this library; if not, write to the Free Software Foundation, Inc., 51 +Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information +on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your school, +if any, to sign a "copyright disclaimer" for the library, if necessary. Here +is a sample; alter the names: + +Yoyodyne, Inc., hereby disclaims all copyright interest in +the library `Frob' (a library for tweaking knobs) written +by James Random Hacker. + +signature of Ty Coon, 1 April 1990 +Ty Coon, President of Vice +That's all there is to it! diff --git a/lib/avatar.cpp b/lib/avatar.cpp index c65aa25c..0573df5d 100644 --- a/lib/avatar.cpp +++ b/lib/avatar.cpp @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2017 Kitsune Ral <kitsune-ral@users.sf.net> + * SPDX-FileCopyrightText: 2017 Kitsune Ral <kitsune-ral@users.sf.net> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "avatar.h" @@ -37,9 +25,9 @@ public: explicit Private(QUrl url = {}) : _url(move(url)) {} ~Private() { - if (isJobRunning(_thumbnailRequest)) + if (isJobPending(_thumbnailRequest)) _thumbnailRequest->abandon(); - if (isJobRunning(_uploadRequest)) + if (isJobPending(_uploadRequest)) _uploadRequest->abandon(); } @@ -87,7 +75,7 @@ QImage Avatar::get(Connection* connection, int width, int height, bool Avatar::upload(Connection* connection, const QString& fileName, upload_callback_t callback) const { - if (isJobRunning(d->_uploadRequest)) + if (isJobPending(d->_uploadRequest)) return false; return d->upload(connection->uploadFile(fileName), move(callback)); } @@ -95,7 +83,7 @@ bool Avatar::upload(Connection* connection, const QString& fileName, bool Avatar::upload(Connection* connection, QIODevice* source, upload_callback_t callback) const { - if (isJobRunning(d->_uploadRequest) || !source->isReadable()) + if (isJobPending(d->_uploadRequest) || !source->isReadable()) return false; return d->upload(connection->uploadContent(source), move(callback)); } @@ -125,7 +113,7 @@ QImage Avatar::Private::get(Connection* connection, QSize size, && checkUrl(_url)) { qCDebug(MAIN) << "Getting avatar from" << _url.toString(); _requestedSize = size; - if (isJobRunning(_thumbnailRequest)) + if (isJobPending(_thumbnailRequest)) _thumbnailRequest->abandon(); if (callback) callbacks.emplace_back(move(callback)); @@ -157,7 +145,7 @@ QImage Avatar::Private::get(Connection* connection, QSize size, bool Avatar::Private::upload(UploadContentJob* job, upload_callback_t &&callback) { _uploadRequest = job; - if (!isJobRunning(_uploadRequest)) + if (!isJobPending(_uploadRequest)) return false; _uploadRequest->connect(_uploadRequest, &BaseJob::success, _uploadRequest, [job, callback] { callback(job->contentUri()); }); @@ -194,7 +182,7 @@ bool Avatar::updateUrl(const QUrl& newUrl) d->_url = newUrl; d->_imageSource = Private::Unknown; - if (isJobRunning(d->_thumbnailRequest)) + if (isJobPending(d->_thumbnailRequest)) d->_thumbnailRequest->abandon(); return true; } diff --git a/lib/avatar.h b/lib/avatar.h index 7a566bfa..111f565d 100644 --- a/lib/avatar.h +++ b/lib/avatar.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2017 Kitsune Ral <kitsune-ral@users.sf.net> + * SPDX-FileCopyrightText: 2017 Kitsune Ral <kitsune-ral@users.sf.net> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once diff --git a/lib/connection.cpp b/lib/connection.cpp index 2a86d2eb..015e73c9 100644 --- a/lib/connection.cpp +++ b/lib/connection.cpp @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2015 Felix Rohrbach <kde@fxrh.de> + * SPDX-FileCopyrightText: 2015 Felix Rohrbach <kde@fxrh.de> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "connection.h" @@ -37,6 +25,7 @@ #include "csapi/versions.h" #include "csapi/voip.h" #include "csapi/wellknown.h" +#include "csapi/whoami.h" #include "events/directchatevent.h" #include "events/eventloader.h" @@ -133,10 +122,27 @@ public: != "json"; bool lazyLoading = false; + /** \brief Check the homeserver and resolve it if needed, before connecting + * + * A single entry for functions that need to check whether the homeserver + * is valid before running. May execute connectFn either synchronously + * or asynchronously. In case of errors, emits resolveError() if + * the homeserver URL is not valid and cannot be resolved from userId, or + * the homeserver doesn't support the requested login flow. + * + * \param userId fully-qualified MXID to resolve HS from + * \param connectFn a function to execute once the HS URL is good + * \param flow optionally, a login flow that should be supported for + * connectFn to work; `none`, if there's no login flow + * requirements + * \sa resolveServer, resolveError + */ + void checkAndConnect(const QString &userId, + const std::function<void ()> &connectFn, + const std::optional<LoginFlow> &flow = none); template <typename... LoginArgTs> void loginToServer(LoginArgTs&&... loginArgs); - void assumeIdentity(const QString& userId, const QString& accessToken, - const QString& deviceId); + void completeSetup(const QString &mxId); void removeRoom(const QString& roomId); void consumeRoomData(SyncDataList&& roomDataList, bool fromCache); @@ -253,7 +259,7 @@ Connection::~Connection() void Connection::resolveServer(const QString& mxid) { - if (isJobRunning(d->resolverJob)) + if (isJobPending(d->resolverJob)) d->resolverJob->abandon(); auto maybeBaseUrl = QUrl::fromUserInput(serverPart(mxid)); @@ -264,14 +270,21 @@ void Connection::resolveServer(const QString& mxid) return; } - auto domain = maybeBaseUrl.host(); - qCDebug(MAIN) << "Finding the server" << domain; + qCDebug(MAIN) << "Finding the server" << maybeBaseUrl.host(); - d->data->setBaseUrl(maybeBaseUrl); // Just enough to check .well-known file + const auto& oldBaseUrl = d->data->baseUrl(); + d->data->setBaseUrl(maybeBaseUrl); // Temporarily set it for this one call d->resolverJob = callApi<GetWellknownJob>(); - connect(d->resolverJob, &BaseJob::finished, this, [this, maybeBaseUrl] { - if (d->resolverJob->status() != BaseJob::NotFoundError) { - if (d->resolverJob->status() != BaseJob::Success) { + // Connect to finished() to make sure baseUrl is restored in any case + connect(d->resolverJob, &BaseJob::finished, this, [this, maybeBaseUrl, oldBaseUrl] { + // Revert baseUrl so that setHomeserver() below triggers signals + // in case the base URL actually changed + d->data->setBaseUrl(oldBaseUrl); + if (d->resolverJob->error() == BaseJob::Abandoned) + return; + + if (d->resolverJob->error() != BaseJob::NotFoundError) { + if (!d->resolverJob->status().good()) { qCWarning(MAIN) << "Fetching .well-known file failed, FAIL_PROMPT"; emit resolveError(tr("Failed resolving the homeserver")); @@ -297,12 +310,12 @@ void Connection::resolveServer(const QString& mxid) << "for base URL"; setHomeserver(maybeBaseUrl); } + Q_ASSERT(d->loginFlowsJob != nullptr); // Ensured by setHomeserver() connect(d->loginFlowsJob, &BaseJob::success, this, &Connection::resolved); connect(d->loginFlowsJob, &BaseJob::failure, this, [this] { qCWarning(MAIN) << "Homeserver base URL sanity check failed"; - emit resolveError( - tr("The homeserver base URL doesn't seem to work")); + emit resolveError(tr("The homeserver doesn't seem to be working")); }); }); } @@ -325,10 +338,10 @@ void Connection::loginWithPassword(const QString& userId, const QString& initialDeviceName, const QString& deviceId) { - checkAndConnect(userId, [=] { + d->checkAndConnect(userId, [=] { d->loginToServer(LoginFlows::Password.type, makeUserIdentifier(userId), password, /*token*/ "", deviceId, initialDeviceName); - }); + }, LoginFlows::Password); } SsoSession* Connection::prepareForSso(const QString& initialDeviceName, @@ -341,17 +354,30 @@ void Connection::loginWithToken(const QByteArray& loginToken, const QString& initialDeviceName, const QString& deviceId) { + Q_ASSERT(d->data->baseUrl().isValid() && d->loginFlows.contains(LoginFlows::Token)); d->loginToServer(LoginFlows::Token.type, none /*user is encoded in loginToken*/, "" /*password*/, loginToken, deviceId, initialDeviceName); } -void Connection::assumeIdentity(const QString& userId, - const QString& accessToken, +void Connection::assumeIdentity(const QString& mxId, const QString& accessToken, const QString& deviceId) { - checkAndConnect(userId, - [=] { d->assumeIdentity(userId, accessToken, deviceId); }); + d->checkAndConnect(mxId, [this, mxId, accessToken, deviceId] { + d->data->setToken(accessToken.toLatin1()); + d->data->setDeviceId(deviceId); // Can't we deduce this from access_token? + auto* job = callApi<GetTokenOwnerJob>(); + connect(job, &BaseJob::success, this, [this, job, mxId] { + if (mxId != job->userId()) + qCWarning(MAIN).nospace() + << "The access_token owner (" << job->userId() + << ") is different from passed MXID (" << mxId << ")!"; + d->completeSetup(job->userId()); + }); + connect(job, &BaseJob::failure, this, [this, job] { + emit loginError(job->errorString(), job->rawDataSample()); + }); + }); } void Connection::reloadCapabilities() @@ -391,8 +417,9 @@ void Connection::Private::loginToServer(LoginArgTs&&... loginArgs) auto loginJob = q->callApi<LoginJob>(std::forward<LoginArgTs>(loginArgs)...); connect(loginJob, &BaseJob::success, q, [this, loginJob] { - assumeIdentity(loginJob->userId(), loginJob->accessToken(), - loginJob->deviceId()); + data->setToken(loginJob->accessToken().toLatin1()); + data->setDeviceId(loginJob->deviceId()); + completeSetup(loginJob->userId()); #ifndef Quotient_E2EE_ENABLED qCWarning(E2EE) << "End-to-end encryption (E2EE) support is turned off."; #else // Quotient_E2EE_ENABLED @@ -405,21 +432,18 @@ void Connection::Private::loginToServer(LoginArgTs&&... loginArgs) }); } -void Connection::Private::assumeIdentity(const QString& userId, - const QString& accessToken, - const QString& deviceId) +void Connection::Private::completeSetup(const QString& mxId) { - data->setUserId(userId); + data->setUserId(mxId); q->user(); // Creates a User object for the local user - data->setToken(accessToken.toLatin1()); - data->setDeviceId(deviceId); - q->setObjectName(userId % '/' % deviceId); + q->setObjectName(data->userId() % '/' % data->deviceId()); qCDebug(MAIN) << "Using server" << data->baseUrl().toDisplayString() - << "by user" << userId << "from device" << deviceId; + << "by user" << data->userId() + << "from device" << data->deviceId(); #ifndef Quotient_E2EE_ENABLED qCWarning(E2EE) << "End-to-end encryption (E2EE) support is turned off."; #else // Quotient_E2EE_ENABLED - AccountSettings accountSettings(userId); + AccountSettings accountSettings(data->userId()); encryptionManager.reset( new EncryptionManager(accountSettings.encryptionAccountPickle())); if (accountSettings.encryptionAccountPickle().isEmpty()) { @@ -432,22 +456,37 @@ void Connection::Private::assumeIdentity(const QString& userId, q->reloadCapabilities(); } -void Connection::checkAndConnect(const QString& userId, - std::function<void()> connectFn) +void Connection::Private::checkAndConnect(const QString& userId, + const std::function<void()>& connectFn, + const std::optional<LoginFlow>& flow) { - if (d->data->baseUrl().isValid()) { + if (data->baseUrl().isValid() && (!flow || loginFlows.contains(*flow))) { connectFn(); return; } - // Not good to go, try to fix the homeserver URL. + // Not good to go, try to ascertain the homeserver URL and flows if (userId.startsWith('@') && userId.indexOf(':') != -1) { - connectSingleShot(this, &Connection::homeserverChanged, this, connectFn); - // NB: doResolveServer can emit resolveError, so this is a part of - // checkAndConnect function contract. - resolveServer(userId); + q->resolveServer(userId); + if (flow) + connectSingleShot(q, &Connection::loginFlowsChanged, q, + [this, flow, connectFn] { + if (loginFlows.contains(*flow)) + connectFn(); + else + emit q->loginError( + tr("The homeserver at %1 does not support" + " the login flow '%2'") + .arg(data->baseUrl().toDisplayString()), + flow->type); + }); + else + connectSingleShot(q, &Connection::homeserverChanged, q, connectFn); } else - emit resolveError(tr("%1 is an invalid homeserver URL") - .arg(d->data->baseUrl().toString())); + emit q->resolveError(tr("Please provide the fully-qualified user id" + " (such as @user:example.org) so that the" + " homeserver could be resolved; the current" + " homeserver URL(%1) is not good") + .arg(data->baseUrl().toDisplayString())); } void Connection::logout() @@ -932,7 +971,7 @@ void Connection::doInDirectChat(User* u, // not left), and delete inexistent (forgotten?) ones along the way. DirectChatsMap removals; for (auto it = d->directChats.constFind(u); - it != d->directChats.constEnd() && it.key() == u; ++it) { + it != d->directChats.cend() && it.key() == u; ++it) { const auto& roomId = *it; if (auto r = room(roomId, JoinState::Join)) { Q_ASSERT(r->id() == roomId); @@ -1178,7 +1217,7 @@ QByteArray Connection::accessToken() const { // The logout job needs access token to do its job; so the token is // kept inside d->data but no more exposed to the outside world. - return isJobRunning(d->logoutJob) ? QByteArray() : d->data->accessToken(); + return isJobPending(d->logoutJob) ? QByteArray() : d->data->accessToken(); } bool Connection::isLoggedIn() const { return !accessToken().isEmpty(); } @@ -1493,12 +1532,10 @@ QByteArray Connection::generateTxnId() const void Connection::setHomeserver(const QUrl& url) { - if (isJobRunning(d->resolverJob)) + if (isJobPending(d->resolverJob)) d->resolverJob->abandon(); - d->resolverJob = nullptr; - if (isJobRunning(d->loginFlowsJob)) + if (isJobPending(d->loginFlowsJob)) d->loginFlowsJob->abandon(); - d->loginFlowsJob = nullptr; d->loginFlows.clear(); if (homeserver() != url) { @@ -1508,7 +1545,7 @@ void Connection::setHomeserver(const QUrl& url) // Whenever a homeserver is updated, retrieve available login flows from it d->loginFlowsJob = callApi<GetLoginFlowsJob>(BackgroundRequest); - connect(d->loginFlowsJob, &BaseJob::finished, this, [this] { + connect(d->loginFlowsJob, &BaseJob::result, this, [this] { if (d->loginFlowsJob->status().good()) d->loginFlows = d->loginFlowsJob->flows(); else diff --git a/lib/connection.h b/lib/connection.h index 6517b909..f3d7d725 100644 --- a/lib/connection.h +++ b/lib/connection.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2015 Felix Rohrbach <kde@fxrh.de> + * SPDX-FileCopyrightText: 2015 Felix Rohrbach <kde@fxrh.de> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once @@ -62,28 +50,27 @@ class SendToDeviceJob; class SendMessageJob; class LeaveRoomJob; +using LoginFlow = GetLoginFlowsJob::LoginFlow; + +/// Predefined login flows +struct LoginFlows { + static inline const LoginFlow Password { "m.login.password" }; + static inline const LoginFlow SSO { "m.login.sso" }; + static inline const LoginFlow Token { "m.login.token" }; +}; + // To simplify comparisons of LoginFlows -inline bool operator==(const GetLoginFlowsJob::LoginFlow& lhs, - const GetLoginFlowsJob::LoginFlow& rhs) +inline bool operator==(const LoginFlow& lhs, const LoginFlow& rhs) { return lhs.type == rhs.type; } -inline bool operator!=(const GetLoginFlowsJob::LoginFlow& lhs, - const GetLoginFlowsJob::LoginFlow& rhs) +inline bool operator!=(const LoginFlow& lhs, const LoginFlow& rhs) { return !(lhs == rhs); } -/// Predefined login flows -struct LoginFlows { - using LoginFlow = GetLoginFlowsJob::LoginFlow; - static inline const LoginFlow Password { "m.login.password" }; - static inline const LoginFlow SSO { "m.login.sso" }; - static inline const LoginFlow Token { "m.login.token" }; -}; - class Connection; using room_factory_t = @@ -497,20 +484,42 @@ public: setUserFactory(defaultUserFactory<T>()); } -public slots: +public Q_SLOTS: /** Set the homeserver base URL */ void setHomeserver(const QUrl& baseUrl); /** Determine and set the homeserver from MXID */ void resolveServer(const QString& mxid); + /** \brief Log in using a username and password pair + * + * Before logging in, this method checks if the homeserver is valid and + * supports the password login flow. If the homeserver is invalid but + * a full user MXID is provided, this method calls resolveServer() using + * this MXID. + * + * \sa resolveServer, resolveError, loginError + */ void loginWithPassword(const QString& userId, const QString& password, const QString& initialDeviceName, const QString& deviceId = {}); + /** \brief Log in using a login token + * + * One usual case for this method is the final stage of logging in via SSO. + * Unlike loginWithPassword() and assumeIdentity(), this method cannot + * resolve the server from the user name because the full user MXID is + * encoded in the login token. Callers should ensure the homeserver + * sanity in advance. + */ void loginWithToken(const QByteArray& loginToken, const QString& initialDeviceName, const QString& deviceId = {}); - void assumeIdentity(const QString& userId, const QString& accessToken, + /** \brief Use an existing access token to connect to the homeserver + * + * Similar to loginWithPassword(), this method checks that the homeserver + * URL is valid and tries to resolve it from the MXID in case it is not. + */ + void assumeIdentity(const QString& mxId, const QString& accessToken, const QString& deviceId); /*! \deprecated Use loginWithPassword instead */ void connectToServer(const QString& userId, const QString& password, @@ -656,15 +665,15 @@ public slots: */ virtual PostReceiptJob* postReceipt(Room* room, RoomEvent* event); -signals: +Q_SIGNALS: /** * @deprecated * This was a signal resulting from a successful resolveServer(). * Since Connection now provides setHomeserver(), the HS URL * may change even without resolveServer() invocation. Use - * homeserverChanged() instead of resolved(). You can also use - * connectToServer and connectWithToken without the HS URL set in - * advance (i.e. without calling resolveServer), as they now trigger + * loginFLowsChanged() instead of resolved(). You can also use + * loginWith*() and assumeIdentity() without the HS URL set in + * advance (i.e. without calling resolveServer), as they trigger * server name resolution from MXID if the server URL is not valid. */ void resolved(); @@ -853,26 +862,13 @@ protected: */ void onSyncSuccess(SyncData&& data, bool fromCache = false); -protected slots: +protected Q_SLOTS: void syncLoopIteration(); private: class Private; QScopedPointer<Private> d; - /** - * A single entry for functions that need to check whether the - * homeserver is valid before running. May either execute connectFn - * synchronously or asynchronously (if tryResolve is true and - * a DNS lookup is initiated); in case of errors, emits resolveError - * if the homeserver URL is not valid and cannot be resolved from - * userId. - * - * @param userId - fully-qualified MXID to resolve HS from - * @param connectFn - a function to execute once the HS URL is good - */ - void checkAndConnect(const QString& userId, std::function<void()> connectFn); - static room_factory_t _roomFactory; static user_factory_t _userFactory; }; diff --git a/lib/connectiondata.cpp b/lib/connectiondata.cpp index d57363d0..25ab775a 100644 --- a/lib/connectiondata.cpp +++ b/lib/connectiondata.cpp @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2015 Felix Rohrbach <kde@fxrh.de> + * SPDX-FileCopyrightText: 2015 Felix Rohrbach <kde@fxrh.de> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "connectiondata.h" diff --git a/lib/connectiondata.h b/lib/connectiondata.h index 000099d1..a3b2d39b 100644 --- a/lib/connectiondata.h +++ b/lib/connectiondata.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2015 Felix Rohrbach <kde@fxrh.de> + * SPDX-FileCopyrightText: 2015 Felix Rohrbach <kde@fxrh.de> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once diff --git a/lib/converters.cpp b/lib/converters.cpp index e5236bb9..0df880a0 100644 --- a/lib/converters.cpp +++ b/lib/converters.cpp @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2018 Kitsune Ral <kitsune-ral@users.sf.net> + * SPDX-FileCopyrightText: 2018 Kitsune Ral <kitsune-ral@users.sf.net> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "converters.h" @@ -32,9 +20,9 @@ QVariant JsonConverter<QVariant>::load(const QJsonValue& jv) return jv.toVariant(); } -QJsonObject JsonConverter<QVariantHash>::dump(const QVariantHash& map) +QJsonObject JsonConverter<QVariantHash>::dump(const QVariantHash& vh) { - return QJsonObject::fromVariantHash(map); + return QJsonObject::fromVariantHash(vh); } QVariantHash JsonConverter<QVariantHash>::load(const QJsonValue& jv) diff --git a/lib/converters.h b/lib/converters.h index 81d7b6d8..d4f19b60 100644 --- a/lib/converters.h +++ b/lib/converters.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2017 Kitsune Ral <kitsune-ral@users.sf.net> + * SPDX-FileCopyrightText: 2017 Kitsune Ral <kitsune-ral@users.sf.net> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once @@ -1,3 +1,8 @@ +// SPDX-FileCopyrightText: 2019 Alexey Andreyev <aa13q@ya.ru> +// SPDX-FileCopyrightText: 2019 Kitsune Ral <Kitsune-Ral@users.sf.net> +// +// SPDX-License-Identifier: LGPL-2.1-or-later + #pragma once #include "util.h" diff --git a/lib/encryptionmanager.cpp b/lib/encryptionmanager.cpp index 4a1025b2..8d241eb2 100644 --- a/lib/encryptionmanager.cpp +++ b/lib/encryptionmanager.cpp @@ -1,3 +1,8 @@ +// SPDX-FileCopyrightText: 2019 Alexey Andreyev <aa13q@ya.ru> +// SPDX-FileCopyrightText: 2019 Kitsune Ral <Kitsune-Ral@users.sf.net> +// +// SPDX-License-Identifier: LGPL-2.1-or-later + #ifdef Quotient_E2EE_ENABLED #include "encryptionmanager.h" @@ -245,7 +250,7 @@ void EncryptionManager::uploadOneTimeKeys(Connection* connection, if (forceUpdate || d->oneTimeKeyCounts.isEmpty()) { d->uploadOneTimeKeysInitJob = connection->callApi<UploadKeysJob>(); connect(d->uploadOneTimeKeysInitJob, &BaseJob::success, this, [this] { - d->setOneTimeKeyCounts(d->uploadIdentityKeysJob->oneTimeKeyCounts()); + d->setOneTimeKeyCounts(d->uploadOneTimeKeysInitJob->oneTimeKeyCounts()); }); } diff --git a/lib/encryptionmanager.h b/lib/encryptionmanager.h index 5df15e83..0f507337 100644 --- a/lib/encryptionmanager.h +++ b/lib/encryptionmanager.h @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2019 Alexey Andreyev <aa13q@ya.ru> +// +// SPDX-License-Identifier: LGPL-2.1-or-later + #ifdef Quotient_E2EE_ENABLED #pragma once diff --git a/lib/eventitem.cpp b/lib/eventitem.cpp index 2e2b11c0..9c47e50d 100644 --- a/lib/eventitem.cpp +++ b/lib/eventitem.cpp @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2018 Kitsune Ral <kitsune-ral@users.sf.net> + * SPDX-FileCopyrightText: 2018 Kitsune Ral <kitsune-ral@users.sf.net> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "eventitem.h" diff --git a/lib/eventitem.h b/lib/eventitem.h index 7b2c3c44..2d3d9ef6 100644 --- a/lib/eventitem.h +++ b/lib/eventitem.h @@ -1,25 +1,14 @@ /****************************************************************************** - * Copyright (C) 2018 Kitsune Ral <kitsune-ral@users.sf.net> + * SPDX-FileCopyrightText: 2018 Kitsune Ral <kitsune-ral@users.sf.net> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "events/stateevent.h" +#include <any> #include <utility> namespace Quotient { @@ -72,6 +61,12 @@ public: return std::exchange(evt, move(other)); } + /// Store arbitrary data with the event item + void setUserData(std::any userData) { data = userData; } + /// Obtain custom data previously stored with the event item + const std::any& userdata() const { return data; } + std::any& userData() { return data; } + protected: template <typename EventT> EventT* getAs() @@ -81,6 +76,7 @@ protected: private: RoomEventPtr evt; + std::any data; }; class TimelineItem : public EventItemBase { diff --git a/lib/events/accountdataevents.h b/lib/events/accountdataevents.h index 0f240aa1..d0abf577 100644 --- a/lib/events/accountdataevents.h +++ b/lib/events/accountdataevents.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2018 Kitsune Ral <kitsune-ral@users.sf.net> + * SPDX-FileCopyrightText: 2018 Kitsune Ral <kitsune-ral@users.sf.net> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once diff --git a/lib/events/callanswerevent.cpp b/lib/events/callanswerevent.cpp index bf096534..f3d0a9a0 100644 --- a/lib/events/callanswerevent.cpp +++ b/lib/events/callanswerevent.cpp @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2017 Marius Gripsgard <marius@ubports.com> + * SPDX-FileCopyrightText: 2017 Marius Gripsgard <marius@ubports.com> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "callanswerevent.h" diff --git a/lib/events/callanswerevent.h b/lib/events/callanswerevent.h index 2709882b..d7214468 100644 --- a/lib/events/callanswerevent.h +++ b/lib/events/callanswerevent.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2017 Marius Gripsgard <marius@ubports.com> + * SPDX-FileCopyrightText: 2017 Marius Gripsgard <marius@ubports.com> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once diff --git a/lib/events/callcandidatesevent.cpp b/lib/events/callcandidatesevent.cpp index 24f0dd46..9b765064 100644 --- a/lib/events/callcandidatesevent.cpp +++ b/lib/events/callcandidatesevent.cpp @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2017 Marius Gripsgard <marius@ubports.com> + * SPDX-FileCopyrightText: 2017 Marius Gripsgard <marius@ubports.com> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "callcandidatesevent.h" diff --git a/lib/events/callcandidatesevent.h b/lib/events/callcandidatesevent.h index e224f048..ae3bb150 100644 --- a/lib/events/callcandidatesevent.h +++ b/lib/events/callcandidatesevent.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2017 Marius Gripsgard <marius@ubports.com> + * SPDX-FileCopyrightText: 2017 Marius Gripsgard <marius@ubports.com> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once diff --git a/lib/events/callhangupevent.cpp b/lib/events/callhangupevent.cpp index f2117f38..45b84cd4 100644 --- a/lib/events/callhangupevent.cpp +++ b/lib/events/callhangupevent.cpp @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2017 Marius Gripsgard <marius@ubports.com> + * SPDX-FileCopyrightText: 2017 Marius Gripsgard <marius@ubports.com> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "callhangupevent.h" diff --git a/lib/events/callhangupevent.h b/lib/events/callhangupevent.h index 5d73fb62..432f72f5 100644 --- a/lib/events/callhangupevent.h +++ b/lib/events/callhangupevent.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2017 Marius Gripsgard <marius@ubports.com> + * SPDX-FileCopyrightText: 2017 Marius Gripsgard <marius@ubports.com> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once diff --git a/lib/events/callinviteevent.cpp b/lib/events/callinviteevent.cpp index 63f331de..86478ada 100644 --- a/lib/events/callinviteevent.cpp +++ b/lib/events/callinviteevent.cpp @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2017 Marius Gripsgard <marius@ubports.com> + * SPDX-FileCopyrightText: 2017 Marius Gripsgard <marius@ubports.com> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "callinviteevent.h" diff --git a/lib/events/callinviteevent.h b/lib/events/callinviteevent.h index b067a492..304c89ac 100644 --- a/lib/events/callinviteevent.h +++ b/lib/events/callinviteevent.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2017 Marius Gripsgard <marius@ubports.com> + * SPDX-FileCopyrightText: 2017 Marius Gripsgard <marius@ubports.com> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once diff --git a/lib/events/directchatevent.cpp b/lib/events/directchatevent.cpp index b4027e16..39d11072 100644 --- a/lib/events/directchatevent.cpp +++ b/lib/events/directchatevent.cpp @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2018 Kitsune Ral <kitsune-ral@users.sf.net> + * SPDX-FileCopyrightText: 2018 Kitsune Ral <kitsune-ral@users.sf.net> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "directchatevent.h" diff --git a/lib/events/directchatevent.h b/lib/events/directchatevent.h index bb091c5c..373e36dc 100644 --- a/lib/events/directchatevent.h +++ b/lib/events/directchatevent.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2018 Kitsune Ral <kitsune-ral@users.sf.net> + * SPDX-FileCopyrightText: 2018 Kitsune Ral <kitsune-ral@users.sf.net> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once diff --git a/lib/events/encryptedevent.cpp b/lib/events/encryptedevent.cpp index 117aae37..dc9eaf2d 100644 --- a/lib/events/encryptedevent.cpp +++ b/lib/events/encryptedevent.cpp @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2019 Alexey Andreyev <aa13q@ya.ru> +// +// SPDX-License-Identifier: LGPL-2.1-or-later + #include "encryptedevent.h" using namespace Quotient; diff --git a/lib/events/encryptedevent.h b/lib/events/encryptedevent.h index 235b2aa4..9de08b00 100644 --- a/lib/events/encryptedevent.h +++ b/lib/events/encryptedevent.h @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2019 Alexey Andreyev <aa13q@ya.ru> +// +// SPDX-License-Identifier: LGPL-2.1-or-later + #pragma once #include "e2ee.h" diff --git a/lib/events/encryptionevent.h b/lib/events/encryptionevent.h index cbb6d786..3431ddd8 100644 --- a/lib/events/encryptionevent.h +++ b/lib/events/encryptionevent.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2017 Kitsune Ral <kitsune-ral@users.sf.net> + * SPDX-FileCopyrightText: 2017 Kitsune Ral <kitsune-ral@users.sf.net> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once diff --git a/lib/events/event.cpp b/lib/events/event.cpp index 96e33864..97edb4e0 100644 --- a/lib/events/event.cpp +++ b/lib/events/event.cpp @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2015 Felix Rohrbach <kde@fxrh.de> + * SPDX-FileCopyrightText: 2015 Felix Rohrbach <kde@fxrh.de> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "event.h" @@ -61,11 +49,14 @@ QString Event::matrixType() const { return fullJson()[TypeKeyL].toString(); } QByteArray Event::originalJson() const { return QJsonDocument(_json).toJson(); } +// On const below: this is to catch accidental attempts to change event JSON +// NOLINTNEXTLINE(readability-const-return-type) const QJsonObject Event::contentJson() const { return fullJson()[ContentKeyL].toObject(); } +// NOLINTNEXTLINE(readability-const-return-type) const QJsonObject Event::unsignedJson() const { return fullJson()[UnsignedKeyL].toObject(); diff --git a/lib/events/event.h b/lib/events/event.h index 626a0229..c5752a7a 100644 --- a/lib/events/event.h +++ b/lib/events/event.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2015 Felix Rohrbach <kde@fxrh.de> + * SPDX-FileCopyrightText: 2015 Felix Rohrbach <kde@fxrh.de> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once @@ -298,7 +286,7 @@ using Events = EventsArray<Event>; // === is<>(), eventCast<>() and visit<>() === -template <typename EventT> +template <class EventT> inline bool is(const Event& e) { return e.type() == typeId<EventT>(); @@ -309,7 +297,7 @@ inline bool isUnknown(const Event& e) return e.type() == unknownEventTypeId(); } -template <typename EventT, typename BasePtrT> +template <class EventT, typename BasePtrT> inline auto eventCast(const BasePtrT& eptr) -> decltype(static_cast<EventT*>(&*eptr)) { @@ -319,7 +307,7 @@ inline auto eventCast(const BasePtrT& eptr) } // A single generic catch-all visitor -template <typename BaseEventT, typename FnT> +template <class BaseEventT, typename FnT> inline auto visit(const BaseEventT& event, FnT&& visitor) -> decltype(visitor(event)) { @@ -327,18 +315,18 @@ inline auto visit(const BaseEventT& event, FnT&& visitor) } namespace _impl { - template <typename T, typename FnT> - constexpr auto needs_downcast() - { - return !std::is_convertible_v<T, fn_arg_t<FnT>>; - } + // Using bool instead of auto below because auto apparently upsets MSVC + template <class BaseT, typename FnT> + inline constexpr bool needs_downcast = + std::is_base_of_v<BaseT, std::decay_t<fn_arg_t<FnT>>> + && !std::is_same_v<BaseT, std::decay_t<fn_arg_t<FnT>>>; } // A single type-specific void visitor -template <typename BaseEventT, typename FnT> -inline std::enable_if_t<_impl::needs_downcast<BaseEventT, FnT>() +template <class BaseT, typename FnT> +inline auto visit(const BaseT& event, FnT&& visitor) + -> std::enable_if_t<_impl::needs_downcast<BaseT, FnT> && std::is_void_v<fn_return_t<FnT>>> -visit(const BaseEventT& event, FnT&& visitor) { using event_type = fn_arg_t<FnT>; if (is<std::decay_t<event_type>>(event)) @@ -347,10 +335,10 @@ visit(const BaseEventT& event, FnT&& visitor) // A single type-specific non-void visitor with an optional default value // non-voidness is guarded by defaultValue type -template <typename BaseEventT, typename FnT> -inline std::enable_if_t<_impl::needs_downcast<BaseEventT, FnT>(), fn_return_t<FnT>> -visit(const BaseEventT& event, FnT&& visitor, - fn_return_t<FnT>&& defaultValue = {}) +template <class BaseT, typename FnT> +inline auto visit(const BaseT& event, FnT&& visitor, + fn_return_t<FnT>&& defaultValue = {}) + -> std::enable_if_t<_impl::needs_downcast<BaseT, FnT>, fn_return_t<FnT>> { using event_type = fn_arg_t<FnT>; if (is<std::decay_t<event_type>>(event)) @@ -359,9 +347,10 @@ visit(const BaseEventT& event, FnT&& visitor, } // A chain of 2 or more visitors -template <typename BaseEventT, typename FnT1, typename FnT2, typename... FnTs> -inline fn_return_t<FnT1> visit(const BaseEventT& event, FnT1&& visitor1, - FnT2&& visitor2, FnTs&&... visitors) +template <class BaseT, typename FnT1, typename FnT2, typename... FnTs> +inline std::common_type_t<fn_return_t<FnT1>, fn_return_t<FnT2>> visit( + const BaseT& event, FnT1&& visitor1, FnT2&& visitor2, + FnTs&&... visitors) { using event_type1 = fn_arg_t<FnT1>; if (is<std::decay_t<event_type1>>(event)) @@ -374,8 +363,8 @@ inline fn_return_t<FnT1> visit(const BaseEventT& event, FnT1&& visitor1, // over a range of event pointers template <typename RangeT, typename... FnTs> inline auto visitEach(RangeT&& events, FnTs&&... visitors) - -> std::enable_if_t<std::is_convertible_v< - std::decay_t<decltype(**events.begin())>, Event>> + -> std::enable_if_t<std::is_void_v< + decltype(visit(**begin(events), std::forward<FnTs>(visitors)...))>> { for (auto&& evtPtr: events) visit(*evtPtr, std::forward<FnTs>(visitors)...); diff --git a/lib/events/eventcontent.cpp b/lib/events/eventcontent.cpp index 0cb9e292..18b1b94b 100644 --- a/lib/events/eventcontent.cpp +++ b/lib/events/eventcontent.cpp @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2017 Kitsune Ral <kitsune-ral@users.sf.net> + * SPDX-FileCopyrightText: 2017 Kitsune Ral <kitsune-ral@users.sf.net> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "eventcontent.h" diff --git a/lib/events/eventcontent.h b/lib/events/eventcontent.h index 9c167d4b..e247adbf 100644 --- a/lib/events/eventcontent.h +++ b/lib/events/eventcontent.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2017 Kitsune Ral <kitsune-ral@users.sf.net> + * SPDX-FileCopyrightText: 2017 Kitsune Ral <kitsune-ral@users.sf.net> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once diff --git a/lib/events/eventloader.h b/lib/events/eventloader.h index ebb96441..0d95daf5 100644 --- a/lib/events/eventloader.h +++ b/lib/events/eventloader.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2018 Kitsune Ral <kitsune-ral@users.sf.net> + * SPDX-FileCopyrightText: 2018 Kitsune Ral <kitsune-ral@users.sf.net> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once diff --git a/lib/events/reactionevent.cpp b/lib/events/reactionevent.cpp index 003c8ead..9b43e372 100644 --- a/lib/events/reactionevent.cpp +++ b/lib/events/reactionevent.cpp @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2019 Kitsune Ral <kitsune-ral@users.sf.net> + * SPDX-FileCopyrightText: 2019 Kitsune Ral <kitsune-ral@users.sf.net> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "reactionevent.h" diff --git a/lib/events/reactionevent.h b/lib/events/reactionevent.h index 48b0bc6c..09166b24 100644 --- a/lib/events/reactionevent.h +++ b/lib/events/reactionevent.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2019 Kitsune Ral <kitsune-ral@users.sf.net> + * SPDX-FileCopyrightText: 2019 Kitsune Ral <kitsune-ral@users.sf.net> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once diff --git a/lib/events/receiptevent.cpp b/lib/events/receiptevent.cpp index deb3c4e8..b6f0fcdd 100644 --- a/lib/events/receiptevent.cpp +++ b/lib/events/receiptevent.cpp @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2016 Felix Rohrbach <kde@fxrh.de> + * SPDX-FileCopyrightText: 2016 Felix Rohrbach <kde@fxrh.de> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ /* diff --git a/lib/events/receiptevent.h b/lib/events/receiptevent.h index b7adea44..ec297a6c 100644 --- a/lib/events/receiptevent.h +++ b/lib/events/receiptevent.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2016 Felix Rohrbach <kde@fxrh.de> + * SPDX-FileCopyrightText: 2016 Felix Rohrbach <kde@fxrh.de> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once diff --git a/lib/events/redactionevent.cpp b/lib/events/redactionevent.cpp index bf467718..5889773c 100644 --- a/lib/events/redactionevent.cpp +++ b/lib/events/redactionevent.cpp @@ -1 +1,5 @@ +// SPDX-FileCopyrightText: 2019 Kitsune Ral <Kitsune-Ral@users.sf.net> +// +// SPDX-License-Identifier: CC0-1.0 + #include "redactionevent.h" diff --git a/lib/events/redactionevent.h b/lib/events/redactionevent.h index 3b3af18e..320db6f2 100644 --- a/lib/events/redactionevent.h +++ b/lib/events/redactionevent.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2017 Kitsune Ral <kitsune-ral@users.sf.net> + * SPDX-FileCopyrightText: 2017 Kitsune Ral <kitsune-ral@users.sf.net> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once diff --git a/lib/events/roomavatarevent.h b/lib/events/roomavatarevent.h index c2100eaa..649412e8 100644 --- a/lib/events/roomavatarevent.h +++ b/lib/events/roomavatarevent.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2017 Kitsune Ral <kitsune-ral@users.sf.net> + * SPDX-FileCopyrightText: 2017 Kitsune Ral <kitsune-ral@users.sf.net> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once diff --git a/lib/events/roomcanonicalaliasevent.h b/lib/events/roomcanonicalaliasevent.h index 4a21b7cc..eda94d2d 100644 --- a/lib/events/roomcanonicalaliasevent.h +++ b/lib/events/roomcanonicalaliasevent.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2020 QMatrixClient project + * SPDX-FileCopyrightText: 2020 QMatrixClient project * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once diff --git a/lib/events/roomcreateevent.cpp b/lib/events/roomcreateevent.cpp index 0fc7d6b9..3d9ec4a3 100644 --- a/lib/events/roomcreateevent.cpp +++ b/lib/events/roomcreateevent.cpp @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2019 QMatrixClient project + * SPDX-FileCopyrightText: 2019 QMatrixClient project * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "roomcreateevent.h" diff --git a/lib/events/roomcreateevent.h b/lib/events/roomcreateevent.h index 91aefe9e..8328d38a 100644 --- a/lib/events/roomcreateevent.h +++ b/lib/events/roomcreateevent.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2019 QMatrixClient project + * SPDX-FileCopyrightText: 2019 QMatrixClient project * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once diff --git a/lib/events/roomevent.cpp b/lib/events/roomevent.cpp index a2dbc07d..2b6ac2be 100644 --- a/lib/events/roomevent.cpp +++ b/lib/events/roomevent.cpp @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2018 Kitsune Ral <kitsune-ral@users.sf.net> + * SPDX-FileCopyrightText: 2018 Kitsune Ral <kitsune-ral@users.sf.net> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "roomevent.h" diff --git a/lib/events/roomevent.h b/lib/events/roomevent.h index 084cb524..3fafecfd 100644 --- a/lib/events/roomevent.h +++ b/lib/events/roomevent.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2018 Kitsune Ral <kitsune-ral@users.sf.net> + * SPDX-FileCopyrightText: 2018 Kitsune Ral <kitsune-ral@users.sf.net> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once diff --git a/lib/events/roommemberevent.cpp b/lib/events/roommemberevent.cpp index 913bde74..d093286c 100644 --- a/lib/events/roommemberevent.cpp +++ b/lib/events/roommemberevent.cpp @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2015 Felix Rohrbach <kde@fxrh.de> + * SPDX-FileCopyrightText: 2015 Felix Rohrbach <kde@fxrh.de> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "roommemberevent.h" diff --git a/lib/events/roommemberevent.h b/lib/events/roommemberevent.h index cebaaf10..b7a7c9df 100644 --- a/lib/events/roommemberevent.h +++ b/lib/events/roommemberevent.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2015 Felix Rohrbach <kde@fxrh.de> + * SPDX-FileCopyrightText: 2015 Felix Rohrbach <kde@fxrh.de> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once diff --git a/lib/events/roommessageevent.cpp b/lib/events/roommessageevent.cpp index 616a034f..19d460b8 100644 --- a/lib/events/roommessageevent.cpp +++ b/lib/events/roommessageevent.cpp @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2015 Felix Rohrbach <kde@fxrh.de> + * SPDX-FileCopyrightText: 2015 Felix Rohrbach <kde@fxrh.de> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "roommessageevent.h" diff --git a/lib/events/roommessageevent.h b/lib/events/roommessageevent.h index 2501d097..ebc9d564 100644 --- a/lib/events/roommessageevent.h +++ b/lib/events/roommessageevent.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2015 Felix Rohrbach <kde@fxrh.de> + * SPDX-FileCopyrightText: 2015 Felix Rohrbach <kde@fxrh.de> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once diff --git a/lib/events/roomtombstoneevent.cpp b/lib/events/roomtombstoneevent.cpp index f93eb60d..163e1d3a 100644 --- a/lib/events/roomtombstoneevent.cpp +++ b/lib/events/roomtombstoneevent.cpp @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2019 QMatrixClient project + * SPDX-FileCopyrightText: 2019 QMatrixClient project * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "roomtombstoneevent.h" diff --git a/lib/events/roomtombstoneevent.h b/lib/events/roomtombstoneevent.h index 2c2f0663..8d50aba0 100644 --- a/lib/events/roomtombstoneevent.h +++ b/lib/events/roomtombstoneevent.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2019 QMatrixClient project + * SPDX-FileCopyrightText: 2019 QMatrixClient project * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once diff --git a/lib/events/simplestateevents.h b/lib/events/simplestateevents.h index cde5b0fd..58ba3b5a 100644 --- a/lib/events/simplestateevents.h +++ b/lib/events/simplestateevents.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2017 Kitsune Ral <kitsune-ral@users.sf.net> + * SPDX-FileCopyrightText: 2017 Kitsune Ral <kitsune-ral@users.sf.net> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once diff --git a/lib/events/stateevent.cpp b/lib/events/stateevent.cpp index 5909e8a6..7bde12bb 100644 --- a/lib/events/stateevent.cpp +++ b/lib/events/stateevent.cpp @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2018 Kitsune Ral <kitsune-ral@users.sf.net> + * SPDX-FileCopyrightText: 2018 Kitsune Ral <kitsune-ral@users.sf.net> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "stateevent.h" diff --git a/lib/events/stateevent.h b/lib/events/stateevent.h index 20a85f83..0db37767 100644 --- a/lib/events/stateevent.h +++ b/lib/events/stateevent.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2018 Kitsune Ral <kitsune-ral@users.sf.net> + * SPDX-FileCopyrightText: 2018 Kitsune Ral <kitsune-ral@users.sf.net> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once diff --git a/lib/events/stickerevent.cpp b/lib/events/stickerevent.cpp new file mode 100644 index 00000000..ea4dff3f --- /dev/null +++ b/lib/events/stickerevent.cpp @@ -0,0 +1,26 @@ +// SDPX-FileCopyrightText: 2020 Carl Schwan <carlschwan@kde.org> +// SPDX-License-Identifier: LGPL-2.1-or-later + +#include "stickerevent.h" + +using namespace Quotient; + +StickerEvent::StickerEvent(const QJsonObject &obj) + : RoomEvent(typeId(), obj) + , m_imageContent(EventContent::ImageContent(obj["content"_ls].toObject())) +{} + +QString StickerEvent::body() const +{ + return content<QString>("body"_ls); +} + +const EventContent::ImageContent &StickerEvent::image() const +{ + return m_imageContent; +} + +QUrl StickerEvent::url() const +{ + return m_imageContent.url; +} diff --git a/lib/events/stickerevent.h b/lib/events/stickerevent.h new file mode 100644 index 00000000..93671086 --- /dev/null +++ b/lib/events/stickerevent.h @@ -0,0 +1,38 @@ +// SDPX-FileCopyrightText: 2020 Carl Schwan <carlschwan@kde.org> +// SPDX-License-Identifier: LGPL-2.1-or-later + +#pragma once + +#include "roomevent.h" +#include "eventcontent.h" + +namespace Quotient { + +/// Sticker messages are specialised image messages that are displayed without +/// controls (e.g. no "download" link, or light-box view on click, as would be +/// displayed for for m.image events). +class StickerEvent : public RoomEvent +{ +public: + DEFINE_EVENT_TYPEID("m.sticker", StickerEvent) + + explicit StickerEvent(const QJsonObject &obj); + + /// \brief A textual representation or associated description of the + /// sticker image. + /// + /// This could be the alt text of the original image, or a message to + /// accompany and further describe the sticker. + QString body() const; + + /// \brief Metadata about the image referred to in url including a + /// thumbnail representation. + const EventContent::ImageContent &image() const; + + /// \brief The URL to the sticker image. This must be a valid mxc:// URI. + QUrl url() const; +private: + EventContent::ImageContent m_imageContent; +}; +REGISTER_EVENT_TYPE(StickerEvent) +} // namespace Quotient diff --git a/lib/events/typingevent.cpp b/lib/events/typingevent.cpp index e102fc79..7d3f71e5 100644 --- a/lib/events/typingevent.cpp +++ b/lib/events/typingevent.cpp @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2015 Felix Rohrbach <kde@fxrh.de> + * SPDX-FileCopyrightText: 2015 Felix Rohrbach <kde@fxrh.de> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "typingevent.h" diff --git a/lib/events/typingevent.h b/lib/events/typingevent.h index 97e1f9cc..8ca4f8e4 100644 --- a/lib/events/typingevent.h +++ b/lib/events/typingevent.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2015 Felix Rohrbach <kde@fxrh.de> + * SPDX-FileCopyrightText: 2015 Felix Rohrbach <kde@fxrh.de> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once diff --git a/lib/jobs/basejob.cpp b/lib/jobs/basejob.cpp index 422931ee..a0c88581 100644 --- a/lib/jobs/basejob.cpp +++ b/lib/jobs/basejob.cpp @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2015 Felix Rohrbach <kde@fxrh.de> + * SPDX-FileCopyrightText: 2015 Felix Rohrbach <kde@fxrh.de> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "basejob.h" @@ -24,6 +12,7 @@ #include <QtCore/QTimer> #include <QtCore/QStringBuilder> #include <QtCore/QMetaEnum> +#include <QtCore/QPointer> #include <QtNetwork/QNetworkAccessManager> #include <QtNetwork/QNetworkReply> #include <QtNetwork/QNetworkRequest> @@ -76,15 +65,6 @@ QDebug BaseJob::Status::dumpToLog(QDebug dbg) const return dbg << ": " << message; } -struct NetworkReplyDeleter : public QScopedPointerDeleteLater { - static inline void cleanup(QNetworkReply* reply) - { - if (reply && reply->isRunning()) - reply->abort(); - QScopedPointerDeleteLater::cleanup(reply); - } -}; - template <typename... Ts> constexpr auto make_array(Ts&&... items) { @@ -112,6 +92,16 @@ public: retryTimer.setSingleShot(true); } + ~Private() + { + if (reply) { + if (reply->isRunning()) { + reply->abort(); + } + delete reply; + } + } + void sendRequest(); /*! \brief Parse the response byte array into JSON * @@ -140,7 +130,10 @@ public: QByteArrayList expectedKeys; - QScopedPointer<QNetworkReply, NetworkReplyDeleter> reply; + // When the QNetworkAccessManager is destroyed it destroys all pending replies. + // Using QPointer allows us to know when that happend. + QPointer<QNetworkReply> reply; + Status status = Unprepared; QByteArray rawResponse; /// Contains a null document in case of non-JSON body (for a successful @@ -194,6 +187,7 @@ BaseJob::BaseJob(HttpVerb verb, const QString& name, const QString& endpoint, setObjectName(name); connect(&d->timer, &QTimer::timeout, this, &BaseJob::timeout); connect(&d->retryTimer, &QTimer::timeout, this, [this] { + qCDebug(d->logCat) << "Retrying" << this; d->connection->submit(this); }); } @@ -258,7 +252,7 @@ void BaseJob::setExpectedContentTypes(const QByteArrayList& contentTypes) d->expectedContentTypes = contentTypes; } -const QByteArrayList BaseJob::expectedKeys() const { return d->expectedKeys; } +QByteArrayList BaseJob::expectedKeys() const { return d->expectedKeys; } void BaseJob::addExpectedKey(const QByteArray& key) { d->expectedKeys << key; } @@ -315,16 +309,16 @@ void BaseJob::Private::sendRequest() switch (verb) { case HttpVerb::Get: - reply.reset(connection->nam()->get(req)); + reply = connection->nam()->get(req); break; case HttpVerb::Post: - reply.reset(connection->nam()->post(req, requestData.source())); + reply = connection->nam()->post(req, requestData.source()); break; case HttpVerb::Put: - reply.reset(connection->nam()->put(req, requestData.source())); + reply = connection->nam()->put(req, requestData.source()); break; case HttpVerb::Delete: - reply.reset(connection->nam()->deleteResource(req)); + reply = connection->nam()->sendCustomRequest(req, "DELETE", requestData.source()); break; } } @@ -337,7 +331,7 @@ void BaseJob::beforeAbandon() { } void BaseJob::initiate(ConnectionData* connData, bool inBackground) { - if (connData && connData->baseUrl().isValid()) { + if (Q_LIKELY(connData && connData->baseUrl().isValid())) { d->inBackground = inBackground; d->connection = connData; doPrepare(); @@ -350,7 +344,7 @@ void BaseJob::initiate(ConnectionData* connData, bool inBackground) setStatus(FileError, "Request data not ready"); } Q_ASSERT(status().code != Pending); // doPrepare() must NOT set this - if (status().code == Unprepared) { + if (Q_LIKELY(status().code == Unprepared)) { d->connection->submit(this); return; } @@ -369,8 +363,11 @@ void BaseJob::initiate(ConnectionData* connData, bool inBackground) void BaseJob::sendRequest() { - if (status().code == Abandoned) + if (status().code == Abandoned) { + qCDebug(d->logCat) << "Won't proceed with the abandoned request:" + << d->dumpRequest(); return; + } Q_ASSERT(d->connection && status().code == Pending); qCDebug(d->logCat).noquote() << "Making" << d->dumpRequest(); d->needsToken |= d->connection->needsToken(objectName()); @@ -510,14 +507,15 @@ BaseJob::Status BaseJob::prepareResult() { return Success; } BaseJob::Status BaseJob::prepareError() { - if (!d->rawResponse.isEmpty()) { - if (const auto status = d->parseJson(); !status.good()) - return status; // If there's anything there, it should be JSON - if (d->jsonResponse.isArray()) // ...specifically, a JSON object - return { IncorrectResponse, - tr("Malformed error JSON: an array instead of an object") }; - } + // Try to make sense of the error payload but be prepared for all kinds + // of unexpected stuff (raw HTML, plain text, foreign JSON among those) + if (!d->rawResponse.isEmpty() + && reply()->rawHeader("Content-Type") == "application/json") + d->parseJson(); + // By now, if d->parseJson() above succeeded then jsonData() will return + // a valid JSON object - or an empty object otherwise (in which case most + // of if's below will fall through to `return NoError` at the end const auto& errorJson = jsonData(); const auto errCode = errorJson.value("errcode"_ls).toString(); if (error() == TooManyRequestsError || errCode == "M_LIMIT_EXCEEDED") { @@ -615,10 +613,12 @@ void BaseJob::finishJob() qCWarning(d->logCat).nospace() << this << ": retry #" << d->retriesTaken << " in " << retryIn.count() << " s"; + setStatus(Pending, "Pending retry"); d->retryTimer.start(retryIn); emit retryScheduled(d->retriesTaken, milliseconds(retryIn).count()); return; } + [[fallthrough]]; default:; } diff --git a/lib/jobs/basejob.h b/lib/jobs/basejob.h index be2926be..3165edd3 100644 --- a/lib/jobs/basejob.h +++ b/lib/jobs/basejob.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2015 Felix Rohrbach <kde@fxrh.de> + * SPDX-FileCopyrightText: 2015 Felix Rohrbach <kde@fxrh.de> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once @@ -136,6 +124,14 @@ public: { return !operator==(other); } + bool operator==(int otherCode) const + { + return code == otherCode; + } + bool operator!=(int otherCode) const + { + return !operator==(otherCode); + } int code; QString message; @@ -251,7 +247,7 @@ public: return dbg << j->objectName(); } -public slots: +public Q_SLOTS: void initiate(ConnectionData* connData, bool inBackground); /** @@ -263,7 +259,7 @@ public slots: */ void abandon(); -signals: +Q_SIGNALS: /** The job is about to send a network request */ void aboutToSendRequest(); @@ -355,7 +351,7 @@ protected: const QByteArrayList& expectedContentTypes() const; void addExpectedContentType(const QByteArray& contentType); void setExpectedContentTypes(const QByteArrayList& contentTypes); - const QByteArrayList expectedKeys() const; + QByteArrayList expectedKeys() const; void addExpectedKey(const QByteArray &key); void setExpectedKeys(const QByteArrayList &keys); @@ -433,7 +429,7 @@ protected: // Job objects should only be deleted via QObject::deleteLater ~BaseJob() override; -protected slots: +protected Q_SLOTS: void timeout(); /*! \brief Check the pending or received reply for upfront issues @@ -456,7 +452,7 @@ protected slots: */ virtual Status checkReply(const QNetworkReply *reply) const; -private slots: +private Q_SLOTS: void sendRequest(); void gotReply(); @@ -470,7 +466,7 @@ private: QScopedPointer<Private> d; }; -inline bool isJobRunning(BaseJob* job) +inline bool isJobPending(BaseJob* job) { return job && job->error() == BaseJob::Pending; } diff --git a/lib/jobs/downloadfilejob.cpp b/lib/jobs/downloadfilejob.cpp index 7b4cf690..0011a97c 100644 --- a/lib/jobs/downloadfilejob.cpp +++ b/lib/jobs/downloadfilejob.cpp @@ -64,7 +64,7 @@ void DownloadFileJob::onSentRequest(QNetworkReply* reply) return; auto sizeHeader = reply->header(QNetworkRequest::ContentLengthHeader); if (sizeHeader.isValid()) { - auto targetSize = sizeHeader.value<qint64>(); + auto targetSize = sizeHeader.toLongLong(); if (targetSize != -1) if (!d->tempFile->resize(targetSize)) { qCWarning(JOBS) << "Failed to allocate" << targetSize diff --git a/lib/jobs/mediathumbnailjob.cpp b/lib/jobs/mediathumbnailjob.cpp index a69f00e9..fbea8797 100644 --- a/lib/jobs/mediathumbnailjob.cpp +++ b/lib/jobs/mediathumbnailjob.cpp @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2016 Felix Rohrbach <kde@fxrh.de> + * SPDX-FileCopyrightText: 2016 Felix Rohrbach <kde@fxrh.de> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "mediathumbnailjob.h" diff --git a/lib/jobs/mediathumbnailjob.h b/lib/jobs/mediathumbnailjob.h index e6d39085..cb55a0b0 100644 --- a/lib/jobs/mediathumbnailjob.h +++ b/lib/jobs/mediathumbnailjob.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2016 Felix Rohrbach <kde@fxrh.de> + * SPDX-FileCopyrightText: 2016 Felix Rohrbach <kde@fxrh.de> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once diff --git a/lib/jobs/postreadmarkersjob.h b/lib/jobs/postreadmarkersjob.h deleted file mode 100644 index 5a4d942c..00000000 --- a/lib/jobs/postreadmarkersjob.h +++ /dev/null @@ -1,38 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2017 Kitsune Ral <kitsune-ral@users.sf.net> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#pragma once - -#include "basejob.h" - -#include <QtCore/QJsonObject> - -using namespace Quotient; - -class PostReadMarkersJob : public BaseJob { -public: - explicit PostReadMarkersJob(const QString& roomId, - const QString& readUpToEventId) - : BaseJob( - HttpVerb::Post, "PostReadMarkersJob", - QStringLiteral("_matrix/client/r0/rooms/%1/read_markers").arg(roomId)) - { - setRequestData( - QJsonObject { { QStringLiteral("m.fully_read"), readUpToEventId } }); - } -}; diff --git a/lib/jobs/requestdata.h b/lib/jobs/requestdata.h index 9cb5ecaf..2a227646 100644 --- a/lib/jobs/requestdata.h +++ b/lib/jobs/requestdata.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2018 Kitsune Ral <kitsune-ral@users.sf.net> + * SPDX-FileCopyrightText: 2018 Kitsune Ral <kitsune-ral@users.sf.net> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once diff --git a/lib/jobs/syncjob.cpp b/lib/jobs/syncjob.cpp index 9087fe50..beb0a535 100644 --- a/lib/jobs/syncjob.cpp +++ b/lib/jobs/syncjob.cpp @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2016 Felix Rohrbach <kde@fxrh.de> + * SPDX-FileCopyrightText: 2016 Felix Rohrbach <kde@fxrh.de> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "syncjob.h" diff --git a/lib/jobs/syncjob.h b/lib/jobs/syncjob.h index bf139a7b..a7d10ed8 100644 --- a/lib/jobs/syncjob.h +++ b/lib/jobs/syncjob.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2016 Felix Rohrbach <kde@fxrh.de> + * SPDX-FileCopyrightText: 2016 Felix Rohrbach <kde@fxrh.de> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once diff --git a/lib/joinstate.h b/lib/joinstate.h index 31c2b6a7..1a7b1add 100644 --- a/lib/joinstate.h +++ b/lib/joinstate.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2015 Felix Rohrbach <kde@fxrh.de> + * SPDX-FileCopyrightText: 2015 Felix Rohrbach <kde@fxrh.de> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once diff --git a/lib/logging.cpp b/lib/logging.cpp index c346fbf1..3f757393 100644 --- a/lib/logging.cpp +++ b/lib/logging.cpp @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2017 Elvis Angelaccio <elvid.angelaccio@kde.org> + * SPDX-FileCopyrightText: 2017 Elvis Angelaccio <elvid.angelaccio@kde.org> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "logging.h" @@ -24,6 +12,7 @@ LOGGING_CATEGORY(MAIN, "quotient.main") LOGGING_CATEGORY(EVENTS, "quotient.events") LOGGING_CATEGORY(STATE, "quotient.events.state") +LOGGING_CATEGORY(MEMBERS, "quotient.events.members") LOGGING_CATEGORY(MESSAGES, "quotient.events.messages") LOGGING_CATEGORY(EPHEMERAL, "quotient.events.ephemeral") LOGGING_CATEGORY(E2EE, "quotient.e2ee") diff --git a/lib/logging.h b/lib/logging.h index ce4131bb..21d05d8b 100644 --- a/lib/logging.h +++ b/lib/logging.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2017 Kitsune Ral <kitsune-ral@users.sf.net> + * SPDX-FileCopyrightText: 2017 Kitsune Ral <kitsune-ral@users.sf.net> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once @@ -23,6 +11,7 @@ Q_DECLARE_LOGGING_CATEGORY(MAIN) Q_DECLARE_LOGGING_CATEGORY(STATE) +Q_DECLARE_LOGGING_CATEGORY(MEMBERS) Q_DECLARE_LOGGING_CATEGORY(MESSAGES) Q_DECLARE_LOGGING_CATEGORY(EVENTS) Q_DECLARE_LOGGING_CATEGORY(EPHEMERAL) diff --git a/lib/networkaccessmanager.cpp b/lib/networkaccessmanager.cpp index b9037bcc..43a8287a 100644 --- a/lib/networkaccessmanager.cpp +++ b/lib/networkaccessmanager.cpp @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2018 Kitsune Ral <kitsune-ral@users.sf.net> + * SPDX-FileCopyrightText: 2018 Kitsune Ral <kitsune-ral@users.sf.net> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "networkaccessmanager.h" @@ -52,9 +40,10 @@ static NetworkAccessManager* createNam() auto nam = new NetworkAccessManager(QCoreApplication::instance()); #if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) // See #109; in newer Qt, bearer management is deprecated altogether - nam->connect(nam, &QNetworkAccessManager::networkAccessibleChanged, [nam] { - nam->setNetworkAccessible(QNetworkAccessManager::Accessible); - }); + NetworkAccessManager::connect(nam, + &QNetworkAccessManager::networkAccessibleChanged, [nam] { + nam->setNetworkAccessible(QNetworkAccessManager::Accessible); + }); #endif return nam; } diff --git a/lib/networkaccessmanager.h b/lib/networkaccessmanager.h index a678b80f..6075767a 100644 --- a/lib/networkaccessmanager.h +++ b/lib/networkaccessmanager.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2018 Kitsune Ral <kitsune-ral@users.sf.net> + * SPDX-FileCopyrightText: 2018 Kitsune Ral <kitsune-ral@users.sf.net> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once diff --git a/lib/networksettings.cpp b/lib/networksettings.cpp index 40ecba11..db16034a 100644 --- a/lib/networksettings.cpp +++ b/lib/networksettings.cpp @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2017 Kitsune Ral <kitsune-ral@users.sf.net> + * SPDX-FileCopyrightText: 2017 Kitsune Ral <kitsune-ral@users.sf.net> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "networksettings.h" diff --git a/lib/networksettings.h b/lib/networksettings.h index 2399cf5f..31602734 100644 --- a/lib/networksettings.h +++ b/lib/networksettings.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2017 Kitsune Ral <kitsune-ral@users.sf.net> + * SPDX-FileCopyrightText: 2017 Kitsune Ral <kitsune-ral@users.sf.net> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once diff --git a/lib/qt_connection_util.h b/lib/qt_connection_util.h index 699735d4..158d7a40 100644 --- a/lib/qt_connection_util.h +++ b/lib/qt_connection_util.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2019 Kitsune Ral <kitsune-ral@users.sf.net> + * SPDX-FileCopyrightText: 2019 Kitsune Ral <kitsune-ral@users.sf.net> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once diff --git a/lib/quotient_common.h b/lib/quotient_common.h index bb05af05..e2384f12 100644 --- a/lib/quotient_common.h +++ b/lib/quotient_common.h @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2019 Kitsune Ral <Kitsune-Ral@users.sf.net> +// +// SPDX-License-Identifier: LGPL-2.1-or-later + #pragma once #include <qobjectdefs.h> diff --git a/lib/room.cpp b/lib/room.cpp index a309cd24..bc89464d 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2015 Felix Rohrbach <kde@fxrh.de> + * SPDX-FileCopyrightText: 2015 Felix Rohrbach <kde@fxrh.de> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "room.h" @@ -36,6 +24,7 @@ #include "csapi/room_state.h" #include "csapi/room_upgrades.h" #include "csapi/rooms.h" +#include "csapi/read_markers.h" #include "csapi/tags.h" #include "events/callanswerevent.h" @@ -55,7 +44,6 @@ #include "events/roompowerlevelsevent.h" #include "jobs/downloadfilejob.h" #include "jobs/mediathumbnailjob.h" -#include "jobs/postreadmarkersjob.h" #include "events/roomcanonicalaliasevent.h" #include <QtCore/QDir> @@ -192,7 +180,7 @@ public: // void inviteUser(User* u); // We might get it at some point in time. void insertMemberIntoMap(User* u); - void removeMemberFromMap(const QString& username, User* u); + void removeMemberFromMap(User* u); // This updates the room displayname field (which is the way a room // should be shown in the room list); called whenever the list of @@ -263,10 +251,11 @@ public: for (auto&& eptr : events) { const auto& evt = *eptr; Q_ASSERT(evt.isStateEvent()); - // Update baseState afterwards to make sure that the old state - // is valid and usable inside processStateEvent - changes |= q->processStateEvent(evt); - baseState[{ evt.matrixType(), evt.stateKey() }] = move(eptr); + auto change = q->processStateEvent(evt); + if (change != NoChange) { + changes |= change; + baseState[{ evt.matrixType(), evt.stateKey() }] = move(eptr); + } } if (events.size() > 9 || et.nsecsElapsed() >= profilerMinNsecs()) qCDebug(PROFILER) @@ -350,7 +339,7 @@ public: */ bool processReplacement(const RoomMessageEvent& newEvent); - void setTags(TagsMap newTags); + void setTags(TagsMap&& newTags); QJsonObject toJson() const; @@ -632,8 +621,8 @@ Room::Changes Room::Private::setLastReadEvent(User* u, QString eventId) emit q->readMarkerForUserMoved(u, eventId, storedId); if (isLocalUser(u)) { if (storedId != serverReadMarker) - connection->callApi<PostReadMarkersJob>(BackgroundRequest, id, - storedId); + connection->callApi<SetReadMarkerJob>(BackgroundRequest, id, + storedId); emit q->readMarkerMoved(eventId, storedId); return Change::ReadMarkerChange; } @@ -857,7 +846,7 @@ const Room::RelatedEvents Room::relatedEvents(const RoomEvent& evt, void Room::Private::getAllMembers() { // If already loaded or already loading, there's nothing to do here. - if (q->joinedCount() <= membersMap.size() || isJobRunning(allMembersJob)) + if (q->joinedCount() <= membersMap.size() || isJobPending(allMembersJob)) return; allMembersJob = connection->callApi<GetMembersByRoomJob>( @@ -1010,11 +999,11 @@ TagRecord Room::tag(const QString& name) const { return d->tags.value(name); } std::pair<bool, QString> validatedTag(QString name) { - if (name.contains('.')) + if (name.isEmpty() || name.indexOf('.', 1) != -1) return { false, name }; qCWarning(MAIN) << "The tag" << name - << "doesn't follow the CS API conventions"; + << "doesn't follow the CS API conventions"; name.prepend("u."); qCWarning(MAIN) << "Using " << name << "instead"; @@ -1073,20 +1062,20 @@ void Room::setTags(TagsMap newTags, ActionScope applyOn) if (propagate) { for (auto* r = this; (r = r->successor(joinStates));) - r->setTags(newTags, ActionScope::ThisRoomOnly); + r->setTags(d->tags, ActionScope::ThisRoomOnly); } } -void Room::Private::setTags(TagsMap newTags) +void Room::Private::setTags(TagsMap&& newTags) { emit q->tagsAboutToChange(); const auto keys = newTags.keys(); for (const auto& k : keys) - if (const auto& checkRes = validatedTag(k); checkRes.first) { - if (newTags.contains(checkRes.second)) + if (const auto& [adjusted, adjustedTag] = validatedTag(k); adjusted) { + if (newTags.contains(adjustedTag)) newTags.remove(k); else - newTags.insert(checkRes.second, newTags.take(k)); + newTags.insert(adjustedTag, newTags.take(k)); } tags = move(newTags); @@ -1192,8 +1181,8 @@ QString Room::fileNameToDownload(const QString& eventId) const FileTransferInfo Room::fileTransferInfo(const QString& id) const { - auto infoIt = d->fileTransfers.find(id); - if (infoIt == d->fileTransfers.end()) + const auto infoIt = d->fileTransfers.constFind(id); + if (infoIt == d->fileTransfers.cend()) return {}; // FIXME: Add lib tests to make sure FileTransferInfo::status stays @@ -1222,8 +1211,8 @@ QUrl Room::fileSource(const QString& id) const return url; // No urlToDownload means it's a pending or completed upload. - auto infoIt = d->fileTransfers.find(id); - if (infoIt != d->fileTransfers.end()) + auto infoIt = d->fileTransfers.constFind(id); + if (infoIt != d->fileTransfers.cend()) return QUrl::fromLocalFile(infoIt->localFileInfo.absoluteFilePath()); qCWarning(MAIN) << "File source for identifier" << id << "not found"; @@ -1312,7 +1301,6 @@ void Room::handleRoomKeyEvent(const RoomKeyEvent& roomKeyEvent, Q_UNUSED(roomKeyEvent) Q_UNUSED(senderKey) qCWarning(E2EE) << "End-to-end encryption (E2EE) support is turned off."; - return; #else // Quotient_E2EE_ENABLED if (roomKeyEvent.algorithm() != MegolmV1AesSha2AlgoKey) { qCWarning(E2EE) << "Ignoring unsupported algorithm" @@ -1354,14 +1342,27 @@ Room::Changes Room::Private::setSummary(RoomSummary&& newSummary) void Room::Private::insertMemberIntoMap(User* u) { - const auto userName = u->name(q); - // If there is exactly one namesake of the added user, signal member - // renaming for that other one because the two should be disambiguated now. + const auto maybeUserName = + getCurrentState<RoomMemberEvent>(u->id())->newDisplayName(); + if (!maybeUserName) + qCWarning(MEMBERS) << "insertMemberIntoMap():" << u->id() + << "has no name (even empty)"; + const auto userName = maybeUserName.value_or(QString()); const auto namesakes = membersMap.values(userName); + qCDebug(MEMBERS) << "insertMemberIntoMap(), user" << u->id() + << "with name" << userName << '-' + << namesakes.size() << "namesake(s) found"; - // Callers should check they are not adding an existing user once more. + // Callers should make sure they are not adding an existing user once more Q_ASSERT(!namesakes.contains(u)); + if (namesakes.contains(u)) { // Release version whines but continues + qCCritical(MEMBERS) << "Trying to add a user" << u->id() << "to room" + << q->objectName() << "but that's already in it"; + return; + } + // If there is exactly one namesake of the added user, signal member + // renaming for that other one because the two should be disambiguated now if (namesakes.size() == 1) emit q->memberAboutToRename(namesakes.front(), namesakes.front()->fullName(q)); @@ -1370,18 +1371,43 @@ void Room::Private::insertMemberIntoMap(User* u) emit q->memberRenamed(namesakes.front()); } -void Room::Private::removeMemberFromMap(const QString& username, User* u) +void Room::Private::removeMemberFromMap(User* u) { + const auto userName = + getCurrentState<RoomMemberEvent>( + u->id())->newDisplayName().value_or(QString()); + + qCDebug(MEMBERS) << "removeMemberFromMap(), username" << userName + << "for user" << u->id(); User* namesake = nullptr; - auto namesakes = membersMap.values(username); + auto namesakes = membersMap.values(userName); + // If there was one namesake besides the removed user, signal member + // renaming for it because it doesn't need to be disambiguated any more. if (namesakes.size() == 2) { - namesake = namesakes.front() == u ? namesakes.back() : namesakes.front(); + namesake = + namesakes.front() == u ? namesakes.back() : namesakes.front(); Q_ASSERT_X(namesake != u, __FUNCTION__, "Room members list is broken"); - emit q->memberAboutToRename(namesake, username); + emit q->memberAboutToRename(namesake, userName); + } + if (membersMap.remove(userName, u) == 0) { + qCDebug(MEMBERS) << "No entries removed; checking the whole list"; + // Unless at the stage of initial filling, this no removed entries + // is suspicious; double-check that this user is not found in + // the whole map, and stop (for debug builds) or shout in the logs + // (for release builds) if there's one. That search is O(n), which + // may come rather expensive for larger rooms. + QElapsedTimer et; + auto it = std::find(membersMap.cbegin(), membersMap.cend(), u); + if (et.nsecsElapsed() > profilerMinNsecs() / 10) + qCDebug(MEMBERS) << "...done in" << et; + if (it != membersMap.cend()) { + Q_ASSERT_X(false, __FUNCTION__, + "Mismatched name in the room members list"); + qCCritical(MEMBERS) << "Mismatched name in the room members list;" + " avoiding the list corruption"; + membersMap.remove(it.key(), u); + } } - membersMap.remove(username, u); - // If there was one namesake besides the removed user, signal member - // renaming for it because it doesn't need to be disambiguated any more. if (namesake) emit q->memberRenamed(namesake); } @@ -1423,7 +1449,7 @@ Room::Private::moveEventsToTimeline(RoomEventsRange events, } const auto insertedSize = (index - baseIndex) * placement; Q_ASSERT(insertedSize == int(events.size())); - return insertedSize; + return Timeline::size_type(insertedSize); } QString Room::memberName(const QString& mxId) const @@ -1639,15 +1665,15 @@ QString Room::retryMessage(const QString& txnId) const auto it = findPendingEvent(txnId); Q_ASSERT(it != d->unsyncedEvents.end()); qCDebug(EVENTS) << "Retrying transaction" << txnId; - const auto& transferIt = d->fileTransfers.find(txnId); - if (transferIt != d->fileTransfers.end()) { + const auto& transferIt = d->fileTransfers.constFind(txnId); + if (transferIt != d->fileTransfers.cend()) { Q_ASSERT(transferIt->isUpload); if (transferIt->status == FileTransferInfo::Completed) { qCDebug(MESSAGES) << "File for transaction" << txnId << "has already been uploaded, bypassing re-upload"; } else { - if (isJobRunning(transferIt->job)) { + if (isJobPending(transferIt->job)) { qCDebug(MESSAGES) << "Abandoning the upload job for transaction" << txnId << "and starting again"; transferIt->job->abandon(); @@ -1680,7 +1706,7 @@ void Room::discardMessage(const QString& txnId) const auto& transferIt = d->fileTransfers.find(txnId); if (transferIt != d->fileTransfers.end()) { Q_ASSERT(transferIt->isUpload); - if (isJobRunning(transferIt->job)) { + if (isJobPending(transferIt->job)) { transferIt->status = FileTransferInfo::Cancelled; transferIt->job->abandon(); emit fileTransferFailed(txnId, tr("File upload cancelled")); @@ -1737,7 +1763,8 @@ QString Room::postFile(const QString& plainText, const QUrl& localPath, // to enable the preview while the event is pending. uploadFile(txnId, localPath); // Below, the upload job is used as a context object to clean up connections - connect(this, &Room::fileTransferCompleted, d->fileTransfers[txnId].job, + const auto& transferJob = d->fileTransfers.value(txnId).job; + connect(this, &Room::fileTransferCompleted, transferJob, [this, txnId](const QString& id, const QUrl&, const QUrl& mxcUri) { if (id == txnId) { auto it = findPendingEvent(txnId); @@ -1756,7 +1783,7 @@ QString Room::postFile(const QString& plainText, const QUrl& localPath, } } }); - connect(this, &Room::fileTransferCancelled, d->fileTransfers[txnId].job, + connect(this, &Room::fileTransferCancelled, transferJob, [this, txnId](const QString& id) { if (id == txnId) { auto it = findPendingEvent(txnId); @@ -1885,7 +1912,7 @@ void Room::getPreviousContent(int limit, const QString &filter) { d->getPrevious void Room::Private::getPreviousContent(int limit, const QString &filter) { - if (isJobRunning(eventsHistoryJob)) + if (isJobPending(eventsHistoryJob)) return; eventsHistoryJob = @@ -1938,7 +1965,7 @@ void Room::uploadFile(const QString& id, const QUrl& localFilename, "localFilename should point at a local file"); auto fileName = localFilename.toLocalFile(); auto job = connection()->uploadFile(fileName, overrideContentType); - if (isJobRunning(job)) { + if (isJobPending(job)) { d->fileTransfers[id] = { job, fileName, true }; connect(job, &BaseJob::uploadProgress, this, [this, id](qint64 sent, qint64 total) { @@ -1958,8 +1985,8 @@ void Room::uploadFile(const QString& id, const QUrl& localFilename, void Room::downloadFile(const QString& eventId, const QUrl& localFilename) { - auto ongoingTransfer = d->fileTransfers.find(eventId); - if (ongoingTransfer != d->fileTransfers.end() + if (auto ongoingTransfer = d->fileTransfers.constFind(eventId); + ongoingTransfer != d->fileTransfers.cend() && ongoingTransfer->status == FileTransferInfo::Started) { qCWarning(MAIN) << "Transfer for" << eventId << "is ongoing; download won't start"; @@ -1994,7 +2021,7 @@ void Room::downloadFile(const QString& eventId, const QUrl& localFilename) qDebug(MAIN) << "File path:" << filePath; } auto job = connection()->downloadFile(fileUrl, filePath); - if (isJobRunning(job)) { + if (isJobPending(job)) { // If there was a previous transfer (completed or failed), overwrite it. d->fileTransfers[eventId] = { job, job->targetFileName() }; connect(job, &BaseJob::downloadProgress, this, @@ -2016,13 +2043,13 @@ void Room::downloadFile(const QString& eventId, const QUrl& localFilename) void Room::cancelFileTransfer(const QString& id) { - auto it = d->fileTransfers.find(id); - if (it == d->fileTransfers.end()) { + const auto it = d->fileTransfers.constFind(id); + if (it == d->fileTransfers.cend()) { qCWarning(MAIN) << "No information on file transfer" << id << "in room" << d->id; return; } - if (isJobRunning(it->job)) + if (isJobPending(it->job)) it->job->abandon(); d->fileTransfers.remove(id); emit fileTransferCancelled(id); @@ -2119,8 +2146,8 @@ bool Room::Private::processRedaction(const RedactionEvent& redaction) { // Can't use findInTimeline because it returns a const iterator, and // we need to change the underlying TimelineItem. - const auto pIdx = eventsIndex.find(redaction.redactedEvent()); - if (pIdx == eventsIndex.end()) + const auto pIdx = eventsIndex.constFind(redaction.redactedEvent()); + if (pIdx == eventsIndex.cend()) return false; Q_ASSERT(q->isValidIndex(*pIdx)); @@ -2190,8 +2217,8 @@ bool Room::Private::processReplacement(const RoomMessageEvent& newEvent) { // Can't use findInTimeline because it returns a const iterator, and // we need to change the underlying TimelineItem. - const auto pIdx = eventsIndex.find(newEvent.replacedEvent()); - if (pIdx == eventsIndex.end()) + const auto pIdx = eventsIndex.constFind(newEvent.replacedEvent()); + if (pIdx == eventsIndex.cend()) return false; Q_ASSERT(q->isValidIndex(*pIdx)); @@ -2434,57 +2461,95 @@ void Room::Private::addHistoricalMessageEvents(RoomEvents&& events) Room::Changes Room::processStateEvent(const RoomEvent& e) { if (!e.isStateEvent()) - return Change::NoChange; + return NoChange; - // Find a value (create empty if necessary) and get a reference to it - // getCurrentState<> is not used here because it (creates and) returns + // Find a value (create an empty one if necessary) and get a reference + // to it. Can't use getCurrentState<>() because it (creates and) returns // a stub if a value is not found, and what's needed here is a "real" event // or nullptr. - const auto*& curStateEvent = - d->currentState[{ e.matrixType(), e.stateKey() }]; + auto& curStateEvent = d->currentState[{ e.matrixType(), e.stateKey() }]; // Prepare for the state change - visit(e, [this, oldRme = static_cast<const RoomMemberEvent*>(curStateEvent)]( - const RoomMemberEvent& rme) { - auto* u = user(rme.userId()); - if (!u) { // ??? - qCCritical(MAIN) - << "Could not get a user object for" << rme.userId(); - return; - } - const auto prevMembership = oldRme ? oldRme->membership() - : MembershipType::Leave; - switch (prevMembership) { - case MembershipType::Invite: - if (rme.membership() != prevMembership) { - d->usersInvited.removeOne(u); - Q_ASSERT(!d->usersInvited.contains(u)); + // clang-format off + const bool proceed = visit(e + , [this, curStateEvent](const RoomMemberEvent& rme) { + // clang-format on + auto* oldRme = static_cast<const RoomMemberEvent*>(curStateEvent); + auto* u = user(rme.userId()); + if (!u) { // Some terribly malformed user id? + qCCritical(MAIN) << "Could not get a user object for" + << rme.userId(); + return false; // Stay low and hope for the best... } - break; - case MembershipType::Join: - switch (rme.membership()) { - case MembershipType::Join: // rename/avatar change or no-op - if (rme.newDisplayName()) { - emit memberAboutToRename(u, *rme.newDisplayName()); - d->removeMemberFromMap(u->name(this), u); + const auto prevMembership = oldRme ? oldRme->membership() + : MembershipType::Leave; + switch (prevMembership) { + case MembershipType::Invite: + if (rme.membership() != prevMembership) { + d->usersInvited.removeOne(u); + Q_ASSERT(!d->usersInvited.contains(u)); } break; - case MembershipType::Invite: - qCWarning(MAIN) << "Membership change from Join to Invite:" - << rme; - [[fallthrough]]; - default: // whatever the new membership, it's no more Join - d->removeMemberFromMap(u->name(this), u); - emit userRemoved(u); + case MembershipType::Join: + if (rme.membership() == MembershipType::Join) { + // rename/avatar change or no-op + if (rme.newDisplayName()) { + emit memberAboutToRename(u, *rme.newDisplayName()); + d->removeMemberFromMap(u); + } + if (!rme.newDisplayName() && !rme.newAvatarUrl()) { + qCWarning(MEMBERS) + << "No-op membership event for" << rme.userId() + << "- retaining the state"; + qCWarning(MEMBERS) << "The event dump:" << rme; + return false; + } + } else { + if (rme.membership() == MembershipType::Invite) + qCWarning(MAIN) + << "Membership change from Join to Invite:" << rme; + // whatever the new membership, it's no more Join + d->removeMemberFromMap(u); + emit userRemoved(u); + } + break; + case MembershipType::Ban: + case MembershipType::Knock: + case MembershipType::Leave: + if (rme.membership() == MembershipType::Invite + || rme.membership() == MembershipType::Join) { + d->membersLeft.removeOne(u); + Q_ASSERT(!d->membersLeft.contains(u)); + } + break; + case MembershipType::Undefined: + ; // A warning will be dropped in the post-processing block below } - break; - default: - if (rme.membership() == MembershipType::Invite - || rme.membership() == MembershipType::Join) { - d->membersLeft.removeOne(u); - Q_ASSERT(!d->membersLeft.contains(u)); + return true; + // clang-format off + } + , [this, curStateEvent]( const EncryptionEvent& ee) { + // clang-format on + auto* oldEncEvt = + static_cast<const EncryptionEvent*>(curStateEvent); + if (ee.algorithm().isEmpty()) { + qWarning(STATE) + << "The encryption event for room" << objectName() + << "doesn't have 'algorithm' specified - ignoring"; + return false; } + if (oldEncEvt + && oldEncEvt->encryption() != EncryptionEventContent::Undefined) { + qCWarning(STATE) << "The room is already encrypted but a new" + " room encryption event arrived - ignoring"; + return false; + } + return true; + // clang-format off } - }); + , true); // By default, go forward with the state change + // clang-format on + if (!proceed) + return NoChange; // Change the state const auto* const oldStateEvent = @@ -2492,47 +2557,35 @@ Room::Changes Room::processStateEvent(const RoomEvent& e) Q_ASSERT(!oldStateEvent || (oldStateEvent->matrixType() == e.matrixType() && oldStateEvent->stateKey() == e.stateKey())); - if (!is<RoomMemberEvent>(e)) // Room member events are too numerous + if (is<RoomMemberEvent>(e)) + qCDebug(MEMBERS) << "Updated room member state:" << e; + else qCDebug(STATE) << "Updated room state:" << e; // Update internal structures as per the change and work out the return value // clang-format off - return visit(e + const auto result = visit(e , [] (const RoomNameEvent&) { return NameChange; } - , [] (const RoomAliasesEvent&) { - return NoChange; // This event has been removed by MSC2432 - } , [this, oldStateEvent] (const RoomCanonicalAliasEvent& cae) { // clang-format on setObjectName(cae.alias().isEmpty() ? d->id : cae.alias()); - QString previousCanonicalAlias = - oldStateEvent - ? static_cast<const RoomCanonicalAliasEvent*>(oldStateEvent) - ->alias() - : QString(); - - auto previousAltAliases = - oldStateEvent - ? static_cast<const RoomCanonicalAliasEvent*>(oldStateEvent) - ->altAliases() - : QStringList(); - - if (!previousCanonicalAlias.isEmpty()) { - previousAltAliases.push_back(previousCanonicalAlias); + const auto* oldCae = + static_cast<const RoomCanonicalAliasEvent*>(oldStateEvent); + QStringList previousAltAliases {}; + if (oldCae) { + previousAltAliases = oldCae->altAliases(); + if (!oldCae->alias().isEmpty()) + previousAltAliases.push_back(oldCae->alias()); } - const auto previousAliases = std::move(previousAltAliases); - auto newAliases = cae.altAliases(); - - if (!cae.alias().isEmpty()) { + if (!cae.alias().isEmpty()) newAliases.push_front(cae.alias()); - } - connection()->updateRoomAliases(id(), previousAliases, newAliases); + connection()->updateRoomAliases(id(), previousAltAliases, newAliases); return AliasesChange; // clang-format off } @@ -2572,33 +2625,23 @@ Room::Changes Room::processStateEvent(const RoomEvent& e) if (u == localUser() && evt.isDirect()) connection()->addToDirectChats(this, user(evt.senderId())); break; - default: + case MembershipType::Knock: + case MembershipType::Ban: + case MembershipType::Leave: if (!d->membersLeft.contains(u)) d->membersLeft.append(u); + break; + case MembershipType::Undefined: + qCWarning(MEMBERS) << "Ignored undefined membership type"; } return MembersChange; // clang-format off } - , [this, oldEncEvt = static_cast<const EncryptionEvent*>(oldStateEvent)]( - const EncryptionEvent& ee) { - // clang-format on - if (ee.algorithm().isEmpty()) { - qWarning(STATE) - << "The encryption event for room" << objectName() - << "doesn't have 'algorithm' specified - ignoring"; - return NoChange; - } - if (oldEncEvt - && oldEncEvt->encryption() != EncryptionEventContent::Undefined) { - qCWarning(STATE) << "The room is already encrypted but a new" - " room encryption event arrived - ignoring"; - return NoChange; - } + , [this] (const EncryptionEvent&) { // As encryption can only be switched on once, emit the signal here // instead of aggregating and emitting in updateData() emit encryption(); return OtherChange; - // clang-format off } , [this] (const RoomTombstoneEvent& evt) { const auto successorId = evt.successorRoomId(); @@ -2615,9 +2658,12 @@ Room::Changes Room::processStateEvent(const RoomEvent& e) }); return OtherChange; + // clang-format off } - ); + , OtherChange); // clang-format on + Q_ASSERT(result != NoChange); + return result; } Room::Changes Room::processEphemeralEvent(EventPtr&& event) @@ -2779,7 +2825,7 @@ QString Room::Private::calculateDisplayname() const const bool localUserIsIn = joinState == JoinState::Join; const bool emptyRoom = membersMap.isEmpty() - || (membersMap.size() == 1 && isLocalUser(*membersMap.begin())); + || (membersMap.size() == 1 && isLocalUser(*membersMap.cbegin())); const bool nonEmptySummary = summary.heroes && !summary.heroes->empty(); auto shortlist = nonEmptySummary ? buildShortlist(*summary.heroes) : !emptyRoom ? buildShortlist(membersMap) @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2015 Felix Rohrbach <kde@fxrh.de> + * SPDX-FileCopyrightText: 2015 Felix Rohrbach <kde@fxrh.de> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once @@ -547,7 +535,7 @@ public: return setState(EvT(std::forward<ArgTs>(args)...)); } -public slots: +public Q_SLOTS: /** Check whether the room should be upgraded */ void checkVersion(); @@ -611,7 +599,7 @@ public slots: void answerCall(const QString& callId, const QString& sdp); void hangupCall(const QString& callId); -signals: +Q_SIGNALS: /// Initial set of state events has been loaded /** * The initial set is what comes from the initial sync for the room. diff --git a/lib/settings.h b/lib/settings.h index c45764a6..badabec2 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2016 Kitsune Ral <kitsune-ral@users.sf.net> + * SPDX-FileCopyrightText: 2016 Kitsune Ral <kitsune-ral@users.sf.net> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once diff --git a/lib/syncdata.cpp b/lib/syncdata.cpp index e6472e18..f67ab6c7 100644 --- a/lib/syncdata.cpp +++ b/lib/syncdata.cpp @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2018 Kitsune Ral <kitsune-ral@users.sf.net> + * SPDX-FileCopyrightText: 2018 Kitsune Ral <kitsune-ral@users.sf.net> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "syncdata.h" diff --git a/lib/syncdata.h b/lib/syncdata.h index 67d04557..d9868e46 100644 --- a/lib/syncdata.h +++ b/lib/syncdata.h @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2018 Kitsune Ral <kitsune-ral@users.sf.net> + * SPDX-FileCopyrightText: 2018 Kitsune Ral <kitsune-ral@users.sf.net> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once diff --git a/lib/uri.cpp b/lib/uri.cpp index 8370d83a..e0912eb6 100644 --- a/lib/uri.cpp +++ b/lib/uri.cpp @@ -30,7 +30,9 @@ Uri::Uri(QByteArray primaryId, QByteArray secondaryId, QString query) for (const auto& p: replacePairs) if (primaryId[0] == p.sigil) { primaryType_ = Type(p.sigil); - pathToBe = p.uriString + primaryId.mid(1); + auto safePrimaryId = primaryId.mid(1); + safePrimaryId.replace('/', "%2F"); + pathToBe = p.uriString + safePrimaryId; break; } if (!secondaryId.isEmpty()) { @@ -38,11 +40,40 @@ Uri::Uri(QByteArray primaryId, QByteArray secondaryId, QString query) primaryType_ = Invalid; return; } - pathToBe += "/event/" + secondaryId.mid(1); + auto safeSecondaryId = secondaryId.mid(1); + safeSecondaryId.replace('/', "%2F"); + pathToBe += "/event/" + safeSecondaryId; } - setPath(pathToBe); + setPath(pathToBe, QUrl::TolerantMode); } - setQuery(std::move(query)); + if (!query.isEmpty()) + setQuery(query); +} + +static inline auto encodedPath(const QUrl& url) +{ + return url.path(QUrl::EncodeDelimiters | QUrl::EncodeUnicode); +} + +static QString pathSegment(const QUrl& url, int which) +{ + return QUrl::fromPercentEncoding( + encodedPath(url).section('/', which, which).toUtf8()); +} + +static auto decodeFragmentPart(const QStringRef& part) +{ + return QUrl::fromPercentEncoding(part.toLatin1()).toUtf8(); +} + +static auto matrixToUrlRegexInit() +{ + // See https://matrix.org/docs/spec/appendices#matrix-to-navigation + const QRegularExpression MatrixToUrlRE { + "^/(?<main>[^:]+:[^/?]+)(/(?<sec>(\\$|%24)[^?]+))?(\\?(?<query>.+))?$" + }; + Q_ASSERT(MatrixToUrlRE.isValid()); + return MatrixToUrlRE; } Uri::Uri(QUrl url) : QUrl(std::move(url)) @@ -51,14 +82,13 @@ Uri::Uri(QUrl url) : QUrl(std::move(url)) if (isEmpty()) return; // primaryType_ == Empty - if (!QUrl::isValid()) { // MatrixUri::isValid() checks primaryType_ - primaryType_ = Invalid; + primaryType_ = Invalid; + if (!QUrl::isValid()) // MatrixUri::isValid() checks primaryType_ return; - } if (scheme() == "matrix") { // Check sanity as per https://github.com/matrix-org/matrix-doc/pull/2312 - const auto& urlPath = path(); + const auto& urlPath = encodedPath(*this); const auto& splitPath = urlPath.splitRef('/'); switch (splitPath.size()) { case 2: @@ -83,17 +113,15 @@ Uri::Uri(QUrl url) : QUrl(std::move(url)) primaryType_ = NonMatrix; // Default, unless overridden by the code below if (scheme() == "https" && authority() == "matrix.to") { - // See https://matrix.org/docs/spec/appendices#matrix-to-navigation - static const QRegularExpression MatrixToUrlRE { - R"(^/(?<main>[^/?]+)(/(?<sec>[^?]+))?(\?(?<query>.+))?$)" - }; + static const auto MatrixToUrlRE = matrixToUrlRegexInit(); // matrix.to accepts both literal sigils (as well as & and ? used in // its "query" substitute) and their %-encoded forms; // so force QUrl to decode everything. - auto f = fragment(QUrl::FullyDecoded); + auto f = fragment(QUrl::EncodeUnicode); if (auto&& m = MatrixToUrlRE.match(f); m.hasMatch()) - *this = Uri { m.captured("main").toUtf8(), - m.captured("sec").toUtf8(), m.captured("query") }; + *this = Uri { decodeFragmentPart(m.capturedRef("main")), + decodeFragmentPart(m.capturedRef("sec")), + decodeFragmentPart(m.capturedRef("query")) }; } } @@ -119,7 +147,7 @@ Uri::Type Uri::type() const { return primaryType_; } Uri::SecondaryType Uri::secondaryType() const { - return path().section('/', 2, 2) == "event" ? EventId : NoSecondaryId; + return pathSegment(*this, 2) == "event" ? EventId : NoSecondaryId; } QUrl Uri::toUrl(UriForm form) const @@ -128,7 +156,7 @@ QUrl Uri::toUrl(UriForm form) const return {}; if (form == CanonicalUri || type() == NonMatrix) - return *this; + return *this; // NOLINT(cppcoreguidelines-slicing): It's intentional QUrl url; url.setScheme("https"); @@ -148,13 +176,13 @@ QString Uri::primaryId() const if (primaryType_ == Empty || primaryType_ == Invalid) return {}; - const auto& idStem = path().section('/', 1, 1); + const auto& idStem = pathSegment(*this, 1); return idStem.isEmpty() ? idStem : primaryType_ + idStem; } QString Uri::secondaryId() const { - const auto& idStem = path().section('/', 3); + const auto& idStem = pathSegment(*this, 3); return idStem.isEmpty() ? idStem : secondaryType() + idStem; } diff --git a/lib/uriresolver.cpp b/lib/uriresolver.cpp index ec30512c..27360bcc 100644 --- a/lib/uriresolver.cpp +++ b/lib/uriresolver.cpp @@ -75,6 +75,8 @@ private: std::tuple<FnTs...> fns_; }; +template <typename... FnTs> +StaticUriDispatcher(FnTs&&... fns) -> StaticUriDispatcher<FnTs...>; UriResolveResult Quotient::visitResource( Connection* account, const Uri& uri, diff --git a/lib/uriresolver.h b/lib/uriresolver.h index 9b2ced9d..428ce04c 100644 --- a/lib/uriresolver.h +++ b/lib/uriresolver.h @@ -141,7 +141,7 @@ public: return UriResolverBase::visitResource(account, uri); } -signals: +Q_SIGNALS: /// An action on a user has been requested void userAction(Quotient::User* user, QString action); diff --git a/lib/user.cpp b/lib/user.cpp index 45a9c121..9c2b76b5 100644 --- a/lib/user.cpp +++ b/lib/user.cpp @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2015 Felix Rohrbach <kde@fxrh.de> + * SPDX-FileCopyrightText: 2015 Felix Rohrbach <kde@fxrh.de> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "user.h" @@ -78,7 +66,7 @@ QString User::id() const { return d->id; } bool User::isGuest() const { Q_ASSERT(!d->id.isEmpty() && d->id.startsWith('@')); - auto it = std::find_if_not(d->id.begin() + 1, d->id.end(), + auto it = std::find_if_not(d->id.cbegin() + 1, d->id.cend(), [](QChar c) { return c.isDigit(); }); Q_ASSERT(it != d->id.end()); return *it == ':'; @@ -138,7 +126,7 @@ inline bool User::doSetAvatar(SourceT&& source) connect(j, &BaseJob::success, this, [this, newUrl = QUrl(contentUri)] { if (newUrl == d->defaultAvatar.url()) { - d->defaultAvatar.updateUrl(move(newUrl)); + d->defaultAvatar.updateUrl(newUrl); emit defaultAvatarChanged(); } else qCWarning(MAIN) << "User" << id() @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2015 Felix Rohrbach <kde@fxrh.de> + * SPDX-FileCopyrightText: 2015 Felix Rohrbach <kde@fxrh.de> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once @@ -122,7 +110,7 @@ public: QString avatarMediaId(const Room* room = nullptr) const; QUrl avatarUrl(const Room* room = nullptr) const; -public slots: +public Q_SLOTS: /// Set a new name in the global user profile void rename(const QString& newName); /// Set a new name for the user in one room @@ -143,7 +131,7 @@ public slots: /// Check whether the user is in ignore list bool isIgnored() const; -signals: +Q_SIGNALS: void defaultNameChanged(); void defaultAvatarChanged(); diff --git a/lib/util.cpp b/lib/util.cpp index 0c1c54ff..14492ba6 100644 --- a/lib/util.cpp +++ b/lib/util.cpp @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2018 Kitsune Ral <kitsune-ral@users.sf.net> + * SPDX-FileCopyrightText: 2018 Kitsune Ral <kitsune-ral@users.sf.net> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "util.h" @@ -161,9 +149,6 @@ static_assert(std::is_same<fn_arg_t<Fo1>, int>(), "Test fn_arg_t defaulting to first argument"); template <typename T> -static QString ft(T&&) -{ - return {}; -} +static QString ft(T&&); static_assert(std::is_same<fn_arg_t<decltype(ft<QString>)>, QString&&>(), "Test function templates"); @@ -1,19 +1,7 @@ /****************************************************************************** - * Copyright (C) 2016 Kitsune Ral <kitsune-ral@users.sf.net> + * SPDX-FileCopyrightText: 2016 Kitsune Ral <kitsune-ral@users.sf.net> * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once @@ -148,7 +136,7 @@ public: namespace _impl { template <typename AlwaysVoid, typename> - struct fn_traits; + struct fn_traits {}; } /// Determine traits of an arbitrary function/lambda/functor diff --git a/libquotient.pri b/libquotient.pri index ef0f112a..677f60d3 100644 --- a/libquotient.pri +++ b/libquotient.pri @@ -72,7 +72,6 @@ HEADERS += \ $$SRCPATH/jobs/syncjob.h \ $$SRCPATH/jobs/mediathumbnailjob.h \ $$SRCPATH/jobs/downloadfilejob.h \ - $$SRCPATH/jobs/postreadmarkersjob.h \ $$files($$SRCPATH/csapi/*.h, false) \ $$files($$SRCPATH/csapi/definitions/*.h, false) \ $$files($$SRCPATH/csapi/definitions/wellknown/*.h, false) \ diff --git a/tests/quotest.cpp b/tests/quotest.cpp index 3b7f2f48..98c01cfc 100644 --- a/tests/quotest.cpp +++ b/tests/quotest.cpp @@ -91,6 +91,7 @@ public slots: void doTest(const QByteArray& testName); private slots: + TEST_DECL(findRoomByAlias) TEST_DECL(loadMembers) TEST_DECL(sendMessage) TEST_DECL(sendReaction) @@ -104,17 +105,21 @@ private slots: // Add more tests above here public: - Room* room() const { return targetRoom; } - Connection* connection() const { return targetRoom->connection(); } + [[nodiscard]] Room* room() const { return targetRoom; } + [[nodiscard]] Connection* connection() const + { + return targetRoom->connection(); + } private: - bool checkFileSendingOutcome(const TestToken& thisTest, - const QString& txnId, const QString& fileName); - bool checkRedactionOutcome(const QByteArray& thisTest, - const QString& evtIdToRedact); - - bool validatePendingEvent(const QString& txnId); - bool checkDirectChat() const; + [[nodiscard]] bool checkFileSendingOutcome(const TestToken& thisTest, + const QString& txnId, + const QString& fileName); + [[nodiscard]] bool checkRedactionOutcome(const QByteArray& thisTest, + const QString& evtIdToRedact); + + [[nodiscard]] bool validatePendingEvent(const QString& txnId); + [[nodiscard]] bool checkDirectChat() const; void finishTest(const TestToken& token, bool condition, const char* file, int line); @@ -182,10 +187,10 @@ TestManager::TestManager(int& argc, char** argv) connect(c, &Connection::connected, this, &TestManager::setupAndRun); connect(c, &Connection::resolveError, this, - [this](const QString& error) { + [](const QString& error) { clog << "Failed to resolve the server: " << error.toStdString() << endl; - this->exit(-2); + QCoreApplication::exit(-2); }, Qt::QueuedConnection); connect(c, &Connection::loginError, this, @@ -195,7 +200,7 @@ TestManager::TestManager(int& argc, char** argv) << message.toStdString() << endl << "Details:" << endl << details.toStdString() << endl; - this->exit(-2); + QCoreApplication::exit(-2); }, Qt::QueuedConnection); connect(c, &Connection::loadedRoomState, this, &TestManager::onNewRoom); @@ -264,7 +269,7 @@ void TestManager::onNewRoom(Room* r) << endl; connect(r, &Room::aboutToAddNewMessages, r, [r](RoomEventsRange timeline) { clog << timeline.size() << " new event(s) in room " - << r->canonicalAlias().toStdString() << endl; + << r->objectName().toStdString() << endl; }); } @@ -302,26 +307,25 @@ void TestManager::doTests() }); } +TEST_IMPL(findRoomByAlias) +{ + auto* roomByAlias = connection()->roomByAlias(targetRoom->canonicalAlias(), + JoinState::Join); + FINISH_TEST(roomByAlias == targetRoom); +} + TEST_IMPL(loadMembers) { - // Trying to load members from another (larger) room - const auto& testRoomAlias = QStringLiteral("#test:matrix.org"); - auto* r = connection()->roomByAlias(testRoomAlias, JoinState::Join); - if (!r) { - clog << testRoomAlias.toStdString() - << " is not found in the test user's rooms" << endl; - FAIL_TEST(); - } // It's not exactly correct because an arbitrary server might not support // lazy loading; but in the absence of capabilities framework we assume // it does. - if (r->memberNames().size() >= r->joinedCount()) { + if (targetRoom->users().size() >= targetRoom->joinedCount()) { clog << "Lazy loading doesn't seem to be enabled" << endl; FAIL_TEST(); } - r->setDisplayed(); - connect(r, &Room::allMembersLoaded, [this, thisTest, r] { - FINISH_TEST(r->memberNames().size() >= r->joinedCount()); + targetRoom->setDisplayed(); + connect(targetRoom, &Room::allMembersLoaded, this, [this, thisTest] { + FINISH_TEST(targetRoom->users().size() >= targetRoom->joinedCount()); }); return false; } @@ -727,20 +731,25 @@ TEST_IMPL(visitResources) "matrix:room/" + roomAlias.mid(1) + "/event/" + eventId.mid(1), "https://matrix.to/#/" + roomId + '/' + eventId }; - // The following URIs are not supposed to be actually joined (and even - // exist, as yet) - only to be syntactically correct + // Check that reserved characters are correctly processed. static const auto& joinRoomAlias = - QStringLiteral("unjoined:example.org"); // # will be added below + QStringLiteral("##/?.@\"unjoined:example.org"); + static const auto& encodedRoomAliasNoSigil = + QUrl::toPercentEncoding(joinRoomAlias.mid(1), ":"); static const QString joinQuery { "?action=join" }; + // These URIs are not supposed to be actually joined (and even exist, + // as yet) - only to be syntactically correct static const QStringList joinByAliasUris { - "matrix:room/" + joinRoomAlias + joinQuery, - "https://matrix.to/#/%23"/*`#`*/ + joinRoomAlias + joinQuery + Uri(joinRoomAlias.toUtf8(), {}, joinQuery.mid(1)).toDisplayString(), + "matrix:room/" + encodedRoomAliasNoSigil + joinQuery, + "https://matrix.to/#/%23"/*`#`*/ + encodedRoomAliasNoSigil + joinQuery, + "https://matrix.to/#/%23" + joinRoomAlias.mid(1) /* unencoded */ + joinQuery }; static const auto& joinRoomId = QStringLiteral("!anyid:example.org"); static const QStringList viaServers { "matrix.org", "example.org" }; static const auto viaQuery = std::accumulate(viaServers.cbegin(), viaServers.cend(), joinQuery, - [](QString q, const QString& s) { + [](const QString& q, const QString& s) { return q + "&via=" + s; }); static const QStringList joinByIdUris { @@ -755,7 +764,7 @@ TEST_IMPL(visitResources) || testResourceResolver(eventUris, &UriDispatcher::roomAction, room(), { eventId }) || testResourceResolver(joinByAliasUris, &UriDispatcher::joinAction, - connection(), { '#' + joinRoomAlias }) + connection(), { joinRoomAlias }) || testResourceResolver(joinByIdUris, &UriDispatcher::joinAction, connection(), { joinRoomId, viaServers })) return true; @@ -794,43 +803,47 @@ void TestManager::conclude() htmlReport += "<br><strong>Did not finish:</strong>" + dnfList; } - // TODO: Waiting for proper futures to come so that it could be: - // targetRoom->postHtmlText(...) - // .then(this, &TestManager::finalize); // Qt-style or - // .then([this] { finalize(); }); // STL-style auto txnId = room->postHtmlText(plainReport, htmlReport); // Now just wait until all the pending events reach the server - connectUntil(room, &Room::messageSent, this, [this, room, plainReport] { - const auto& pendingEvents = room->pendingEvents(); - if (auto c = std::count_if(pendingEvents.begin(), pendingEvents.end(), - [](const PendingEventItem& pe) { - return pe.deliveryStatus() - < EventStatus::ReachedServer; - }); - c > 0) { - clog << "Events to reach the server: " << c << ", not leaving yet" - << endl; - return false; - } + connectUntil(room, &Room::messageSent, this, + [this, txnId, room, plainReport] (const QString& sentTxnId) { + if (sentTxnId != txnId) + return false; + const auto& pendingEvents = room->pendingEvents(); + if (auto c = std::count_if(pendingEvents.cbegin(), + pendingEvents.cend(), + [](const PendingEventItem& pe) { + return pe.deliveryStatus() + < EventStatus::ReachedServer; + }); + c > 0) { + clog << "Events to reach the server: " << c + << ", not leaving yet" << endl; + return false; + } - clog << "Leaving the room" << endl; - auto* job = room->leaveRoom(); - connect(job, &BaseJob::finished, this, [this, job,plainReport] { - Q_ASSERT(job->status().good()); - finalize(); - // Still flying, as the exit() connection in finalize() is queued - clog << plainReport.toStdString() << endl; + clog << "Leaving the room" << endl; + // TODO: Waiting for proper futures to come so that it could be: +// room->leaveRoom() +// .then(this, &TestManager::finalize); // Qt-style or +// .then([this] { finalize(); }); // STL-style + auto* job = room->leaveRoom(); + connect(job, &BaseJob::result, this, [this, job,plainReport] { + Q_ASSERT(job->status().good()); + finalize(); + // Still flying, as the exit() connection in finalize() is queued + clog << plainReport.toStdString() << endl; + }); + return true; }); - return true; - }); } void TestManager::finalize() { clog << "Logging out" << endl; c->logout(); - connect(c, &Connection::loggedOut, - this, [this] { this->exit(failed.size() + running.size()); }, + connect(c, &Connection::loggedOut, this, + [this] { QCoreApplication::exit(failed.size() + running.size()); }, Qt::QueuedConnection); } @@ -842,6 +855,7 @@ int main(int argc, char* argv[]) << endl; return -1; } + // NOLINTNEXTLINE(readability-static-accessed-through-instance) return TestManager(argc, argv).exec(); } |