diff options
-rw-r--r-- | .github/workflows/ci.yml | 159 | ||||
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | CONTRIBUTING.md | 9 | ||||
-rw-r--r-- | README.md | 16 | ||||
-rw-r--r-- | lib/accountregistry.h | 25 | ||||
-rw-r--r-- | lib/avatar.cpp | 8 | ||||
-rw-r--r-- | lib/connection.cpp | 78 | ||||
-rw-r--r-- | lib/connection.h | 5 | ||||
-rw-r--r-- | lib/room.cpp | 4 | ||||
-rw-r--r-- | libquotient.pri | 3 |
10 files changed, 145 insertions, 164 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 172c027f..f03af94b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,47 +14,65 @@ concurrency: ci-${{ github.ref }} jobs: CI: runs-on: ${{ matrix.os }} - continue-on-error: false + continue-on-error: ${{ matrix.qt-version != '5.15.2' }} # Qt 6 will fail for now strategy: fail-fast: false max-parallel: 1 matrix: os: [ ubuntu-20.04, macos-10.15 ] - compiler: [ Clang ] # GCC builds are added individually below - qt-version: [ '5.12.12' ] + qt-version: [ '6.3.1', '5.15.2' ] + compiler: [ LLVM ] # Not using binary values here, to make the job captions more readable e2ee: [ '', e2ee ] update-api: [ '', update-api ] - sonar: [ '' ] + static-analysis: [ '' ] platform: [ '' ] qt-arch: [ '' ] exclude: - - os: windows-2019 - e2ee: e2ee # Not supported by the current CI script + - qt-version: '6.3.1' + update-api: update-api # Generated code is not specific to Qt version + - os: ubuntu-20.04 + e2ee: e2ee # Will be re-added with static analysis below + # TODO: Enable E2EE on Windows and macOS - os: macos-10.15 - e2ee: e2ee # Missing OpenSSL + e2ee: e2ee include: + - os: windows-2019 + qt-version: '5.15.2' + compiler: MSVC + platform: x64 + qt-arch: win64_msvc2019_64 + - os: ubuntu-20.04 + qt-version: '5.15.2' + compiler: LLVM + e2ee: e2ee + static-analysis: codeql - os: ubuntu-latest + qt-version: '5.15.2' compiler: GCC - qt-version: '5.12.12' e2ee: e2ee - sonar: sonar + static-analysis: sonar - os: ubuntu-20.04 + qt-version: '5.15.2' compiler: GCC - qt-version: '5.12.12' e2ee: e2ee update-api: update-api + - os: ubuntu-20.04 + qt-version: '5.15.2' + compiler: LLVM + update-api: update-api - os: windows-2019 + qt-version: '6.3.1' compiler: MSVC + # e2ee: e2ee # TODO platform: x64 - qt-version: '5.12.12' - qt-arch: win64_msvc2017_64 + qt-arch: win64_msvc2019_64 - os: windows-2019 + qt-version: '5.15.2' compiler: MSVC - platform: x64 - qt-version: '5.12.12' - qt-arch: win64_msvc2017_64 update-api: update-api + platform: x64 + qt-arch: win64_msvc2019_64 env: SONAR_SERVER_URL: 'https://sonarcloud.io' @@ -64,44 +82,14 @@ jobs: with: fetch-depth: 0 - - name: Cache Qt - id: cache-qt - uses: actions/cache@v2 - with: - path: ${{ runner.workspace }}/Qt - key: ${{ runner.os }}${{ matrix.platform }}-Qt${{ matrix.qt-version }}-cache - - - name: Install Qt - uses: jurplel/install-qt-action@v2.11.1 - with: - version: ${{ matrix.qt-version }} - arch: ${{ matrix.qt-arch }} - cached: ${{ steps.cache-qt.outputs.cache-hit }} - - - name: Install Ninja (macOS/Windows) - if: ${{ !startsWith(matrix.os, 'ubuntu') }} - uses: seanmiddleditch/gha-setup-ninja@v3 - - - name: Install Ninja and Valgrind (Linux) - if: startsWith(matrix.os, 'ubuntu') - run: | - sudo apt-get -qq install ninja-build valgrind - echo "VALGRIND=valgrind --tool=memcheck --leak-check=yes --gen-suppressions=all --suppressions=$GITHUB_WORKSPACE/quotest/.valgrind.supp" >>$GITHUB_ENV - - name: Setup build environment run: | - if [ "${{ matrix.compiler }}" == "GCC" ]; then - CXX_VERSION_POSTFIX='-10' - echo "CC=gcc$CXX_VERSION_POSTFIX" >>$GITHUB_ENV - echo "CXX=g++$CXX_VERSION_POSTFIX" >>$GITHUB_ENV - elif [[ '${{ matrix.compiler }}' == 'Clang' ]]; then - if [[ '${{ runner.os }}' == 'Linux' ]]; then - CXX_VERSION_POSTFIX='-11' - # Do CodeQL analysis on one of Linux branches - echo "CODEQL_ANALYSIS=true" >>$GITHUB_ENV - fi - echo "CC=clang$CXX_VERSION_POSTFIX" >>$GITHUB_ENV - echo "CXX=clang++$CXX_VERSION_POSTFIX" >>$GITHUB_ENV + if [ '${{ matrix.compiler }}' == 'GCC' ]; then + echo "CC=gcc-10" >>$GITHUB_ENV + echo "CXX=g++-10" >>$GITHUB_ENV + elif [[ '${{ runner.os }}' != 'Windows' ]]; then + echo "CC=clang" >>$GITHUB_ENV + echo "CXX=clang++" >>$GITHUB_ENV fi if grep -q 'refs/tags' <<<'${{ github.ref }}'; then VERSION="$(git describe --tags)" @@ -110,20 +98,19 @@ jobs: else VERSION="$(git describe --all --contains)-ci${{ github.run_number }}-$(git rev-parse --short HEAD)" fi - echo "QUOTEST_ORIGIN=$VERSION @ ${{ runner.os }}/${{ matrix.compiler }}" >>$GITHUB_ENV - # Build libQuotient as a shared library across platforms but also - # check the static configuration somewhere + echo "QUOTEST_ORIGIN=$VERSION @ ${{ runner.os }}/Qt-${{ matrix.qt-version }}/${{ matrix.compiler }}" >>$GITHUB_ENV + CMAKE_ARGS="-G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DBUILD_SHARED_LIBS=${{ runner.os == 'Linux' }} \ -DCMAKE_INSTALL_PREFIX=~/.local \ -DCMAKE_PREFIX_PATH=~/.local \ - -DCMAKE_INSTALL_RPATH_USE_LINK_PATH=ON" + -DCMAKE_INSTALL_RPATH_USE_LINK_PATH=ON \ + -DBUILD_WITH_QT6=${{ startsWith(matrix.qt-version, '6') }}" - if [ -n "${{ matrix.sonar }}" ]; then + if [ '${{ matrix.static-analysis }}' == 'sonar' ]; then mkdir -p $HOME/.sonar CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_CXX_FLAGS=--coverage" - echo "COV=gcov$CXX_VERSION_POSTFIX" >>$GITHUB_ENV fi echo "CMAKE_ARGS=$CMAKE_ARGS" >>$GITHUB_ENV @@ -137,14 +124,42 @@ jobs: cmake -E make_directory ${{ runner.workspace }}/build echo "BUILD_PATH=${{ runner.workspace }}/build/libQuotient" >>$GITHUB_ENV - - name: Setup MSVC environment + - name: Cache Qt + id: cache-qt + uses: actions/cache@v2 + with: + path: ${{ runner.workspace }}/Qt + key: ${{ runner.os }}${{ matrix.platform }}-Qt${{ matrix.qt-version }}-cache + + - name: Install Qt + uses: jurplel/install-qt-action@v2.14.0 + with: + version: ${{ matrix.qt-version }} + arch: ${{ matrix.qt-arch }} + cached: ${{ steps.cache-qt.outputs.cache-hit }} + + - name: Install Ninja (macOS/Windows) + if: ${{ !startsWith(matrix.os, 'ubuntu') }} + uses: seanmiddleditch/gha-setup-ninja@v3 + + - name: Install dependencies (Linux) + if: startsWith(matrix.os, 'ubuntu') + run: | + if [ -n "${{ matrix.e2ee }}" ]; then + EXTRA_DEPS="libssl-dev libolm-dev" + echo "QUOTEST_ORIGIN=$QUOTEST_ORIGIN with E2EE" >>$GITHUB_ENV + fi + sudo apt-get -qq install ninja-build valgrind $EXTRA_DEPS + echo "VALGRIND=valgrind --tool=memcheck --leak-check=yes --gen-suppressions=all --suppressions=$GITHUB_WORKSPACE/quotest/.valgrind.supp" >>$GITHUB_ENV + + - name: Setup MSVC uses: ilammy/msvc-dev-cmd@v1 if: matrix.compiler == 'MSVC' with: arch: ${{ matrix.platform }} - name: Download and set up Sonar Cloud tools - if: matrix.sonar != '' + if: matrix.static-analysis == 'sonar' env: SONAR_SCANNER_VERSION: 4.6.2.2472 run: | @@ -157,20 +172,6 @@ jobs: unzip -o sonar-scanner-cli*.zip popd - - name: Install OpenSSL - if: ${{ contains(matrix.os, 'ubuntu') && matrix.e2ee }} - run: | - sudo apt-get install libssl-dev - - - name: Build and install olm - if: matrix.e2ee - working-directory: ${{ runner.workspace }} - run: | - git clone https://gitlab.matrix.org/matrix-org/olm.git - cmake -S olm -B build/olm $CMAKE_ARGS - cmake --build build/olm --target install - echo "QUOTEST_ORIGIN=$QUOTEST_ORIGIN with E2EE" >>$GITHUB_ENV - - name: Build and install QtKeychain run: | cd .. @@ -191,8 +192,8 @@ jobs: echo "QUOTEST_ORIGIN=$QUOTEST_ORIGIN with API files regeneration" >>$GITHUB_ENV - name: Initialize CodeQL tools - if: env.CODEQL_ANALYSIS - uses: github/codeql-action/init@v1 + if: matrix.static-analysis == 'codeql' + uses: github/codeql-action/init@v2 with: languages: cpp # If you wish to specify custom queries, you can do so here or in a config file. @@ -234,18 +235,18 @@ jobs: timeout-minutes: 4 # quotest is supposed to finish within 3 minutes, actually - name: Perform CodeQL analysis - if: env.CODEQL_ANALYSIS - uses: github/codeql-action/analyze@v1 + if: matrix.static-analysis == 'codeql' + uses: github/codeql-action/analyze@v2 - name: Run sonar-scanner - if: matrix.sonar != '' + if: matrix.static-analysis == 'sonar' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} run: | mkdir .coverage && pushd .coverage find $BUILD_PATH -name '*.gcda' -print0 \ - | xargs -0 $COV -s $GITHUB_WORKSPACE -pr + | xargs -0 gcov -s $GITHUB_WORKSPACE -pr # Coverage of the test source code is not tracked, as it is always 100% # (if not, some tests failed and broke the build at an earlier stage) rm -f quotest* autotests* diff --git a/CMakeLists.txt b/CMakeLists.txt index efdd5bb6..048d3b07 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -77,7 +77,7 @@ option(BUILD_WITH_QT6 "Build Quotient with Qt 6 (EXPERIMENTAL)" OFF) if (BUILD_WITH_QT6) set(QtMinVersion "6.0") else() - set(QtMinVersion "5.12") + set(QtMinVersion "5.15") set(QtExtraModules "Multimedia") # See #483 endif() string(REGEX REPLACE "^(.).*" "Qt\\1" Qt ${QtMinVersion}) # makes "Qt5" or "Qt6" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bc65abf3..7a5ee079 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -154,14 +154,7 @@ just don't bankrupt us with it. Refactoring is welcome. ### Code style and formatting -As of Quotient 0.7, the C++ standard for newly written code is C++20 with a few -restrictions, notably: -* enumerators and slots cannot have `[[attributes]]` because moc from Qt 5.12 - chokes on them - this will be lifted when we move on to Qt 5.13 for the oldest - supported version, in the meantime use `Q_DECL_DEPRECATED` and similar Qt - macros - they expand to nothing when the code is passed to moc. -* explicit lists in lambda captures are preferred over `[=]`; note that C++20 - deprecates implicit `this` capture in `[=]`. +As of Quotient 0.7, the C++ standard for newly written code is C++20. The code style is defined by `.clang-format`, and in general, all C++ files should follow it. Files with minor deviations from the defined style are still @@ -26,19 +26,17 @@ If you find what looks like a security issue, please use instructions in SECURITY.md. ## Getting and using libQuotient -Depending on your platform, the library can come as a separate package. -Recent releases of Debian and openSUSE, e.g., already have the package -(under the old name). If your Linux repo doesn't provide binary package -(either libqmatrixclient - older - or libquotient - newer), or you're -on Windows or macOS, your best bet is to build the library from the source -and bundle it with your application. +Depending on your platform, the library can be obtained from a package +management system. Recent releases of Debian and openSUSE, e.g., already have +it. Alternatively, just build the library from the source and bundle it with +your application, as described below. ### Pre-requisites - A recent Linux, macOS or Windows system (desktop versions are known to work; mobile operating systems where Qt is available might work too) - - Recent enough Linux examples: Debian Bullseye; Fedora 33; openSUSE Leap 15.3; - Ubuntu Focal Fossa. -- Qt 5 (either Open Source or Commercial), 5.12 or higher + - Recent enough Linux examples: Debian Bullseye; Fedora 35; + openSUSE Leap 15.4; Ubuntu 22.04 LTS. +- Qt 5 (either Open Source or Commercial), 5.15 or higher - CMake 3.16 or newer (from your package management system or [the official website](https://cmake.org/download/)) - A C++ toolchain with that supports at least some subset of C++20: diff --git a/lib/accountregistry.h b/lib/accountregistry.h index 38cfe6c6..9560688e 100644 --- a/lib/accountregistry.h +++ b/lib/accountregistry.h @@ -31,8 +31,9 @@ class QUOTIENT_API AccountRegistry : public QAbstractListModel, /// Can be used to inform the user or to show a login screen if size() == 0 and no accounts are loaded Q_PROPERTY(QStringList accountsLoading READ accountsLoading NOTIFY accountsLoadingChanged) public: - using const_iterator = QVector::const_iterator; - using const_reference = QVector::const_reference; + using vector_t = QVector<Connection*>; + using const_iterator = vector_t::const_iterator; + using const_reference = vector_t::const_reference; enum EventRoles { AccountRole = Qt::UserRole + 1, @@ -42,24 +43,24 @@ public: [[deprecated("Use Accounts variable instead")]] // static AccountRegistry& instance(); - // Expose most of QVector's const-API but only provide add() and drop() + // Expose most of vector_t's const-API but only provide add() and drop() // for changing it. In theory other changing operations could be supported // too; but then boilerplate begin/end*() calls has to be tucked into each // and this class gives no guarantees on the order of entries, so why care. - const QVector<Connection*>& accounts() const { return *this; } + const vector_t& accounts() const { return *this; } void add(Connection* a); void drop(Connection* a); - const_iterator begin() const { return QVector::begin(); } - const_iterator end() const { return QVector::end(); } - const_reference front() const { return QVector::front(); } - const_reference back() const { return QVector::back(); } + const_iterator begin() const { return vector_t::begin(); } + const_iterator end() const { return vector_t::end(); } + const_reference front() const { return vector_t::front(); } + const_reference back() const { return vector_t::back(); } bool isLoggedIn(const QString& userId) const; Connection* get(const QString& userId); - using QVector::isEmpty, QVector::empty; - using QVector::size, QVector::count, QVector::capacity; - using QVector::cbegin, QVector::cend, QVector::contains; + using vector_t::isEmpty, vector_t::empty; + using vector_t::size, vector_t::count, vector_t::capacity; + using vector_t::cbegin, vector_t::cend, vector_t::contains; // QAbstractItemModel interface implementation @@ -88,4 +89,4 @@ private: inline QUOTIENT_API AccountRegistry Accounts {}; inline AccountRegistry& AccountRegistry::instance() { return Accounts; } -} +} // namespace Quotient diff --git a/lib/avatar.cpp b/lib/avatar.cpp index 9304a3de..13de99bf 100644 --- a/lib/avatar.cpp +++ b/lib/avatar.cpp @@ -39,7 +39,7 @@ public: // The below are related to image caching, hence mutable mutable QImage _originalImage; - mutable std::vector<QPair<QSize, QImage>> _scaledImages; + mutable std::vector<std::pair<QSize, QImage>> _scaledImages; mutable QSize _requestedSize; mutable enum { Unknown, Cache, Network, Banned } _imageSource = Unknown; mutable QPointer<MediaThumbnailJob> _thumbnailRequest = nullptr; @@ -124,9 +124,9 @@ QImage Avatar::Private::get(Connection* connection, QSize size, }); } - for (const auto& p : _scaledImages) - if (p.first == size) - return p.second; + for (const auto& [scaledSize, scaledImage] : _scaledImages) + if (scaledSize == size) + return scaledImage; auto result = _originalImage.isNull() ? QImage() : _originalImage.scaled(size, Qt::KeepAspectRatio, diff --git a/lib/connection.cpp b/lib/connection.cpp index 101bef89..c390cc05 100644 --- a/lib/connection.cpp +++ b/lib/connection.cpp @@ -92,7 +92,7 @@ public: // state is Invited. The spec mandates to keep Invited room state // separately; specifically, we should keep objects for Invite and // Leave state of the same room if the two happen to co-exist. - QHash<QPair<QString, bool>, Room*> roomMap; + QHash<std::pair<QString, bool>, Room*> roomMap; /// Mapping from serverparts to alias/room id mappings, /// as of the last sync QHash<QString, QString> roomAliasMap; @@ -381,10 +381,9 @@ public: const QString& device) const; QString edKeyForUserDevice(const QString& userId, const QString& device) const; - std::unique_ptr<EncryptedEvent> makeEventForSessionKey( - const QString& roomId, const QString& targetUserId, - const QString& targetDeviceId, const QByteArray& sessionId, - const QByteArray& sessionKey) const; + QJsonObject encryptSessionKeyEvent(QJsonObject payloadJson, + const QString& targetUserId, + const QString& targetDeviceId) const; #endif void saveAccessTokenToKeychain() const @@ -1365,17 +1364,10 @@ ForgetRoomJob* Connection::forgetRoom(const QString& id) } SendToDeviceJob* Connection::sendToDevices( - const QString& eventType, const UsersToDevicesToEvents& eventsMap) + const QString& eventType, const UsersToDevicesToContent& contents) { - QHash<QString, QHash<QString, QJsonObject>> json; - json.reserve(int(eventsMap.size())); - for (const auto& [userId, devicesToEvents] : eventsMap) { - auto& jsonUser = json[userId]; - for (const auto& [deviceId, event] : devicesToEvents) - jsonUser.insert(deviceId, event->contentJson()); - } return callApi<SendToDeviceJob>(BackgroundRequest, eventType, - generateTxnId(), json); + generateTxnId(), contents); } SendMessageJob* Connection::sendMessage(const QString& roomId, @@ -1715,7 +1707,7 @@ Room* Connection::provideRoom(const QString& id, Omittable<JoinState> joinState) Q_ASSERT_X(!id.isEmpty(), __FUNCTION__, "Empty room id"); // If joinState is empty, all joinState == comparisons below are false. - const auto roomKey = qMakePair(id, joinState == JoinState::Invite); + const std::pair roomKey { id, joinState == JoinState::Invite }; auto* room = d->roomMap.value(roomKey, nullptr); if (room) { // Leave is a special case because in transition (5a) (see the .h file) @@ -2354,30 +2346,15 @@ bool Connection::Private::createOlmSession(const QString& targetUserId, return true; } -std::unique_ptr<EncryptedEvent> Connection::Private::makeEventForSessionKey( - const QString& roomId, const QString& targetUserId, - const QString& targetDeviceId, const QByteArray& sessionId, - const QByteArray& sessionKey) const +QJsonObject Connection::Private::encryptSessionKeyEvent( + QJsonObject payloadJson, const QString& targetUserId, + const QString& targetDeviceId) const { - // Noisy but nice for debugging - // qDebug(E2EE) << "Creating the payload for" << data->userId() << device << - // sessionId << sessionKey.toHex(); - const auto event = makeEvent<RoomKeyEvent>("m.megolm.v1.aes-sha2", roomId, - sessionId, sessionKey, - data->userId()); - auto payloadJson = event->fullJson(); payloadJson.insert("recipient"_ls, targetUserId); - payloadJson.insert(SenderKeyL, data->userId()); payloadJson.insert("recipient_keys"_ls, QJsonObject { { Ed25519Key, edKeyForUserDevice(targetUserId, targetDeviceId) } }); - payloadJson.insert("keys"_ls, - QJsonObject { - { Ed25519Key, - QString(olmAccount->identityKeys().ed25519) } }); - payloadJson.insert("sender_device"_ls, data->deviceId()); - const auto [type, cipherText] = olmEncryptMessage( targetUserId, targetDeviceId, QJsonDocument(payloadJson).toJson(QJsonDocument::Compact)); @@ -2387,8 +2364,8 @@ std::unique_ptr<EncryptedEvent> Connection::Private::makeEventForSessionKey( { "body"_ls, QString(cipherText) } } } }; - return makeEvent<EncryptedEvent>(encrypted, - olmAccount->identityKeys().curve25519); + return EncryptedEvent(encrypted, olmAccount->identityKeys().curve25519) + .contentJson(); } void Connection::sendSessionKeyToDevices( @@ -2409,11 +2386,21 @@ void Connection::sendSessionKeyToDevices( if (hash.isEmpty()) return; + auto keyEventJson = RoomKeyEvent(MegolmV1AesSha2AlgoKey, roomId, sessionId, + sessionKey, userId()) + .fullJson(); + keyEventJson.insert(SenderKeyL, userId()); + keyEventJson.insert("sender_device"_ls, deviceId()); + keyEventJson.insert( + "keys"_ls, + QJsonObject { + { Ed25519Key, QString(olmAccount()->identityKeys().ed25519) } }); + auto job = callApi<ClaimKeysJob>(hash); - connect(job, &BaseJob::success, this, [job, this, roomId, sessionId, sessionKey, devices, index] { - UsersToDevicesToEvents usersToDevicesToEvents; - const auto oneTimeKeys = job->oneTimeKeys(); - for (const auto& [targetUserId, targetDeviceId] : + connect(job, &BaseJob::success, this, [job, this, roomId, sessionId, keyEventJson, devices, index] { + QHash<QString, QHash<QString, QJsonObject>> usersToDevicesToContent; + for (const auto oneTimeKeys = job->oneTimeKeys(); + const auto& [targetUserId, targetDeviceId] : asKeyValueRange(devices)) { if (!hasOlmSession(targetUserId, targetDeviceId) && !d->createOlmSession( @@ -2421,12 +2408,15 @@ void Connection::sendSessionKeyToDevices( oneTimeKeys[targetUserId][targetDeviceId])) continue; - usersToDevicesToEvents[targetUserId][targetDeviceId] = - d->makeEventForSessionKey(roomId, targetUserId, targetDeviceId, - sessionId, sessionKey); + // Noisy but nice for debugging +// qDebug(E2EE) << "Creating the payload for" << targetUserId +// << targetDeviceId << sessionId << sessionKey.toHex(); + usersToDevicesToContent[targetUserId][targetDeviceId] = + d->encryptSessionKeyEvent(keyEventJson, targetUserId, + targetDeviceId); } - if (!usersToDevicesToEvents.empty()) { - sendToDevices(EncryptedEvent::TypeId, usersToDevicesToEvents); + if (!usersToDevicesToContent.empty()) { + sendToDevices(EncryptedEvent::TypeId, usersToDevicesToContent); QVector<std::tuple<QString, QString, QString>> receivedDevices; receivedDevices.reserve(devices.size()); for (const auto& [user, device] : asKeyValueRange(devices)) diff --git a/lib/connection.h b/lib/connection.h index 5b806350..b8246ecb 100644 --- a/lib/connection.h +++ b/lib/connection.h @@ -133,8 +133,7 @@ class QUOTIENT_API Connection : public QObject { Q_PROPERTY(bool canChangePassword READ canChangePassword NOTIFY capabilitiesLoaded) public: - using UsersToDevicesToEvents = - UnorderedMap<QString, UnorderedMap<QString, EventPtr>>; + using UsersToDevicesToContent = QHash<QString, QHash<QString, QJsonObject>>; enum RoomVisibility { PublishRoom, @@ -689,7 +688,7 @@ public Q_SLOTS: ForgetRoomJob* forgetRoom(const QString& id); SendToDeviceJob* sendToDevices(const QString& eventType, - const UsersToDevicesToEvents& eventsMap); + const UsersToDevicesToContent& contents); /** \deprecated This method is experimental and may be removed any time */ SendMessageJob* sendMessage(const QString& roomId, const RoomEvent& event); diff --git a/lib/room.cpp b/lib/room.cpp index 284d19df..f692c354 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -118,7 +118,7 @@ public: // A map from evtId to a map of relation type to a vector of event // pointers. Not using QMultiHash, because we want to quickly return // a number of relations for a given event without enumerating them. - QHash<QPair<QString, QString>, RelatedEvents> relations; + QHash<std::pair<QString, QString>, RelatedEvents> relations; QString displayname; Avatar avatar; QHash<QString, Notification> notifications; @@ -2687,7 +2687,7 @@ bool Room::Private::processRedaction(const RedactionEvent& redaction) } if (const auto* reaction = eventCast<ReactionEvent>(oldEvent)) { const auto& targetEvtId = reaction->relation().eventId; - const QPair lookupKey { targetEvtId, EventRelation::AnnotationType }; + const std::pair lookupKey { targetEvtId, EventRelation::AnnotationType }; if (relations.contains(lookupKey)) { relations[lookupKey].removeOne(reaction); emit q->updatedEvent(targetEvtId); diff --git a/libquotient.pri b/libquotient.pri index 677f60d3..1b4bd9c0 100644 --- a/libquotient.pri +++ b/libquotient.pri @@ -1,8 +1,7 @@ QT += network multimedia QT -= gui -# TODO: Having moved to Qt 5.12, replace c++1z with c++17 below -CONFIG *= c++1z warn_on rtti_off create_prl object_parallel_to_source +CONFIG *= c++20 warn_on rtti_off create_prl object_parallel_to_source win32-msvc* { # Quotient code base does not play well with NMake inference rules |