Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package libqxmpp for openSUSE:Factory checked in at 2026-03-06 18:20:35 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/libqxmpp (Old) and /work/SRC/openSUSE:Factory/.libqxmpp.new.561 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "libqxmpp" Fri Mar 6 18:20:35 2026 rev:45 rq:1337286 version:1.14.3 Changes: -------- --- /work/SRC/openSUSE:Factory/libqxmpp/libqxmpp.changes 2026-02-12 17:30:41.175735319 +0100 +++ /work/SRC/openSUSE:Factory/.libqxmpp.new.561/libqxmpp.changes 2026-03-06 18:21:29.999391527 +0100 @@ -1,0 +2,9 @@ +Fri Mar 6 08:37:57 UTC 2026 - Christophe Marin <[email protected]> + +- Update to 1.14.3 + * JMI: Fix JMI objects not being removed + * OmemoManager: Abort building session without public pre keys + * OutgoingIqManager: Fix potential double-finish of IQ promises + * JMI: Fix regressions introduced by auto-removal of closed JMIs + +------------------------------------------------------------------- Old: ---- qxmpp-1.14.1.tar.xz qxmpp-1.14.1.tar.xz.sig New: ---- _constraints qxmpp-1.14.3.tar.xz qxmpp-1.14.3.tar.xz.sig ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ libqxmpp.spec ++++++ --- /var/tmp/diff_new_pack.bDVK1Y/_old 2026-03-06 18:21:31.043435100 +0100 +++ /var/tmp/diff_new_pack.bDVK1Y/_new 2026-03-06 18:21:31.047435267 +0100 @@ -1,7 +1,7 @@ # # spec file for package libqxmpp # -# Copyright (c) 2025 SUSE LLC and contributors +# Copyright (c) 2026 SUSE LLC and contributors # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,7 +18,7 @@ %define sover 8 Name: libqxmpp -Version: 1.14.1 +Version: 1.14.3 Release: 0 Summary: Qt XMPP Library License: LGPL-2.1-or-later ++++++ _constraints ++++++ <?xml version="1.0" encoding="UTF-8"?> <constraints> <hardware> <disk> <size unit="G">8</size> </disk> </hardware> <overwrite> <conditions> <arch>ppc64le</arch> <arch>riscv64</arch> </conditions> <hardware> <memory> <size unit="G">6</size> </memory> </hardware> </overwrite> </constraints> ++++++ qxmpp-1.14.1.tar.xz -> qxmpp-1.14.3.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qxmpp-1.14.1/CHANGELOG.md new/qxmpp-1.14.3/CHANGELOG.md --- old/qxmpp-1.14.1/CHANGELOG.md 2026-02-10 13:49:31.000000000 +0100 +++ new/qxmpp-1.14.3/CHANGELOG.md 2026-02-26 04:52:39.000000000 +0100 @@ -4,6 +4,18 @@ SPDX-License-Identifier: CC0-1.0 --> +QXmpp 1.14.3 (February 26, 2026) +-------------------------------- + + - JMI: Fix regressions introduced by auto-removal of closed JMIs (@lnj, !747) + - OutgoingIqManager: Fix potential double-finish of IQ promises (@lnj, !748) + +QXmpp 1.14.2 (February 21, 2026) +-------------------------------- + + - OmemoManager: Abort building session without public pre keys (@melvo, !742) + - JMI: Fix JMI objects not being removed (@melvo, !737) + QXmpp 1.14.1 (February 10, 2026) -------------------------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qxmpp-1.14.1/CMakeLists.txt new/qxmpp-1.14.3/CMakeLists.txt --- old/qxmpp-1.14.1/CMakeLists.txt 2026-02-10 13:49:31.000000000 +0100 +++ new/qxmpp-1.14.3/CMakeLists.txt 2026-02-26 04:52:39.000000000 +0100 @@ -3,7 +3,7 @@ # SPDX-License-Identifier: CC0-1.0 cmake_minimum_required(VERSION 3.16) -project(qxmpp VERSION 1.14.1) +project(qxmpp VERSION 1.14.3) set(SO_VERSION 8) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qxmpp-1.14.1/doc/doap.xml new/qxmpp-1.14.3/doc/doap.xml --- old/qxmpp-1.14.1/doc/doap.xml 2026-02-10 13:49:31.000000000 +0100 +++ new/qxmpp-1.14.3/doc/doap.xml 2026-02-26 04:52:39.000000000 +0100 @@ -783,6 +783,20 @@ </implements> <release> <Version> + <revision>1.14.3</revision> + <created>2026-02-26</created> + <file-release rdf:resource='https://download.kde.org/unstable/qxmpp/qxmpp-1.14.3.tar.xz'/> + </Version> + </release> + <release> + <Version> + <revision>1.14.2</revision> + <created>2026-02-21</created> + <file-release rdf:resource='https://download.kde.org/unstable/qxmpp/qxmpp-1.14.2.tar.xz'/> + </Version> + </release> + <release> + <Version> <revision>1.14.1</revision> <created>2026-02-10</created> <file-release rdf:resource='https://download.kde.org/unstable/qxmpp/qxmpp-1.14.1.tar.xz'/> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qxmpp-1.14.1/src/client/QXmppJingleMessageInitiationManager.cpp new/qxmpp-1.14.3/src/client/QXmppJingleMessageInitiationManager.cpp --- old/qxmpp-1.14.1/src/client/QXmppJingleMessageInitiationManager.cpp 2026-02-10 13:49:31.000000000 +0100 +++ new/qxmpp-1.14.3/src/client/QXmppJingleMessageInitiationManager.cpp 2026-02-26 04:52:39.000000000 +0100 @@ -97,6 +97,8 @@ /// QXmppTask<SendResult> QXmppJingleMessageInitiation::reject(std::optional<QXmppJingleReason> reason, bool containsTieBreak) { + QXmppPromise<SendResult> promise; + JmiElement jmiElement; jmiElement.setType(JmiType::Reject); @@ -109,7 +111,20 @@ jmiElement.setReason(reason); jmiElement.setContainsTieBreak(containsTieBreak); - return d->request(std::move(jmiElement)); + d->request(std::move(jmiElement)).then(this, [this, promise, containsTieBreak](SendResult &&result) mutable { + // Tie-break rejections don't close the local session; only emit closed() for real rejections. + if (!containsTieBreak) { + if (hasError(result)) { + Q_EMIT closed(getError(result)); + } else { + Q_EMIT closed(Rejected {}); + } + } + + promise.finish(std::move(result)); + }); + + return promise.task(); } /// @@ -121,6 +136,8 @@ /// QXmppTask<SendResult> QXmppJingleMessageInitiation::retract(std::optional<QXmppJingleReason> reason, bool containsTieBreak) { + QXmppPromise<SendResult> promise; + JmiElement jmiElement; jmiElement.setType(JmiType::Retract); @@ -133,7 +150,20 @@ jmiElement.setReason(reason); jmiElement.setContainsTieBreak(containsTieBreak); - return d->request(std::move(jmiElement)); + d->request(std::move(jmiElement)).then(this, [this, promise, containsTieBreak](SendResult &&result) mutable { + // Tie-break retractions don't close the local session; only emit closed() for real retractions. + if (!containsTieBreak) { + if (hasError(result)) { + Q_EMIT closed(getError(result)); + } else { + Q_EMIT closed(Retracted {}); + } + } + + promise.finish(std::move(result)); + }); + + return promise.task(); } /// @@ -145,6 +175,8 @@ /// QXmppTask<SendResult> QXmppJingleMessageInitiation::finish(std::optional<QXmppJingleReason> reason, const QString &migratedTo) { + QXmppPromise<SendResult> promise; + d->finished = true; JmiElement jmiElement; @@ -159,7 +191,17 @@ jmiElement.setReason(reason); jmiElement.setMigratedTo(migratedTo); - return d->request(std::move(jmiElement)); + d->request(std::move(jmiElement)).then(this, [this, promise](SendResult &&result) mutable { + if (hasError(result)) { + Q_EMIT closed(getError(result)); + } else { + Q_EMIT closed(Finished {}); + } + + promise.finish(std::move(result)); + }); + + return promise.task(); } /// @@ -437,7 +479,6 @@ return true; case JmiType::Finish: if (!existingJmi->isFinished()) { - existingJmi->finish(jmiElement.reason(), jmiElement.migratedTo()); Q_EMIT existingJmi->closed( Jmi::Finished { jmiElement.reason(), jmiElement.migratedTo() }); } @@ -551,18 +592,13 @@ if (QUuid::fromString(existingJmi->id()) < QUuid::fromString(jmiElementId)) { // Jingle message initiator with lower ID rejects the other proposal. + // The local session is not closed; the JMI remains active. existingJmi->setId(jmiElementId); - existingJmi->reject(std::move(reason), true).then(this, [existingJmi](auto result) { - if (hasError(result)) { - Q_EMIT existingJmi->closed(getError(std::move(result))); - } - }); + existingJmi->reject(std::move(reason), true).then(this, [](auto) { }); } else { // Jingle message initiator with higher ID retracts its proposal. existingJmi->retract(std::move(reason), true).then(this, [this, existingJmi, jmiElementId, remoteResource](auto result) { - if (hasError(result)) { - Q_EMIT existingJmi->closed(getError(std::move(result))); - } else { + if (!hasError(result)) { // Afterwards, JMI ID is changed to lower ID. existingJmi->setId(jmiElementId); @@ -590,6 +626,23 @@ std::shared_ptr<QXmppJingleMessageInitiation> QXmppJingleMessageInitiationManager::addJmi(const QString &id, const QString &remoteJid) { auto jmi = std::shared_ptr<QXmppJingleMessageInitiation>(new QXmppJingleMessageInitiation(this, id, remoteJid)); + + connect(jmi.get(), &QXmppJingleMessageInitiation::closed, this, [this, jmi](const QXmppJingleMessageInitiation::Result &result) { + // Don't remove the JMI on tie-break rejection/retraction since the local session persists. + if (const auto *rejected = std::get_if<QXmppJingleMessageInitiation::Rejected>(&result)) { + if (rejected->containsTieBreak) { + return; + } + } + if (const auto *retracted = std::get_if<QXmppJingleMessageInitiation::Retracted>(&result)) { + if (retracted->containsTieBreak) { + return; + } + } + debug(u"JMI with ID '%1' for remote JID '%2' is closed and thus being removed"_s.arg(jmi->id(), jmi->remoteJid())); + clear(jmi); + }); + d->jmis.append(jmi); return jmi; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qxmpp-1.14.1/src/client/QXmppOutgoingClient.cpp new/qxmpp-1.14.3/src/client/QXmppOutgoingClient.cpp --- old/qxmpp-1.14.1/src/client/QXmppOutgoingClient.cpp 2026-02-10 13:49:31.000000000 +0100 +++ new/qxmpp-1.14.3/src/client/QXmppOutgoingClient.cpp 2026-02-26 04:52:39.000000000 +0100 @@ -1219,19 +1219,21 @@ void OutgoingIqManager::finish(const QString &id, IqResult &&result) { if (auto itr = m_requests.find(id); itr != m_requests.end()) { - itr->second.interface.finish(std::move(result)); + auto promise = std::move(itr->second.interface); m_requests.erase(itr); + promise.finish(std::move(result)); } } void OutgoingIqManager::cancelAll() { - for (auto &[id, state] : m_requests) { + auto requests = std::move(m_requests); + m_requests = {}; + for (auto &[id, state] : requests) { state.interface.finish(QXmppError { u"IQ has been cancelled."_s, QXmpp::SendError::Disconnected }); } - m_requests.clear(); } void OutgoingIqManager::onSessionOpened(const SessionBegin &session) @@ -1268,20 +1270,22 @@ return false; } - auto &promise = itr->second.interface; - const auto &expectedFrom = itr->second.jid; - // Check that the sender of the response matches the recipient of the request. // Stanzas coming from the server on behalf of the user's account must have no "from" // attribute or have it set to the user's bare JID. // If 'from' is empty, the IQ has been sent by the server. In this case we don't need to // do the check as we trust the server anyways. - if (auto from = stanza.attribute(u"from"_s); !from.isEmpty() && from != expectedFrom) { + if (auto from = stanza.attribute(u"from"_s); !from.isEmpty() && from != itr->second.jid) { warning(u"Ignored received IQ response to request '%1' because of wrong sender '%2' instead of expected sender '%3'"_s - .arg(id, from, expectedFrom)); + .arg(id, from, itr->second.jid)); return false; } + // Extract the promise and erase from the map before calling finish() to prevent + // re-entrant double-finish if a continuation triggers cancelAll(). + auto promise = std::move(itr->second.interface); + m_requests.erase(itr); + // report IQ errors as QXmppError (this makes it impossible to parse the full error IQ, // but that is okay for now) if (iqType == u"error") { @@ -1300,7 +1304,6 @@ promise.finish(stanza); } - m_requests.erase(itr); return true; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qxmpp-1.14.1/src/omemo/QXmppOmemoManager_p.cpp new/qxmpp-1.14.3/src/omemo/QXmppOmemoManager_p.cpp --- old/qxmpp-1.14.1/src/omemo/QXmppOmemoManager_p.cpp 2026-02-10 13:49:31.000000000 +0100 +++ new/qxmpp-1.14.3/src/omemo/QXmppOmemoManager_p.cpp 2026-02-26 04:52:39.000000000 +0100 @@ -3319,12 +3319,11 @@ // bool ManagerPrivate::buildSession(signal_protocol_address address, const QXmppOmemoDeviceBundle &deviceBundle) { - QXmppPromise<bool> interface; - // Choose a pre key randomly. const auto publicPreKeys = deviceBundle.publicPreKeys(); if (publicPreKeys.isEmpty()) { warning(u"No public pre key could be found in device bundle"_s); + return false; } const auto publicPreKeyIds = publicPreKeys.keys(); const auto publicPreKeyIndex = QRandomGenerator::system()->bounded(publicPreKeyIds.size()); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qxmpp-1.14.1/tests/qxmppcallmanager/tst_qxmppcallmanager.cpp new/qxmpp-1.14.3/tests/qxmppcallmanager/tst_qxmppcallmanager.cpp --- old/qxmpp-1.14.1/tests/qxmppcallmanager/tst_qxmppcallmanager.cpp 2026-02-10 13:49:31.000000000 +0100 +++ new/qxmpp-1.14.3/tests/qxmppcallmanager/tst_qxmppcallmanager.cpp 2026-02-26 04:52:39.000000000 +0100 @@ -80,7 +80,7 @@ QCoreApplication::processEvents(); client.expect(u"<iq id='ph37a419' to='[email protected]/orchard' type='result'/>"_s); client.expect(u"<iq id=\"qx3\" to=\"capulet.lit\" type=\"get\"><services xmlns=\"urn:xmpp:extdisco:2\"/></iq>"_s); - client.inject(u"<iq id='qx3' from='capulet.lit' type='result'><services xmlns='urn:xmpp:extdisco:2'/></iq>"); + client.inject(u"<iq id='qx3' from='capulet.lit' type='result'><services xmlns='urn:xmpp:extdisco:2'/></iq>"_s); QCoreApplication::processEvents(); client.expect(u"<iq id=\"qx2\" to=\"[email protected]/orchard\" from=\"[email protected]/balcony\" type=\"set\"><jingle xmlns=\"urn:xmpp:jingle:1\" action=\"session-info\" sid=\"abc1\"><ringing xmlns=\"urn:xmpp:jingle:apps:rtp:info:1\"/></jingle></iq>"_s);
