diff options
| author | Linus Jahn <lnj@kaidan.im> | 2019-10-21 22:43:11 +0200 |
|---|---|---|
| committer | LNJ <lnj@kaidan.im> | 2019-12-10 22:41:05 +0100 |
| commit | 4d61ddd55f5a1a9b51a154c8493e61237827c212 (patch) | |
| tree | 931ae50141675dd1835bfba617de569d5f9d6e6e /src/base/QXmppPresence.cpp | |
| parent | d40b65c144a8f7042299bdcc387494ae01a60a46 (diff) | |
| download | qxmpp-4d61ddd55f5a1a9b51a154c8493e61237827c212.tar.gz | |
Refactor QXmppPresence, Add missing tests
Diffstat (limited to 'src/base/QXmppPresence.cpp')
| -rw-r--r-- | src/base/QXmppPresence.cpp | 476 |
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 |
