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 class for providing the new body/subject
text references.

https://xmpp.org/extensions/xep-0428.html
  • Loading branch information
lnjX committed Mar 20, 2024
1 parent 247c51f commit 2da1df5
Show file tree
Hide file tree
Showing 6 changed files with 270 additions and 18 deletions.
2 changes: 1 addition & 1 deletion doc/doap.xml
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
57 changes: 57 additions & 0 deletions src/base/QXmppFallback.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// 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 QXMPP_EXPORT QXmppFallback
{
public:
enum Element {
Body,
Subject,
};

struct Range {
/// Start index of the range
uint32_t start;
/// End index of the range
uint32_t end;
};

struct Reference {
/// Element of the message stanza this refers to
Element element;
/// Optional character range in the text
std::optional<Range> range;
};

QXmppFallback(const QString &forNamespace, const QVector<Reference> &references);
QXMPP_PRIVATE_DECLARE_RULE_OF_SIX(QXmppFallback)

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

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

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

private:
QSharedDataPointer<QXmppFallbackPrivate> d;
};

#endif // QXMPPFALLBACK_H
174 changes: 160 additions & 14 deletions src/base/QXmppMessage.cpp
Original file line number Diff line number Diff line change
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,127 @@ void QXmppMessage::serializeExtensions(QXmlStreamWriter *writer, QXmpp::SceMode
}
}
}

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

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

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

///
/// \struct QXmppFallback::Range
///
/// A character range of a string, see \xep{0426, Character counting in message bodies} for details.
///

///
/// \struct QXmppFallback::Reference
///
/// A reference to a text in the message stanza.
///

QXMPP_PRIVATE_DEFINE_RULE_OF_SIX(QXmppFallback)

/// Creates a fallback marker.
QXmppFallback::QXmppFallback(const QString &forNamespace, const QVector<Reference> &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<QXmppFallback::Reference> &QXmppFallback::references() const
{
return d->references;
}

///
/// Sets the text references of this fallback marker.
///
void QXmppFallback::setReferences(const QVector<Reference> &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)
{
if (el.tagName() != u"fallback" || el.namespaceURI() != ns_fallback_indication) {
return {};
}

QVector<Reference> 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(Reference { Body, range });
} else if (subEl.tagName() == u"subject") {
references.push_back(Reference { Subject, range });
}
}

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

///
/// Serializes the object to XML.
///
void QXmppFallback::toXml(QXmlStreamWriter *writer) const
{
writer->writeStartElement(QSL65("fallback"));
writer->writeDefaultNamespace(toString65(ns_fallback_indication));
writeOptionalXmlAttribute(writer, u"for", d->forNamespace);
for (const auto &reference : d->references) {
writer->writeStartElement(reference.element == Body ? QSL65("body") : QSL65("subject"));
if (reference.range) {
writer->writeAttribute(QSL65("start"), serializeInt(reference.range->start));
writer->writeAttribute(QSL65("end"), serializeInt(reference.range->end));
}
writer->writeEndElement();
}
writer->writeEndElement();
}
9 changes: 7 additions & 2 deletions src/base/QXmppMessage.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

class QXmppMessagePrivate;
class QXmppBitsOfBinaryDataList;
class QXmppFallback;
class QXmppJingleMessageInitiationElement;
class QXmppMessageReaction;
class QXmppMixInvitation;
Expand Down Expand Up @@ -254,8 +255,12 @@ class QXMPP_EXPORT QXmppMessage : public QXmppStanza
void setMixInvitation(const std::optional<QXmppMixInvitation> &mixInvitation);

// XEP-0428: Fallback Indication
bool isFallback() const;
void setIsFallback(bool isFallback);
#if QXMPP_DEPRECATED_SINCE(1, 7)
[[deprecated("Use fallbackMarkers()")]] bool isFallback() const;
[[deprecated("Use setFallbackMarkers()")]] void setIsFallback(bool isFallback);
#endif
const QVector<QXmppFallback> &fallbackMarkers() const;
void setFallbackMarkers(const QVector<QXmppFallback> &);

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

0 comments on commit 2da1df5

Please sign in to comment.