diff options
| author | Melvin Keskin <melvo@olomono.de> | 2022-09-25 14:12:51 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-09-25 14:12:51 +0200 |
| commit | 524a02debffd9552f0928b5804d7b51b045aa9d2 (patch) | |
| tree | a8832b961839c27511193ec58e608ea552ff5362 | |
| parent | 48bc0775e68cb6d7647287e90c3e69fde387003a (diff) | |
| download | qxmpp-524a02debffd9552f0928b5804d7b51b045aa9d2.tar.gz | |
Implement XEP-0272: Multiparty Jingle (Muji) stanza extensions (#457)
Adds the presence extension and the extension of the Jingle IQ.
https://xmpp.org/extensions/xep-0272.html
| -rw-r--r-- | doc/doap.xml | 9 | ||||
| -rw-r--r-- | src/base/QXmppConstants.cpp | 2 | ||||
| -rw-r--r-- | src/base/QXmppConstants_p.h | 2 | ||||
| -rw-r--r-- | src/base/QXmppJingleIq.cpp | 43 | ||||
| -rw-r--r-- | src/base/QXmppJingleIq.h | 4 | ||||
| -rw-r--r-- | src/base/QXmppPresence.cpp | 83 | ||||
| -rw-r--r-- | src/base/QXmppPresence.h | 9 | ||||
| -rw-r--r-- | tests/qxmppjingleiq/tst_qxmppjingleiq.cpp | 3 | ||||
| -rw-r--r-- | tests/qxmpppresence/tst_qxmpppresence.cpp | 41 |
9 files changed, 196 insertions, 0 deletions
diff --git a/doc/doap.xml b/doc/doap.xml index bbad8a58..4733e86a 100644 --- a/doc/doap.xml +++ b/doc/doap.xml @@ -392,6 +392,15 @@ SPDX-License-Identifier: CC0-1.0 </implements> <implements> <xmpp:SupportedXep> + <xmpp:xep rdf:resource='https://xmpp.org/extensions/xep-0272.html'/> + <xmpp:status>complete</xmpp:status> + <xmpp:version>0.2</xmpp:version> + <xmpp:since>1.5</xmpp:since> + <xmpp:note>Based on https://github.com/xsf/xeps/pull/1139</xmpp:note> + </xmpp:SupportedXep> + </implements> + <implements> + <xmpp:SupportedXep> <xmpp:xep rdf:resource='https://xmpp.org/extensions/xep-0280.html'/> <xmpp:status>complete</xmpp:status> <xmpp:version>0.10</xmpp:version> diff --git a/src/base/QXmppConstants.cpp b/src/base/QXmppConstants.cpp index 196ee89b..bdf0a9e3 100644 --- a/src/base/QXmppConstants.cpp +++ b/src/base/QXmppConstants.cpp @@ -129,6 +129,8 @@ const char *ns_bob = "urn:xmpp:bob"; const char *ns_conference = "jabber:x:conference"; // XEP-0264: Jingle Content Thumbnails const char *ns_thumbs = "urn:xmpp:thumbs:1"; +// XEP-0272: Multiparty Jingle (Muji) +const char *ns_muji = "urn:xmpp:jingle:muji:0"; // XEP-0280: Message Carbons const char *ns_carbons = "urn:xmpp:carbons:2"; // XEP-0297: Stanza Forwarding diff --git a/src/base/QXmppConstants_p.h b/src/base/QXmppConstants_p.h index 83521c5a..5a1e57e7 100644 --- a/src/base/QXmppConstants_p.h +++ b/src/base/QXmppConstants_p.h @@ -141,6 +141,8 @@ extern const char *ns_bob; extern const char *ns_conference; // XEP-0264: Jingle Content Thumbnails extern const char *ns_thumbs; +// XEP-0272: Multiparty Jingle (Muji) +extern const char *ns_muji; // XEP-0280: Message Carbons extern const char *ns_carbons; // XEP-0297: Stanza Forwarding diff --git a/src/base/QXmppJingleIq.cpp b/src/base/QXmppJingleIq.cpp index 1c244d7b..9d883860 100644 --- a/src/base/QXmppJingleIq.cpp +++ b/src/base/QXmppJingleIq.cpp @@ -1,4 +1,5 @@ // SPDX-FileCopyrightText: 2010 Jeremy Lainé <jeremy.laine@m4x.org> +// SPDX-FileCopyrightText: 2022 Melvin Keskin <melvo@olomono.de> // // SPDX-License-Identifier: LGPL-2.1-or-later @@ -718,6 +719,8 @@ public: QString responder; QString sid; + QString mujiGroupChatJid; + QList<QXmppJingleIq::Content> contents; QXmppJingleIq::Reason reason; bool ringing; @@ -871,6 +874,30 @@ void QXmppJingleIq::setSid(const QString &sid) d->sid = sid; } +/// +/// Returns the JID of the \xep{0272, Multiparty Jingle (Muji)} group chat. +/// +/// \return the Muji group chat JID +/// +/// \since QXmpp 1.5 +/// +QString QXmppJingleIq::mujiGroupChatJid() const +{ + return d->mujiGroupChatJid; +} + +/// +/// Sets the JID of the \xep{0272, Multiparty Jingle (Muji)} group chat. +/// +/// \param mujiGroupChatJid Muji group chat JID +/// +/// \since QXmpp 1.5 +/// +void QXmppJingleIq::setMujiGroupChatJid(const QString &mujiGroupChatJid) +{ + d->mujiGroupChatJid = mujiGroupChatJid; +} + /// \cond bool QXmppJingleIq::isJingleIq(const QDomElement &element) { @@ -892,6 +919,12 @@ void QXmppJingleIq::parseElementFromChild(const QDomElement &element) d->responder = jingleElement.attribute(QStringLiteral("responder")); d->sid = jingleElement.attribute(QStringLiteral("sid")); + // XEP-0272: Multiparty Jingle (Muji) + if (const auto mujiGroupChatElement = jingleElement.firstChildElement(QStringLiteral("muji")); + mujiGroupChatElement.namespaceURI() == ns_muji) { + d->mujiGroupChatJid = mujiGroupChatElement.attribute(QStringLiteral("room")); + } + // content d->contents.clear(); QDomElement contentElement = jingleElement.firstChildElement(QStringLiteral("content")); @@ -917,9 +950,19 @@ void QXmppJingleIq::toXmlElementFromChild(QXmlStreamWriter *writer) const helperToXmlAddAttribute(writer, QStringLiteral("initiator"), d->initiator); helperToXmlAddAttribute(writer, QStringLiteral("responder"), d->responder); helperToXmlAddAttribute(writer, QStringLiteral("sid"), d->sid); + + // XEP-0272: Multiparty Jingle (Muji) + if (!d->mujiGroupChatJid.isEmpty()) { + writer->writeStartElement(QStringLiteral("muji")); + writer->writeDefaultNamespace(ns_muji); + helperToXmlAddAttribute(writer, QStringLiteral("room"), d->mujiGroupChatJid); + writer->writeEndElement(); + } + for (const auto &content : d->contents) { content.toXml(writer); } + d->reason.toXml(writer); // ringing diff --git a/src/base/QXmppJingleIq.h b/src/base/QXmppJingleIq.h index 8ea6deeb..be915787 100644 --- a/src/base/QXmppJingleIq.h +++ b/src/base/QXmppJingleIq.h @@ -1,4 +1,5 @@ // SPDX-FileCopyrightText: 2010 Jeremy Lainé <jeremy.laine@m4x.org> +// SPDX-FileCopyrightText: 2022 Melvin Keskin <melvo@olomono.de> // // SPDX-License-Identifier: LGPL-2.1-or-later @@ -303,6 +304,9 @@ public: QString sid() const; void setSid(const QString &sid); + QString mujiGroupChatJid() const; + void setMujiGroupChatJid(const QString &mujiGroupChatJid); + /// \cond static bool isJingleIq(const QDomElement &element); /// \endcond diff --git a/src/base/QXmppPresence.cpp b/src/base/QXmppPresence.cpp index 54e44fb4..059bd642 100644 --- a/src/base/QXmppPresence.cpp +++ b/src/base/QXmppPresence.cpp @@ -1,10 +1,12 @@ // SPDX-FileCopyrightText: 2009 Manjeet Dahiya <manjeetdahiya@gmail.com> +// SPDX-FileCopyrightText: 2022 Melvin Keskin <melvo@olomono.de> // // SPDX-License-Identifier: LGPL-2.1-or-later #include "QXmppPresence.h" #include "QXmppConstants_p.h" +#include "QXmppJingleIq.h" #include "QXmppUtils.h" #include <QDateTime> @@ -59,6 +61,10 @@ public: QByteArray photoHash; QXmppPresence::VCardUpdateType vCardUpdateType; + // XEP-0272: Multiparty Jingle (Muji) + bool isPreparingMujiSession = false; + QVector<QXmppJingleIq::Content> mujiContents; + // XEP-0319: Last User Interaction in Presence QDateTime lastUserInteraction; @@ -253,6 +259,54 @@ QStringList QXmppPresence::capabilityExt() const return d->capabilityExt; } +/// +/// Returns whether a \xep{0272, Multiparty Jingle (Muji)} session is being prepared. +/// +/// \return whether a Muji session is being prepared +/// +/// \since QXmpp 1.5 +/// +bool QXmppPresence::isPreparingMujiSession() const +{ + return d->isPreparingMujiSession; +} + +/// +/// Sets whether a \xep{0272, Multiparty Jingle (Muji)} session is being prepared. +/// +/// \param isPreparingMujiSession whether a Muji session is being prepared +/// +/// \since QXmpp 1.5 +/// +void QXmppPresence::setIsPreparingMujiSession(bool isPreparingMujiSession) +{ + d->isPreparingMujiSession = isPreparingMujiSession; +} + +/// +/// Returns \xep{0272, Multiparty Jingle (Muji)} contents. +/// +/// \return Muji contents +/// +/// \since QXmpp 1.5 +/// +QVector<QXmppJingleIq::Content> QXmppPresence::mujiContents() const +{ + return d->mujiContents; +} + +/// +/// Sets \xep{0272, Multiparty Jingle (Muji)} contents. +/// +/// \param mujiContents Muji contents +/// +/// \since QXmpp 1.5 +/// +void QXmppPresence::setMujiContents(const QVector<QXmppJingleIq::Content> &mujiContents) +{ + d->mujiContents = mujiContents; +} + /// Returns the MUC item. QXmppMucItem QXmppPresence::mucItem() const @@ -447,6 +501,19 @@ void QXmppPresence::parseExtension(const QDomElement &element, QXmppElementList d->vCardUpdateType = VCardUpdateValidPhoto; } } + // XEP-0272: Multiparty Jingle (Muji) + } else if (element.tagName() == QStringLiteral("muji") && element.namespaceURI() == ns_muji) { + if (!element.firstChildElement(QStringLiteral("preparing")).isNull()) { + d->isPreparingMujiSession = true; + } + + for (auto contentElement = element.firstChildElement(QStringLiteral("content")); + !contentElement.isNull(); + contentElement = contentElement.nextSiblingElement(QStringLiteral("content"))) { + QXmppJingleIq::Content content; + content.parse(contentElement); + d->mujiContents.append(content); + } // XEP-0319: Last User Interaction in Presence } else if (element.tagName() == QStringLiteral("idle") && element.namespaceURI() == ns_idle) { if (element.hasAttribute(QStringLiteral("since"))) { @@ -537,6 +604,22 @@ void QXmppPresence::toXml(QXmlStreamWriter *xmlWriter) const xmlWriter->writeEndElement(); } + // XEP-0272: Multiparty Jingle (Muji) + if (d->isPreparingMujiSession || !d->mujiContents.isEmpty()) { + xmlWriter->writeStartElement(QStringLiteral("muji")); + xmlWriter->writeDefaultNamespace(ns_muji); + + if (d->isPreparingMujiSession) { + xmlWriter->writeEmptyElement(QStringLiteral("preparing")); + } + + for (const auto &mujiContent : d->mujiContents) { + mujiContent.toXml(xmlWriter); + } + + xmlWriter->writeEndElement(); + } + // XEP-0319: Last User Interaction in Presence if (!d->lastUserInteraction.isNull() && d->lastUserInteraction.isValid()) { xmlWriter->writeStartElement(QStringLiteral("idle")); diff --git a/src/base/QXmppPresence.h b/src/base/QXmppPresence.h index f704ddc9..0086c26a 100644 --- a/src/base/QXmppPresence.h +++ b/src/base/QXmppPresence.h @@ -1,10 +1,12 @@ // SPDX-FileCopyrightText: 2009 Manjeet Dahiya <manjeetdahiya@gmail.com> +// SPDX-FileCopyrightText: 2022 Melvin Keskin <melvo@olomono.de> // // SPDX-License-Identifier: LGPL-2.1-or-later #ifndef QXMPPPRESENCE_H #define QXMPPPRESENCE_H +#include "QXmppJingleIq.h" #include "QXmppMucIq.h" #include "QXmppStanza.h" @@ -106,6 +108,13 @@ public: QStringList capabilityExt() const; + // XEP-0272: Multiparty Jingle (Muji) + bool isPreparingMujiSession() const; + void setIsPreparingMujiSession(bool isPreparingMujiSession); + + QVector<QXmppJingleIq::Content> mujiContents() const; + void setMujiContents(const QVector<QXmppJingleIq::Content> &mujiContents); + // XEP-0319: Last User Interaction in Presence QDateTime lastUserInteraction() const; void setLastUserInteraction(const QDateTime &); diff --git a/tests/qxmppjingleiq/tst_qxmppjingleiq.cpp b/tests/qxmppjingleiq/tst_qxmppjingleiq.cpp index 2a4caf22..2a1b20f3 100644 --- a/tests/qxmppjingleiq/tst_qxmppjingleiq.cpp +++ b/tests/qxmppjingleiq/tst_qxmppjingleiq.cpp @@ -1,4 +1,5 @@ // SPDX-FileCopyrightText: 2012 Jeremy Lainé <jeremy.laine@m4x.org> +// SPDX-FileCopyrightText: 2022 Melvin Keskin <melvo@olomono.de> // // SPDX-License-Identifier: LGPL-2.1-or-later @@ -362,6 +363,7 @@ void tst_QXmppJingleIq::testSession() " action=\"session-initiate\"" " initiator=\"romeo@montague.lit/orchard\"" " sid=\"a73sjjvkla37jfea\">" + "<muji xmlns=\"urn:xmpp:jingle:muji:0\" room=\"darkcave@chat.shakespeare.lit\"/>" "<content creator=\"initiator\" name=\"this-is-a-stub\">" "<description xmlns=\"urn:xmpp:jingle:apps:stub:0\"/>" "<transport xmlns=\"urn:xmpp:jingle:transports:stub:0\"/>" @@ -374,6 +376,7 @@ void tst_QXmppJingleIq::testSession() QCOMPARE(session.action(), QXmppJingleIq::SessionInitiate); QCOMPARE(session.initiator(), QLatin1String("romeo@montague.lit/orchard")); QCOMPARE(session.sid(), QLatin1String("a73sjjvkla37jfea")); + QCOMPARE(session.mujiGroupChatJid(), QStringLiteral("darkcave@chat.shakespeare.lit")); QCOMPARE(session.contents().size(), 1); QCOMPARE(session.contents()[0].creator(), QLatin1String("initiator")); QCOMPARE(session.contents()[0].name(), QLatin1String("this-is-a-stub")); diff --git a/tests/qxmpppresence/tst_qxmpppresence.cpp b/tests/qxmpppresence/tst_qxmpppresence.cpp index 7ba5d90c..95d7ee92 100644 --- a/tests/qxmpppresence/tst_qxmpppresence.cpp +++ b/tests/qxmpppresence/tst_qxmpppresence.cpp @@ -1,5 +1,6 @@ // SPDX-FileCopyrightText: 2012 Oliver Goffart <ogoffart@woboq.com> // SPDX-FileCopyrightText: 2012 Jeremy Lainé <jeremy.laine@m4x.org> +// SPDX-FileCopyrightText: 2022 Melvin Keskin <melvo@olomono.de> // // SPDX-License-Identifier: LGPL-2.1-or-later @@ -21,6 +22,7 @@ private slots: void testPresenceWithMucItem(); void testPresenceWithMucPassword(); void testPresenceWithMucSupport(); + void testPresenceWithMuji(); void testPresenceWithLastUserInteraction(); void testPresenceWithMix(); void testPresenceWithVCard(); @@ -250,6 +252,45 @@ void tst_QXmppPresence::testPresenceWithMucSupport() serializePacket(presence, xml); } +void tst_QXmppPresence::testPresenceWithMuji() +{ + const QByteArray xml( + "<presence>" + "<muji xmlns=\"urn:xmpp:jingle:muji:0\">" + "<preparing/>" + "<content creator=\"initiator\" name=\"video\"/>" + "<content creator=\"initiator\" name=\"voice\"/>" + "</muji>" + "</presence>"); + + QXmppPresence presence1; + QVERIFY(!presence1.isPreparingMujiSession()); + QVERIFY(presence1.mujiContents().isEmpty()); + parsePacket(presence1, xml); + + QVERIFY(presence1.isPreparingMujiSession()); + QCOMPARE(presence1.mujiContents().size(), 2); + QCOMPARE(presence1.mujiContents().at(0).name(), QStringLiteral("video")); + QCOMPARE(presence1.mujiContents().at(1).name(), QStringLiteral("voice")); + serializePacket(presence1, xml); + + QXmppPresence presence2; + presence2.setIsPreparingMujiSession(true); + QXmppJingleIq::Content mujiContent1; + mujiContent1.setCreator(QStringLiteral("initiator")); + mujiContent1.setName(QStringLiteral("video")); + QXmppJingleIq::Content mujiContent2; + mujiContent2.setCreator(QStringLiteral("initiator")); + mujiContent2.setName(QStringLiteral("voice")); + presence2.setMujiContents({ mujiContent1, mujiContent2 }); + + QVERIFY(presence2.isPreparingMujiSession()); + QCOMPARE(presence2.mujiContents().size(), 2); + QCOMPARE(presence2.mujiContents().at(0).name(), QStringLiteral("video")); + QCOMPARE(presence2.mujiContents().at(1).name(), QStringLiteral("voice")); + serializePacket(presence2, xml); +} + void tst_QXmppPresence::testPresenceWithLastUserInteraction() { const QByteArray xml( |
