Skip to content

Commit

Permalink
Update XEP-0428: Fallback Indication to v0.2
Browse files Browse the repository at this point in the history
Introduces new QXmppFallback and QXmppFallbackReference classes for
providing the new information.

https://xmpp.org/extensions/xep-0428.html
  • Loading branch information
lnjX committed Mar 20, 2024
1 parent 4001e4f commit f439cd2
Show file tree
Hide file tree
Showing 6 changed files with 317 additions and 16 deletions.
2 changes: 1 addition & 1 deletion doc/doap.xml
Expand Up @@ -608,7 +608,7 @@ SPDX-License-Identifier: CC0-1.0
<xmpp:SupportedXep>
<xmpp:xep rdf:resource='https://xmpp.org/extensions/xep-0428.html'/>
<xmpp:status>complete</xmpp:status>
<xmpp:version>0.1</xmpp:version>
<xmpp:version>0.2.0</xmpp:version>
<xmpp:since>1.3</xmpp:since>
</xmpp:SupportedXep>
</implements>
Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Expand Up @@ -30,6 +30,7 @@ set(INSTALL_HEADER_FILES
base/QXmppExtension.h
base/QXmppExternalService.h
base/QXmppExternalServiceDiscoveryIq.h
base/QXmppFallback.h
base/QXmppFileMetadata.h
base/QXmppFileShare.h
base/QXmppFutureUtils_p.h
Expand Down
65 changes: 65 additions & 0 deletions src/base/QXmppFallback.h
@@ -0,0 +1,65 @@
// SPDX-FileCopyrightText: 2024 Linus Jahn <lnj@kaidan.im>
//
// SPDX-License-Identifier: LGPL-2.1-or-later

#ifndef QXMPPFALLBACK_H
#define QXMPPFALLBACK_H

#include "QXmppGlobal.h"

#include <optional>

#include <QSharedDataPointer>

class QDomElement;
class QXmlStreamWriter;

struct QXmppFallbackPrivate;

class QXmppFallbackReference
{
public:
enum Element {
Body,
Subject,
};

struct Range {
uint32_t start;
uint32_t end;
};

QXmppFallbackReference(Element element, std::optional<Range> range = {});
QXMPP_PRIVATE_DECLARE_RULE_OF_SIX(QXmppFallbackReference)

Element element() const;
void setElement(Element);

std::optional<Range> range() const;
void setRange(std::optional<Range>);

private:
Element m_element;
std::optional<Range> m_range;
};

class QXmppFallback
{
public:
QXmppFallback(const QString &forNamespace, const QVector<QXmppFallbackReference> &references);
QXMPP_PRIVATE_DECLARE_RULE_OF_SIX(QXmppFallback)

const QString &forNamespace() const;
void setForNamespace(const QString &);

const QVector<QXmppFallbackReference> &references() const;
void setReferences(const QVector<QXmppFallbackReference> &);

static std::optional<QXmppFallback> fromDom(const QDomElement &);
void toXml(QXmlStreamWriter *) const;

private:
QSharedDataPointer<QXmppFallbackPrivate> d;
};

#endif // QXMPPFALLBACK_H
218 changes: 204 additions & 14 deletions src/base/QXmppMessage.cpp
Expand Up @@ -10,6 +10,7 @@

#include "QXmppBitsOfBinaryDataList.h"
#include "QXmppConstants_p.h"
#include "QXmppFallback.h"
#include "QXmppFileShare.h"
#include "QXmppGlobal_p.h"
#include "QXmppJingleData.h"
Expand Down Expand Up @@ -158,7 +159,7 @@ class QXmppMessagePrivate : public QSharedData
std::optional<QXmppMixInvitation> mixInvitation;

// XEP-0428: Fallback Indication
bool isFallback;
QVector<QXmppFallback> fallbackMarkers;

// XEP-0434: Trust Messages (TM)
std::optional<QXmppTrustMessageElement> trustMessageElement;
Expand All @@ -184,8 +185,7 @@ QXmppMessagePrivate::QXmppMessagePrivate()
markable(false),
marker(QXmppMessage::NoMarker),
hints(0),
isSpoiler(false),
isFallback(false)
isSpoiler(false)
{
}

Expand Down Expand Up @@ -1211,31 +1211,53 @@ void QXmppMessage::setMixInvitation(const std::optional<QXmppMixInvitation> &mix
}

///
/// Sets whether this message is only a fallback according to \xep{0428}:
/// Fallback Indication.
/// Sets whether this message is only a fallback according to \xep{0428, Fallback Indication}.
///
/// This is useful for clients not supporting end-to-end encryption to indicate
/// that the message body does not contain the intended text of the author.
///
/// \deprecated Use fallbackMarkers() instead, it provides full access to the fallback elements.
///
/// \since QXmpp 1.3
///
bool QXmppMessage::isFallback() const
{
return d->isFallback;
return !d->fallbackMarkers.empty();
}

///
/// Sets whether this message is only a fallback according to \xep{0428}:
/// Fallback Indication.
/// Sets whether this message is only a fallback according to \xep{0428, Fallback Indication}.
///
/// This is useful for clients not supporting end-to-end encryption to indicate
/// that the message body does not contain the intended text of the author.
///
/// \deprecated Use setFallbackMarkers() instead, it provides full access to the fallback elements.
///
/// \since QXmpp 1.3
///
void QXmppMessage::setIsFallback(bool isFallback)
{
d->isFallback = isFallback;
d->fallbackMarkers = { QXmppFallback { {}, {} } };
}

///
/// Returns the fallback elements defined in \xep{0428, Fallback Indication}.
///
/// \since QXmpp 1.7
///
const QVector<QXmppFallback> &QXmppMessage::fallbackMarkers() const
{
return d->fallbackMarkers;
}

///
/// Sets the fallback elements defined in \xep{0428, Fallback Indication}.
///
/// \since QXmpp 1.7
///
void QXmppMessage::setFallbackMarkers(const QVector<QXmppFallback> &fallbackMarkers)
{
d->fallbackMarkers = fallbackMarkers;
}

///
Expand Down Expand Up @@ -1464,7 +1486,9 @@ bool QXmppMessage::parseExtension(const QDomElement &element, QXmpp::SceMode sce
#endif
// XEP-0428: Fallback Indication
if (checkElement(element, u"fallback", ns_fallback_indication)) {
d->isFallback = true;
if (auto fallback = QXmppFallback::fromDom(element)) {
d->fallbackMarkers.push_back(std::move(*fallback));
}
return true;
}
// XEP-0482: Call Invites
Expand Down Expand Up @@ -1716,10 +1740,8 @@ void QXmppMessage::serializeExtensions(QXmlStreamWriter *writer, QXmpp::SceMode
#endif

// XEP-0428: Fallback Indication
if (d->isFallback) {
writer->writeStartElement(QSL65("fallback"));
writer->writeDefaultNamespace(toString65(ns_fallback_indication));
writer->writeEndElement();
for (const auto &fallback : d->fallbackMarkers) {
fallback.toXml(writer);
}
}

Expand Down Expand Up @@ -1903,3 +1925,171 @@ void QXmppMessage::serializeExtensions(QXmlStreamWriter *writer, QXmpp::SceMode
}
}
}

///
/// \class QXmppFallbackReference
///
/// Reference to a text element a message stanza as defined in \xep{0428, Fallback Indication}.
/// It may contain a specific range in the text.
///
/// \sa QXmppFallback
/// \since QXmpp 1.7
///

///
/// \enum QXmppFallbackReference::Element
///
/// Describes the element of the message stanza this refers to.
///

/// Creates a fallback reference.
QXmppFallbackReference::QXmppFallbackReference(Element element, std::optional<Range> range)
: m_element(element),
m_range(range)
{
}

QXMPP_PRIVATE_DEFINE_RULE_OF_SIX(QXmppFallbackReference)

///
/// Returns the element type.
///
QXmppFallbackReference::Element QXmppFallbackReference::element() const
{
return m_element;
}

///
/// Sets the element type.
///
void QXmppFallbackReference::setElement(Element element)
{
m_element = element;
}

///
/// Returns the range in the text to be reference.
///
std::optional<QXmppFallbackReference::Range> QXmppFallbackReference::range() const
{
return m_range;
}

///
/// Sets the range in the text to be reference.
///
void QXmppFallbackReference::setRange(std::optional<Range> range)
{
m_range = range;
}

struct QXmppFallbackPrivate : QSharedData {
QString forNamespace;
QVector<QXmppFallbackReference> references;
};

///
/// \class QXmppFallback
///
/// Fallback marker for message stanzas as defined in \xep{0428, Fallback Indication}.
///
/// \sa QXmppFallback
/// \since QXmpp 1.7
///

QXMPP_PRIVATE_DEFINE_RULE_OF_SIX(QXmppFallback)

/// Creates a fallback marker.
QXmppFallback::QXmppFallback(const QString &forNamespace, const QVector<QXmppFallbackReference> &references)
: d(new QXmppFallbackPrivate { {}, forNamespace, references })
{
}

///
/// Returns the namespace of the XEP that this fallback marker is referring to.
///
const QString &QXmppFallback::forNamespace() const
{
return d->forNamespace;
}

///
/// Sets the namespace of the XEP that this fallback marker is referring to.
///
void QXmppFallback::setForNamespace(const QString &ns)
{
d->forNamespace = ns;
}

///
/// Returns the text references of this fallback marker.
///
const QVector<QXmppFallbackReference> &QXmppFallback::references() const
{
return d->references;
}

///
/// Sets the text references of this fallback marker.
///
void QXmppFallback::setReferences(const QVector<QXmppFallbackReference> &references)
{
d->references = references;
}

///
/// Tries to parse \a el into a QXmppFallback object.
///
/// \return Empty optional on failure, parsed object otherwise.
///
std::optional<QXmppFallback> QXmppFallback::fromDom(const QDomElement &el)
{
using Reference = QXmppFallbackReference;
using Range = QXmppFallbackReference::Range;

if (el.tagName() != u"fallback" || el.namespaceURI() != ns_fallback_indication) {
return {};
}

QVector<QXmppFallbackReference> references;
for (const auto &subEl : iterChildElements(el, {}, ns_fallback_indication)) {
auto start = parseInt<uint32_t>(subEl.attribute(QStringLiteral("start")));
auto end = parseInt<uint32_t>(subEl.attribute(QStringLiteral("end")));
std::optional<Range> range;
if (start && end) {
range = Range { *start, *end };
}

if (subEl.tagName() == u"body") {
references.push_back(QXmppFallbackReference { Reference::Body, range });
} else if (subEl.tagName() == u"subject") {
references.push_back(QXmppFallbackReference { Reference::Subject, range });
}
}

return QXmppFallback {
el.attribute(QStringLiteral("for")),
references,
};
}

///
/// Serializes the object to XML.
///
void QXmppFallback::toXml(QXmlStreamWriter *writer) const
{
using Reference = QXmppFallbackReference;

writer->writeStartElement(QSL65("fallback"));
writer->writeDefaultNamespace(toString65(ns_fallback_indication));
writeOptionalXmlAttribute(writer, u"for", d->forNamespace);
for (const auto &r : d->references) {
writer->writeStartElement(r.element() == Reference::Body ? QSL65("body") : QSL65("subject"));
if (auto range = r.range()) {
writer->writeAttribute(QSL65("start"), QString::number(range->start));
writer->writeAttribute(QSL65("end"), QString::number(range->end));
}
writer->writeEndElement();
}
writer->writeEndElement();
}
3 changes: 3 additions & 0 deletions src/base/QXmppMessage.h
Expand Up @@ -19,6 +19,7 @@

class QXmppMessagePrivate;
class QXmppBitsOfBinaryDataList;
class QXmppFallback;
class QXmppJingleMessageInitiationElement;
class QXmppMessageReaction;
class QXmppMixInvitation;
Expand Down Expand Up @@ -256,6 +257,8 @@ class QXMPP_EXPORT QXmppMessage : public QXmppStanza
// XEP-0428: Fallback Indication
bool isFallback() const;
void setIsFallback(bool isFallback);
const QVector<QXmppFallback> &fallbackMarkers() const;
void setFallbackMarkers(const QVector<QXmppFallback> &);

// XEP-0434: Trust Messages (TM)
std::optional<QXmppTrustMessageElement> trustMessageElement() const;
Expand Down

0 comments on commit f439cd2

Please sign in to comment.