aboutsummaryrefslogtreecommitdiff
path: root/src/base/QXmppPresence.cpp
diff options
context:
space:
mode:
authorLinus Jahn <lnj@kaidan.im>2019-10-21 22:43:11 +0200
committerLNJ <lnj@kaidan.im>2019-12-10 22:41:05 +0100
commit4d61ddd55f5a1a9b51a154c8493e61237827c212 (patch)
tree931ae50141675dd1835bfba617de569d5f9d6e6e /src/base/QXmppPresence.cpp
parentd40b65c144a8f7042299bdcc387494ae01a60a46 (diff)
downloadqxmpp-4d61ddd55f5a1a9b51a154c8493e61237827c212.tar.gz
Refactor QXmppPresence, Add missing tests
Diffstat (limited to 'src/base/QXmppPresence.cpp')
-rw-r--r--src/base/QXmppPresence.cpp476
1 files changed, 227 insertions, 249 deletions
diff --git a/src/base/QXmppPresence.cpp b/src/base/QXmppPresence.cpp
index b18079bb..856bcea0 100644
--- a/src/base/QXmppPresence.cpp
+++ b/src/base/QXmppPresence.cpp
@@ -23,47 +23,48 @@
#include "QXmppPresence.h"
-#include "QXmppUtils.h"
-#include <QtDebug>
+
#include <QDateTime>
#include <QDomElement>
-#include <QXmlStreamWriter>
+
#include "QXmppConstants_p.h"
+#include "QXmppUtils.h"
-static const char* presence_types[] = {
- "error",
- "",
- "unavailable",
- "subscribe",
- "subscribed",
- "unsubscribe",
- "unsubscribed",
- "probe"
+static const QStringList PRESENCE_TYPES = {
+ QStringLiteral("error"),
+ QString(),
+ QStringLiteral("unavailable"),
+ QStringLiteral("subscribe"),
+ QStringLiteral("subscribed"),
+ QStringLiteral("unsubscribe"),
+ QStringLiteral("unsubscribed"),
+ QStringLiteral("probe")
};
-static const char* presence_shows[] = {
- "",
- "away",
- "xa",
- "dnd",
- "chat",
- "invisible"
+static const QStringList AVAILABLE_STATUS_TYPES = {
+ QString(),
+ QStringLiteral("away"),
+ QStringLiteral("xa"),
+ QStringLiteral("dnd"),
+ QStringLiteral("chat"),
+ QStringLiteral("invisible")
};
class QXmppPresencePrivate : public QSharedData
{
public:
+ QXmppPresencePrivate();
+
+ QXmppPresence::Type type;
QXmppPresence::AvailableStatusType availableStatusType;
- int priority;
QString statusText;
- QXmppPresence::Type type;
-
- /// XEP-0153: vCard-Based Avatars
+ int priority;
- /// photoHash: the SHA1 hash of the avatar image data itself (not the base64-encoded version)
- /// in accordance with RFC 3174
- QByteArray photoHash;
- QXmppPresence::VCardUpdateType vCardUpdateType;
+ // XEP-0045: Multi-User Chat
+ QXmppMucItem mucItem;
+ QString mucPassword;
+ QList<int> mucStatusCodes;
+ bool mucSupported;
// XEP-0115: Entity Capabilities
QString capabilityHash;
@@ -72,11 +73,11 @@ public:
// Legacy XEP-0115: Entity Capabilities
QStringList capabilityExt;
- // XEP-0045: Multi-User Chat
- QXmppMucItem mucItem;
- QString mucPassword;
- QList<int> mucStatusCodes;
- bool mucSupported;
+ // XEP-0153: vCard-Based Avatars
+ // photoHash: the SHA1 hash of the avatar image data itself (not the base64-encoded version)
+ // in accordance with RFC 3174
+ QByteArray photoHash;
+ QXmppPresence::VCardUpdateType vCardUpdateType;
// XEP-0319: Last User Interaction in Presence
QDateTime lastUserInteraction;
@@ -86,6 +87,15 @@ public:
QString mixUserNick;
};
+QXmppPresencePrivate::QXmppPresencePrivate()
+ : type(QXmppPresence::Available),
+ availableStatusType(QXmppPresence::Online),
+ priority(0),
+ mucSupported(false),
+ vCardUpdateType(QXmppPresence::VCardUpdateNone)
+{
+}
+
/// Constructs a QXmppPresence.
///
/// \param type
@@ -93,35 +103,27 @@ public:
QXmppPresence::QXmppPresence(QXmppPresence::Type type)
: d(new QXmppPresencePrivate)
{
- d->availableStatusType = Online;
- d->priority = 0;
d->type = type;
- d->mucSupported = false;
- d->vCardUpdateType = VCardUpdateNone;
}
/// Constructs a copy of \a other.
-QXmppPresence::QXmppPresence(const QXmppPresence &other)
- : QXmppStanza(other)
- , d(other.d)
-{
-}
+QXmppPresence::QXmppPresence(const QXmppPresence &other) = default;
/// Destroys a QXmppPresence.
-QXmppPresence::~QXmppPresence()
-{
-
-}
+QXmppPresence::~QXmppPresence() = default;
/// Assigns \a other to this presence.
-QXmppPresence &QXmppPresence::operator=(const QXmppPresence &other)
+QXmppPresence &QXmppPresence::operator=(const QXmppPresence &other) = default;
+
+/// Indicates if the QXmppStanza is a stanza in the XMPP sence (i. e. a message,
+/// iq or presence)
+
+bool QXmppPresence::isXmppStanza() const
{
- QXmppStanza::operator=(other);
- d = other.d;
- return *this;
+ return true;
}
/// Returns the availability status type, for instance busy or away.
@@ -192,202 +194,6 @@ void QXmppPresence::setType(QXmppPresence::Type type)
d->type = type;
}
-/// \cond
-void QXmppPresence::parse(const QDomElement &element)
-{
- QXmppStanza::parse(element);
-
- const QString type = element.attribute("type");
- for (int i = Error; i <= Probe; i++) {
- if (type == presence_types[i]) {
- d->type = static_cast<Type>(i);
- break;
- }
- }
- const QString show = element.firstChildElement("show").text();
- for (int i = Online; i <= Invisible; i++) {
- if (show == presence_shows[i]) {
- d->availableStatusType = static_cast<AvailableStatusType>(i);
- break;
- }
- }
- d->statusText = element.firstChildElement("status").text();
- d->priority = element.firstChildElement("priority").text().toInt();
-
- QXmppElementList extensions;
- QDomElement xElement = element.firstChildElement();
- d->vCardUpdateType = VCardUpdateNone;
- while(!xElement.isNull())
- {
- // XEP-0045: Multi-User Chat
- if(xElement.namespaceURI() == ns_muc) {
- d->mucSupported = true;
- d->mucPassword = xElement.firstChildElement("password").text();
- }
- else if(xElement.namespaceURI() == ns_muc_user)
- {
- QDomElement itemElement = xElement.firstChildElement("item");
- d->mucItem.parse(itemElement);
- QDomElement statusElement = xElement.firstChildElement("status");
- d->mucStatusCodes.clear();
- while (!statusElement.isNull()) {
- d->mucStatusCodes << statusElement.attribute("code").toInt();
- statusElement = statusElement.nextSiblingElement("status");
- }
- }
- // XEP-0153: vCard-Based Avatars
- else if(xElement.namespaceURI() == ns_vcard_update)
- {
- QDomElement photoElement = xElement.firstChildElement("photo");
- if(!photoElement.isNull())
- {
- d->photoHash = QByteArray::fromHex(photoElement.text().toLatin1());
- if(d->photoHash.isEmpty())
- d->vCardUpdateType = VCardUpdateNoPhoto;
- else
- d->vCardUpdateType = VCardUpdateValidPhoto;
- }
- else
- {
- d->photoHash = QByteArray();
- d->vCardUpdateType = VCardUpdateNotReady;
- }
- }
- // XEP-0115: Entity Capabilities
- else if(xElement.tagName() == "c" && xElement.namespaceURI() == ns_capabilities)
- {
- d->capabilityNode = xElement.attribute("node");
- d->capabilityVer = QByteArray::fromBase64(xElement.attribute("ver").toLatin1());
- d->capabilityHash = xElement.attribute("hash");
- d->capabilityExt = xElement.attribute("ext").split(" ", QString::SkipEmptyParts);
- }
- // XEP-0319: Last User Interaction in Presence
- else if (xElement.tagName() == "idle" && xElement.namespaceURI() == ns_idle)
- {
- if (xElement.hasAttribute("since")) {
- const QString since = xElement.attribute("since");
- d->lastUserInteraction = QXmppUtils::datetimeFromString(since);
- }
- }
- // XEP-0405: Mediated Information eXchange (MIX): Participant Server Requirements
- else if (xElement.tagName() == "mix" && xElement.namespaceURI() == ns_mix_presence) {
- d->mixUserJid = xElement.firstChildElement("jid").text();
- d->mixUserNick = xElement.firstChildElement("nick").text();
- }
- else if (xElement.tagName() != "addresses" && xElement.tagName() != "error"
- && xElement.tagName() != "show" && xElement.tagName() != "status"
- && xElement.tagName() != "priority")
- {
- // other extensions
- extensions << QXmppElement(xElement);
- }
- xElement = xElement.nextSiblingElement();
- }
- setExtensions(extensions);
-}
-
-void QXmppPresence::toXml(QXmlStreamWriter *xmlWriter) const
-{
- xmlWriter->writeStartElement("presence");
- helperToXmlAddAttribute(xmlWriter,"xml:lang", lang());
- helperToXmlAddAttribute(xmlWriter,"id", id());
- helperToXmlAddAttribute(xmlWriter,"to", to());
- helperToXmlAddAttribute(xmlWriter,"from", from());
- helperToXmlAddAttribute(xmlWriter,"type", presence_types[d->type]);
-
- const QString show = presence_shows[d->availableStatusType];
- if (!show.isEmpty())
- helperToXmlAddTextElement(xmlWriter, "show", show);
- if (!d->statusText.isEmpty())
- helperToXmlAddTextElement(xmlWriter, "status", d->statusText);
- if (d->priority != 0)
- helperToXmlAddTextElement(xmlWriter, "priority", QString::number(d->priority));
-
- error().toXml(xmlWriter);
-
- // XEP-0045: Multi-User Chat
- if(d->mucSupported) {
- xmlWriter->writeStartElement("x");
- xmlWriter->writeAttribute("xmlns", ns_muc);
- if (!d->mucPassword.isEmpty())
- xmlWriter->writeTextElement("password", d->mucPassword);
- xmlWriter->writeEndElement();
- }
-
- if(!d->mucItem.isNull() || !d->mucStatusCodes.isEmpty())
- {
- xmlWriter->writeStartElement("x");
- xmlWriter->writeAttribute("xmlns", ns_muc_user);
- if (!d->mucItem.isNull())
- d->mucItem.toXml(xmlWriter);
- for (const auto code : d->mucStatusCodes) {
- xmlWriter->writeStartElement("status");
- xmlWriter->writeAttribute("code", QString::number(code));
- xmlWriter->writeEndElement();
- }
- xmlWriter->writeEndElement();
- }
-
- // XEP-0153: vCard-Based Avatars
- if(d->vCardUpdateType != VCardUpdateNone)
- {
- xmlWriter->writeStartElement("x");
- xmlWriter->writeAttribute("xmlns", ns_vcard_update);
- switch(d->vCardUpdateType)
- {
- case VCardUpdateNoPhoto:
- helperToXmlAddTextElement(xmlWriter, "photo", "");
- break;
- case VCardUpdateValidPhoto:
- helperToXmlAddTextElement(xmlWriter, "photo", d->photoHash.toHex());
- break;
- case VCardUpdateNotReady:
- break;
- default:
- break;
- }
- xmlWriter->writeEndElement();
- }
-
- if(!d->capabilityNode.isEmpty() && !d->capabilityVer.isEmpty()
- && !d->capabilityHash.isEmpty())
- {
- xmlWriter->writeStartElement("c");
- xmlWriter->writeAttribute("xmlns", ns_capabilities);
- helperToXmlAddAttribute(xmlWriter, "hash", d->capabilityHash);
- helperToXmlAddAttribute(xmlWriter, "node", d->capabilityNode);
- helperToXmlAddAttribute(xmlWriter, "ver", d->capabilityVer.toBase64());
- xmlWriter->writeEndElement();
- }
-
- // XEP-0319: Last User Interaction in Presence
- if (!d->lastUserInteraction.isNull() && d->lastUserInteraction.isValid())
- {
- xmlWriter->writeStartElement("idle");
- xmlWriter->writeAttribute("xmlns", ns_idle);
- helperToXmlAddAttribute(xmlWriter, "since", QXmppUtils::datetimeToString(
- d->lastUserInteraction));
- xmlWriter->writeEndElement();
- }
-
- // XEP-0405: Mediated Information eXchange (MIX): Participant Server Requirements
- if (!d->mixUserJid.isEmpty() || !d->mixUserNick.isEmpty()) {
- xmlWriter->writeStartElement("mix");
- xmlWriter->writeAttribute("xmlns", ns_mix_presence);
- if (!d->mixUserJid.isEmpty())
- xmlWriter->writeTextElement("jid", d->mixUserJid);
- if (!d->mixUserNick.isEmpty())
- xmlWriter->writeTextElement("nick", d->mixUserNick);
- xmlWriter->writeEndElement();
- }
-
- // other extensions
- QXmppStanza::extensionsToXml(xmlWriter);
-
- xmlWriter->writeEndElement();
-}
-/// \endcond
-
/// Returns the photo-hash of the VCardUpdate.
///
/// \return QByteArray
@@ -578,10 +384,182 @@ void QXmppPresence::setMixUserNick(const QString& mixUserNick)
d->mixUserNick = mixUserNick;
}
-/// Indicates if the QXmppStanza is a stanza in the XMPP sence (i. e. a message,
-/// iq or presence)
+/// \cond
+void QXmppPresence::parse(const QDomElement &element)
+{
+ QXmppStanza::parse(element);
-bool QXmppPresence::isXmppStanza() const
+ // attributes
+ int type = PRESENCE_TYPES.indexOf(element.attribute(QStringLiteral("type")));
+ if (type > -1)
+ d->type = Type(type);
+
+ QXmppElementList unknownElements;
+ QDomElement childElement = element.firstChildElement();
+
+ while (!childElement.isNull()) {
+ if (childElement.tagName() == QStringLiteral("show")) {
+ int availableStatusType = AVAILABLE_STATUS_TYPES.indexOf(childElement.text());
+ if (availableStatusType > -1)
+ d->availableStatusType = AvailableStatusType(availableStatusType);
+ } else if (childElement.tagName() == QStringLiteral("status")) {
+ d->statusText = childElement.text();
+ } else if (childElement.tagName() == QStringLiteral("priority")) {
+ d->priority = childElement.text().toInt();
+ // parse presence extensions
+ // XEP-0033: Extended Stanza Addressing and errors are parsed by QXmppStanza
+ } else if (!(childElement.tagName() == QStringLiteral("addresses") && childElement.namespaceURI() == ns_extended_addressing) &&
+ childElement.tagName() != "error") {
+ parseExtension(childElement, unknownElements);
+ }
+ childElement = childElement.nextSiblingElement();
+ }
+
+ setExtensions(unknownElements);
+}
+
+void QXmppPresence::parseExtension(const QDomElement &element, QXmppElementList &unknownElements)
{
- return true;
+ // XEP-0045: Multi-User Chat
+ if (element.tagName() == QStringLiteral("x") && element.namespaceURI() == ns_muc) {
+ d->mucSupported = true;
+ d->mucPassword = element.firstChildElement(QStringLiteral("password")).text();
+ } else if (element.tagName() == QStringLiteral("x") && element.namespaceURI() == ns_muc_user) {
+ QDomElement itemElement = element.firstChildElement(QStringLiteral("item"));
+ d->mucItem.parse(itemElement);
+ QDomElement statusElement = element.firstChildElement(QStringLiteral("status"));
+ d->mucStatusCodes.clear();
+
+ while (!statusElement.isNull()) {
+ d->mucStatusCodes << statusElement.attribute(QStringLiteral("code")).toInt();
+ statusElement = statusElement.nextSiblingElement(QStringLiteral("status"));
+ }
+ // XEP-0115: Entity Capabilities
+ } else if (element.tagName() == QStringLiteral("c") && element.namespaceURI() == ns_capabilities) {
+ d->capabilityNode = element.attribute(QStringLiteral("node"));
+ d->capabilityVer = QByteArray::fromBase64(element.attribute(QStringLiteral("ver")).toLatin1());
+ d->capabilityHash = element.attribute(QStringLiteral("hash"));
+ d->capabilityExt = element.attribute(QStringLiteral("ext")).split(' ', QString::SkipEmptyParts);
+ // XEP-0153: vCard-Based Avatars
+ } else if (element.namespaceURI() == ns_vcard_update) {
+ QDomElement photoElement = element.firstChildElement(QStringLiteral("photo"));
+ if (photoElement.isNull()) {
+ d->photoHash = {};
+ d->vCardUpdateType = VCardUpdateNotReady;
+ } else {
+ d->photoHash = QByteArray::fromHex(photoElement.text().toLatin1());
+ if (d->photoHash.isEmpty())
+ d->vCardUpdateType = VCardUpdateNoPhoto;
+ else
+ d->vCardUpdateType = VCardUpdateValidPhoto;
+ }
+ // XEP-0319: Last User Interaction in Presence
+ } else if (element.tagName() == QStringLiteral("idle") && element.namespaceURI() == ns_idle) {
+ if (element.hasAttribute(QStringLiteral("since"))) {
+ const QString since = element.attribute(QStringLiteral("since"));
+ d->lastUserInteraction = QXmppUtils::datetimeFromString(since);
+ }
+ // XEP-0405: Mediated Information eXchange (MIX): Participant Server Requirements
+ } else if (element.tagName() == QStringLiteral("mix") && element.namespaceURI() == ns_mix_presence) {
+ d->mixUserJid = element.firstChildElement(QStringLiteral("jid")).text();
+ d->mixUserNick = element.firstChildElement(QStringLiteral("nick")).text();
+ } else {
+ unknownElements << element;
+ }
}
+
+void QXmppPresence::toXml(QXmlStreamWriter *xmlWriter) const
+{
+ xmlWriter->writeStartElement(QStringLiteral("presence"));
+ helperToXmlAddAttribute(xmlWriter, QStringLiteral("xml:lang"), lang());
+ helperToXmlAddAttribute(xmlWriter, QStringLiteral("id"), id());
+ helperToXmlAddAttribute(xmlWriter, QStringLiteral("to"), to());
+ helperToXmlAddAttribute(xmlWriter, QStringLiteral("from"), from());
+ helperToXmlAddAttribute(xmlWriter, QStringLiteral("type"), PRESENCE_TYPES.at(d->type));
+
+ const QString show = AVAILABLE_STATUS_TYPES.at(d->availableStatusType);
+ if (!show.isEmpty())
+ helperToXmlAddTextElement(xmlWriter, QStringLiteral("show"), show);
+ if (!d->statusText.isEmpty())
+ helperToXmlAddTextElement(xmlWriter, QStringLiteral("status"), d->statusText);
+ if (d->priority != 0)
+ helperToXmlAddTextElement(xmlWriter, QStringLiteral("priority"), QString::number(d->priority));
+
+ error().toXml(xmlWriter);
+
+ // XEP-0045: Multi-User Chat
+ if (d->mucSupported) {
+ xmlWriter->writeStartElement(QStringLiteral("x"));
+ xmlWriter->writeAttribute(QStringLiteral("xmlns"), ns_muc);
+ if (!d->mucPassword.isEmpty())
+ xmlWriter->writeTextElement(QStringLiteral("password"), d->mucPassword);
+ xmlWriter->writeEndElement();
+ }
+
+ if (!d->mucItem.isNull() || !d->mucStatusCodes.isEmpty()) {
+ xmlWriter->writeStartElement(QStringLiteral("x"));
+ xmlWriter->writeAttribute(QStringLiteral("xmlns"), ns_muc_user);
+ if (!d->mucItem.isNull())
+ d->mucItem.toXml(xmlWriter);
+ for (const auto code : d->mucStatusCodes) {
+ xmlWriter->writeStartElement(QStringLiteral("status"));
+ xmlWriter->writeAttribute(QStringLiteral("code"), QString::number(code));
+ xmlWriter->writeEndElement();
+ }
+ xmlWriter->writeEndElement();
+ }
+
+ // XEP-0115: Entity Capabilities
+ if (!d->capabilityNode.isEmpty() &&
+ !d->capabilityVer.isEmpty() &&
+ !d->capabilityHash.isEmpty()) {
+ xmlWriter->writeStartElement(QStringLiteral("c"));
+ xmlWriter->writeAttribute(QStringLiteral("xmlns"), ns_capabilities);
+ helperToXmlAddAttribute(xmlWriter, QStringLiteral("hash"), d->capabilityHash);
+ helperToXmlAddAttribute(xmlWriter, QStringLiteral("node"), d->capabilityNode);
+ helperToXmlAddAttribute(xmlWriter, QStringLiteral("ver"), d->capabilityVer.toBase64());
+ xmlWriter->writeEndElement();
+ }
+
+ // XEP-0153: vCard-Based Avatars
+ if (d->vCardUpdateType != VCardUpdateNone) {
+ xmlWriter->writeStartElement(QStringLiteral("x"));
+ xmlWriter->writeAttribute(QStringLiteral("xmlns"), ns_vcard_update);
+ switch(d->vCardUpdateType) {
+ case VCardUpdateNoPhoto:
+ xmlWriter->writeEmptyElement(QStringLiteral("photo"));
+ break;
+ case VCardUpdateValidPhoto:
+ helperToXmlAddTextElement(xmlWriter, QStringLiteral("photo"), d->photoHash.toHex());
+ break;
+ default:
+ break;
+ }
+ xmlWriter->writeEndElement();
+ }
+
+ // XEP-0319: Last User Interaction in Presence
+ if (!d->lastUserInteraction.isNull() && d->lastUserInteraction.isValid()) {
+ xmlWriter->writeStartElement(QStringLiteral("idle"));
+ xmlWriter->writeAttribute(QStringLiteral("xmlns"), ns_idle);
+ helperToXmlAddAttribute(xmlWriter, QStringLiteral("since"), QXmppUtils::datetimeToString(d->lastUserInteraction));
+ xmlWriter->writeEndElement();
+ }
+
+ // XEP-0405: Mediated Information eXchange (MIX): Participant Server Requirements
+ if (!d->mixUserJid.isEmpty() || !d->mixUserNick.isEmpty()) {
+ xmlWriter->writeStartElement(QStringLiteral("mix"));
+ xmlWriter->writeAttribute(QStringLiteral("xmlns"), ns_mix_presence);
+ if (!d->mixUserJid.isEmpty())
+ helperToXmlAddTextElement(xmlWriter, QStringLiteral("jid"), d->mixUserJid);
+ if (!d->mixUserNick.isEmpty())
+ helperToXmlAddTextElement(xmlWriter, QStringLiteral("nick"), d->mixUserNick);
+ xmlWriter->writeEndElement();
+ }
+
+ // unknown extensions
+ QXmppStanza::extensionsToXml(xmlWriter);
+
+ xmlWriter->writeEndElement();
+}
+/// \endcond