aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMelvin Keskin <melvo@olomono.de>2022-09-25 14:12:51 +0200
committerGitHub <noreply@github.com>2022-09-25 14:12:51 +0200
commit524a02debffd9552f0928b5804d7b51b045aa9d2 (patch)
treea8832b961839c27511193ec58e608ea552ff5362
parent48bc0775e68cb6d7647287e90c3e69fde387003a (diff)
downloadqxmpp-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.xml9
-rw-r--r--src/base/QXmppConstants.cpp2
-rw-r--r--src/base/QXmppConstants_p.h2
-rw-r--r--src/base/QXmppJingleIq.cpp43
-rw-r--r--src/base/QXmppJingleIq.h4
-rw-r--r--src/base/QXmppPresence.cpp83
-rw-r--r--src/base/QXmppPresence.h9
-rw-r--r--tests/qxmppjingleiq/tst_qxmppjingleiq.cpp3
-rw-r--r--tests/qxmpppresence/tst_qxmpppresence.cpp41
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(