diff options
| author | Linus Jahn <lnj@kaidan.im> | 2019-06-16 08:31:15 +0200 |
|---|---|---|
| committer | LNJ <lnj@kaidan.im> | 2019-10-19 16:43:36 +0200 |
| commit | 98f2fd04b0a95840584320858ff54cd5caff8f70 (patch) | |
| tree | d7f3e2bc8be6b6c63bb31214ec84b1737a4288b8 /src/base/QXmppMessage.cpp | |
| parent | 38d0769c80c47627225d6278ef17453915b3a854 (diff) | |
Refactor & clean up QXmppMessage
This simplifies parsing and fixes a possible bug:
The bug case looks like this:
- We have one element we want to parse (e,g, "attachment" with namespace xyz)
- There is another element called "attachment" in the stanza and it's
located before the other element.
- QXmppMessage tries to parse the attachment element using
firstChildElement("attachment") and checks the namespace
- The namespace (of the first) element doesn't match
- The actual "attachment" element is not parsed
This also fixes the "constructor does not initialize these fields: […]"
warnings for QXmppMessagePrivate.
Diffstat (limited to 'src/base/QXmppMessage.cpp')
| -rw-r--r-- | src/base/QXmppMessage.cpp | 560 |
1 files changed, 257 insertions, 303 deletions
diff --git a/src/base/QXmppMessage.cpp b/src/base/QXmppMessage.cpp index 9806edf0..c6572f71 100644 --- a/src/base/QXmppMessage.cpp +++ b/src/base/QXmppMessage.cpp @@ -4,6 +4,7 @@ * Authors: * Manjeet Dahiya * Jeremy Lainé + * Linus Jahn * * Source: * https://github.com/qxmpp-project/qxmpp @@ -22,37 +23,37 @@ * */ +#include <QDateTime> #include <QDomElement> #include <QTextStream> #include <QXmlStreamWriter> -#include <QPair> #include "QXmppConstants_p.h" #include "QXmppMessage.h" #include "QXmppUtils.h" -static const char* chat_states[] = { - "", - "active", - "inactive", - "gone", - "composing", - "paused", +static const QStringList CHAT_STATES = { + QString(), + QStringLiteral("active"), + QStringLiteral("inactive"), + QStringLiteral("gone"), + QStringLiteral("composing"), + QStringLiteral("paused") }; -static const char* message_types[] = { - "error", - "normal", - "chat", - "groupchat", - "headline" +static const QStringList MESSAGE_TYPES = { + QStringLiteral("error"), + QStringLiteral("normal"), + QStringLiteral("chat"), + QStringLiteral("groupchat"), + QStringLiteral("headline") }; -static const char* marker_types[] = { - "", - "received", - "displayed", - "acknowledged" +static const QStringList MARKER_TYPES = { + QString(), + QStringLiteral("received"), + QStringLiteral("displayed"), + QStringLiteral("acknowledged") }; static const QStringList ENCRYPTION_NAMESPACES = { @@ -80,7 +81,10 @@ static const QStringList ENCRYPTION_NAMES = { QStringLiteral("OMEMO") }; -static const char *ns_xhtml = "http://www.w3.org/1999/xhtml"; +static bool checkElement(const QDomElement &element, const QString &tagName, const QString &xmlns) +{ + return element.tagName() == tagName && element.namespaceURI() == xmlns; +} enum StampType { @@ -91,6 +95,8 @@ enum StampType class QXmppMessagePrivate : public QSharedData { public: + QXmppMessagePrivate(); + QXmppMessage::Type type; QDateTime stamp; StampType stampType; @@ -143,10 +149,24 @@ public: QString encryptionName; // XEP-0382: Spoiler messages - bool isSpoiler = false; + bool isSpoiler; QString spoilerHint; }; +QXmppMessagePrivate::QXmppMessagePrivate() + : type(QXmppMessage::Normal), + stampType(DelayedDelivery), + state(QXmppMessage::None), + attentionRequested(false), + receiptRequested(false), + markable(false), + marker(QXmppMessage::NoMarker), + privatemsg(false), + hints(0), + isSpoiler(false) +{ +} + /// Constructs a QXmppMessage. /// /// \param from @@ -160,45 +180,29 @@ QXmppMessage::QXmppMessage(const QString& from, const QString& to, const , d(new QXmppMessagePrivate) { d->type = Chat; - d->stampType = DelayedDelivery; - d->state = None; - d->attentionRequested = false; d->body = body; d->thread = thread; - d->receiptRequested = false; - - d->markable = false; - d->marker = NoMarker; - - d->privatemsg = false; - - d->hints = 0; } /// Constructs a copy of \a other. -QXmppMessage::QXmppMessage(const QXmppMessage &other) - : QXmppStanza(other) - , d(other.d) -{ -} - -QXmppMessage::~QXmppMessage() -{ +QXmppMessage::QXmppMessage(const QXmppMessage &other) = default; -} +QXmppMessage::~QXmppMessage() = default; /// Assigns \a other to this message. -QXmppMessage& QXmppMessage::operator=(const QXmppMessage &other) +QXmppMessage& QXmppMessage::operator=(const QXmppMessage &other) = default; + +/// Indicates if the QXmppStanza is a stanza in the XMPP sense (i. e. a message, +/// iq or presence) + +bool QXmppMessage::isXmppStanza() const { - QXmppStanza::operator=(other); - d = other.d; - return *this; + return true; } /// Returns the message's body. -/// QString QXmppMessage::body() const { @@ -317,7 +321,6 @@ void QXmppMessage::setMucInvitationReason(const QString &reason) } /// Returns the message's type. -/// QXmppMessage::Type QXmppMessage::type() const { @@ -367,7 +370,6 @@ void QXmppMessage::setState(QXmppMessage::State state) } /// Returns the message's subject. -/// QString QXmppMessage::subject() const { @@ -415,28 +417,6 @@ void QXmppMessage::setXhtml(const QString &xhtml) d->xhtml = xhtml; } -namespace -{ - static QList<QPair<QString, QString> > knownMessageSubelems() - { - QList<QPair<QString, QString> > result; - result << qMakePair(QString("body"), QString()) - << qMakePair(QString("subject"), QString()) - << qMakePair(QString("thread"), QString()) - << qMakePair(QString("html"), QString()) - << qMakePair(QString("received"), QString(ns_message_receipts)) - << qMakePair(QString("replace"), QString(ns_message_correct)) - << qMakePair(QString("request"), QString()) - << qMakePair(QString("delay"), QString()) - << qMakePair(QString("attention"), QString()) - << qMakePair(QString("addresses"), QString()) - << qMakePair(QString("private"), QString(ns_carbons)); - for (int i = QXmppMessage::Active; i <= QXmppMessage::Paused; i++) - result << qMakePair(QString(chat_states[i]), QString()); - return result; - } -} - /// Returns true if a message is markable, as defined /// XEP-0333: Chat Markers. @@ -519,14 +499,6 @@ void QXmppMessage::setPrivate(const bool priv) d->privatemsg = priv; } -/// Indicates if the QXmppStanza is a stanza in the XMPP sense (i. e. a message, -/// iq or presence) - -bool QXmppMessage::isXmppStanza() const -{ - return true; -} - /// Returns a possibly attached URL from XEP-0066: Out of Band Data QString QXmppMessage::outOfBandUrl() const @@ -756,294 +728,154 @@ void QXmppMessage::parse(const QDomElement &element) { QXmppStanza::parse(element); - const QString type = element.attribute("type"); - d->type = Normal; - for (int i = Error; i <= Headline; i++) { - if (type == message_types[i]) { - d->type = static_cast<Type>(i); - break; - } - } - - d->body = element.firstChildElement("body").text(); - d->subject = element.firstChildElement("subject").text(); - d->thread = element.firstChildElement("thread").text(); - - // chat states - for (int i = Active; i <= Paused; i++) - { - QDomElement stateElement = element.firstChildElement(chat_states[i]); - if (!stateElement.isNull() && - stateElement.namespaceURI() == ns_chat_states) - { - d->state = static_cast<QXmppMessage::State>(i); - break; - } - } - - // XEP-0071: XHTML-IM - QDomElement htmlElement = element.firstChildElement("html"); - if (!htmlElement.isNull() && htmlElement.namespaceURI() == ns_xhtml_im) { - QDomElement bodyElement = htmlElement.firstChildElement("body"); - if (!bodyElement.isNull() && bodyElement.namespaceURI() == ns_xhtml) { - QTextStream stream(&d->xhtml, QIODevice::WriteOnly); - bodyElement.save(stream, 0); - - d->xhtml = d->xhtml.mid(d->xhtml.indexOf('>') + 1); - d->xhtml.replace(" xmlns=\"http://www.w3.org/1999/xhtml\"", ""); - d->xhtml.replace("</body>", ""); - d->xhtml = d->xhtml.trimmed(); - } - } - - // XEP-0184: Message Delivery Receipts - QDomElement receivedElement = element.firstChildElement("received"); - if (!receivedElement.isNull() && receivedElement.namespaceURI() == ns_message_receipts) { - d->receiptId = receivedElement.attribute("id"); - - // compatibility with old-style XEP - if (d->receiptId.isEmpty()) - d->receiptId = id(); - } else { - d->receiptId = QString(); - } - d->receiptRequested = element.firstChildElement("request").namespaceURI() == ns_message_receipts; - - // XEP-0203: Delayed Delivery - QDomElement delayElement = element.firstChildElement("delay"); - if (!delayElement.isNull() && delayElement.namespaceURI() == ns_delayed_delivery) - { - const QString str = delayElement.attribute("stamp"); - d->stamp = QXmppUtils::datetimeFromString(str); - d->stampType = DelayedDelivery; - } - - // XEP-0224: Attention - d->attentionRequested = element.firstChildElement("attention").namespaceURI() == ns_attention; - - // XEP-0333: Chat Markers - QDomElement markableElement = element.firstChildElement("markable"); - if (!markableElement.isNull()) - { - d->markable = true; - } - // check for all the marker types - QDomElement chatStateElement; - QXmppMessage::Marker marker = QXmppMessage::NoMarker; - for (int i = Received; i <= Acknowledged; i++) - { - chatStateElement = element.firstChildElement(marker_types[i]); - if (!chatStateElement.isNull() && - chatStateElement.namespaceURI() == ns_chat_markers) - { - marker = static_cast<QXmppMessage::Marker>(i); - break; - } - } - // if marker is present, check it's the right ns - if (!chatStateElement.isNull()) - { - if (chatStateElement.namespaceURI() == ns_chat_markers) - { - d->marker = marker; - d->markedId = chatStateElement.attribute("id", QString()); - d->markedThread = chatStateElement.attribute("thread", QString()); - } - } - - // XEP-0280: Message Carbons - QDomElement privateElement = element.firstChildElement("private"); - if (!privateElement.isNull()) - d->privatemsg = true; - - // XEP-0308: Last Message Correction - QDomElement replaceElement = element.firstChildElement("replace"); - if (!replaceElement.isNull() && replaceElement.namespaceURI() == ns_message_correct) - d->replaceId = replaceElement.attribute("id"); - - const QList<QPair<QString, QString> > &knownElems = knownMessageSubelems(); + // message type + int messageType = MESSAGE_TYPES.indexOf(element.attribute(QStringLiteral("type"))); + if (messageType != -1) + d->type = static_cast<Type>(messageType); + else + d->type = QXmppMessage::Normal; QXmppElementList extensions; - QDomElement xElement = element.firstChildElement(); - while (!xElement.isNull()) - { - if (xElement.tagName() == "x") - { - if (xElement.namespaceURI() == ns_legacy_delayed_delivery) - { - // if XEP-0203 exists, XEP-0091 has no need to parse because XEP-0091 is no more standard protocol) - if (d->stamp.isNull()) - { - // XEP-0091: Legacy Delayed Delivery - const QString str = xElement.attribute("stamp"); - d->stamp = QDateTime::fromString(str, "yyyyMMddThh:mm:ss"); - d->stamp.setTimeSpec(Qt::UTC); - d->stampType = LegacyDelayedDelivery; - } - } else if (xElement.namespaceURI() == ns_conference) { - // XEP-0249: Direct MUC Invitations - d->mucInvitationJid = xElement.attribute("jid"); - d->mucInvitationPassword = xElement.attribute("password"); - d->mucInvitationReason = xElement.attribute("reason"); - } else if (xElement.namespaceURI() == ns_oob) { - // XEP-0066: Out of Band Data - d->outOfBandUrl = xElement.firstChildElement("url").text(); - } - else { - extensions << QXmppElement(xElement); - } - // XEP-0334: Message Processing Hints - } else if (xElement.namespaceURI() == ns_message_processing_hints && HINT_TYPES.contains(xElement.tagName())) { - addHint(Hint(1 << HINT_TYPES.indexOf(xElement.tagName()))); - // XEP-0367: Message Attaching - } else if (xElement.tagName() == "attach-to" && xElement.namespaceURI() == ns_message_attaching) { - d->attachId = xElement.attribute("id"); - // XEP-0369: Mediated Information eXchange (MIX) - } else if (xElement.tagName() == "mix" && xElement.namespaceURI() == ns_mix) { - d->mixUserJid = xElement.firstChildElement("jid").text(); - d->mixUserNick = xElement.firstChildElement("nick").text(); - // XEP-0380: Explicit Message Encryption - } else if (xElement.tagName() == "encryption" && xElement.namespaceURI() == ns_eme) { - d->encryptionMethod = xElement.attribute("namespace"); - d->encryptionName = xElement.attribute("name"); - // XEP-0382: Spoiler messages - } else if (xElement.tagName() == "spoiler" && xElement.namespaceURI() == ns_spoiler) { - d->isSpoiler = true; - d->spoilerHint = xElement.text(); - } else if (!knownElems.contains(qMakePair(xElement.tagName(), xElement.namespaceURI())) && - !knownElems.contains(qMakePair(xElement.tagName(), QString()))) { - // other extensions - extensions << QXmppElement(xElement); + QDomElement childElement = element.firstChildElement(); + while (!childElement.isNull()) { + if (childElement.tagName() == QStringLiteral("body")) { + d->body = childElement.text(); + } else if (childElement.tagName() == QStringLiteral("subject")) { + d->subject = childElement.text(); + } else if (childElement.tagName() == QStringLiteral("thread")) { + d->thread = childElement.text(); + // parse message extensions + // XEP-0033: Extended Stanza Addressing and errors are parsed by QXmppStanza + } else if (!checkElement(childElement, QStringLiteral("addresses"), ns_extended_addressing) && + childElement.tagName() != QStringLiteral("error")) { + parseExtension(childElement, extensions); } - xElement = xElement.nextSiblingElement(); + childElement = childElement.nextSiblingElement(); } setExtensions(extensions); } void QXmppMessage::toXml(QXmlStreamWriter *xmlWriter) const { - xmlWriter->writeStartElement("message"); - helperToXmlAddAttribute(xmlWriter, "xml:lang", lang()); - helperToXmlAddAttribute(xmlWriter, "id", id()); - helperToXmlAddAttribute(xmlWriter, "to", to()); - helperToXmlAddAttribute(xmlWriter, "from", from()); - helperToXmlAddAttribute(xmlWriter, "type", message_types[d->type]); + xmlWriter->writeStartElement(QStringLiteral("message")); + 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"), MESSAGE_TYPES.at(d->type)); if (!d->subject.isEmpty()) - helperToXmlAddTextElement(xmlWriter, "subject", d->subject); + helperToXmlAddTextElement(xmlWriter, QStringLiteral("subject"), d->subject); if (!d->body.isEmpty()) - helperToXmlAddTextElement(xmlWriter, "body", d->body); + helperToXmlAddTextElement(xmlWriter, QStringLiteral("body"), d->body); if (!d->thread.isEmpty()) - helperToXmlAddTextElement(xmlWriter, "thread", d->thread); + helperToXmlAddTextElement(xmlWriter, QStringLiteral("thread"), d->thread); error().toXml(xmlWriter); // chat states - if (d->state > None && d->state <= Paused) - { - xmlWriter->writeStartElement(chat_states[d->state]); - xmlWriter->writeAttribute("xmlns", ns_chat_states); + if (d->state > None && d->state <= Paused) { + xmlWriter->writeStartElement(CHAT_STATES.at(d->state)); + xmlWriter->writeAttribute(QStringLiteral("xmlns"), ns_chat_states); xmlWriter->writeEndElement(); } // XEP-0071: XHTML-IM if (!d->xhtml.isEmpty()) { - xmlWriter->writeStartElement("html"); - xmlWriter->writeAttribute("xmlns", ns_xhtml_im); - xmlWriter->writeStartElement("body"); - xmlWriter->writeAttribute("xmlns", ns_xhtml); - xmlWriter->writeCharacters(""); + xmlWriter->writeStartElement(QStringLiteral("html")); + xmlWriter->writeAttribute(QStringLiteral("xmlns"), ns_xhtml_im); + xmlWriter->writeStartElement(QStringLiteral("body")); + xmlWriter->writeAttribute(QStringLiteral("xmlns"), ns_xhtml); + xmlWriter->writeCharacters(QStringLiteral("")); xmlWriter->device()->write(d->xhtml.toUtf8()); xmlWriter->writeEndElement(); xmlWriter->writeEndElement(); } // time stamp - if (d->stamp.isValid()) - { + if (d->stamp.isValid()) { QDateTime utcStamp = d->stamp.toUTC(); - if (d->stampType == DelayedDelivery) - { + if (d->stampType == DelayedDelivery) { // XEP-0203: Delayed Delivery - xmlWriter->writeStartElement("delay"); - xmlWriter->writeAttribute("xmlns", ns_delayed_delivery); - helperToXmlAddAttribute(xmlWriter, "stamp", QXmppUtils::datetimeToString(utcStamp)); + xmlWriter->writeStartElement(QStringLiteral("delay")); + xmlWriter->writeAttribute(QStringLiteral("xmlns"), ns_delayed_delivery); + helperToXmlAddAttribute(xmlWriter, QStringLiteral("stamp"), QXmppUtils::datetimeToString(utcStamp)); xmlWriter->writeEndElement(); } else { // XEP-0091: Legacy Delayed Delivery - xmlWriter->writeStartElement("x"); - xmlWriter->writeAttribute("xmlns", ns_legacy_delayed_delivery); - helperToXmlAddAttribute(xmlWriter, "stamp", utcStamp.toString("yyyyMMddThh:mm:ss")); + xmlWriter->writeStartElement(QStringLiteral("x")); + xmlWriter->writeAttribute(QStringLiteral("xmlns"), ns_legacy_delayed_delivery); + helperToXmlAddAttribute(xmlWriter, QStringLiteral("stamp"), utcStamp.toString(QStringLiteral("yyyyMMddThh:mm:ss"))); xmlWriter->writeEndElement(); } } // XEP-0184: Message Delivery Receipts if (!d->receiptId.isEmpty()) { - xmlWriter->writeStartElement("received"); - xmlWriter->writeAttribute("xmlns", ns_message_receipts); - xmlWriter->writeAttribute("id", d->receiptId); + xmlWriter->writeStartElement(QStringLiteral("received")); + xmlWriter->writeAttribute(QStringLiteral("xmlns"), ns_message_receipts); + xmlWriter->writeAttribute(QStringLiteral("id"), d->receiptId); xmlWriter->writeEndElement(); } if (d->receiptRequested) { - xmlWriter->writeStartElement("request"); - xmlWriter->writeAttribute("xmlns", ns_message_receipts); + xmlWriter->writeStartElement(QStringLiteral("request")); + xmlWriter->writeAttribute(QStringLiteral("xmlns"), ns_message_receipts); xmlWriter->writeEndElement(); } // XEP-0224: Attention if (d->attentionRequested) { - xmlWriter->writeStartElement("attention"); - xmlWriter->writeAttribute("xmlns", ns_attention); + xmlWriter->writeStartElement(QStringLiteral("attention")); + xmlWriter->writeAttribute(QStringLiteral("xmlns"), ns_attention); xmlWriter->writeEndElement(); } // XEP-0249: Direct MUC Invitations if (!d->mucInvitationJid.isEmpty()) { - xmlWriter->writeStartElement("x"); - xmlWriter->writeAttribute("xmlns", ns_conference); - xmlWriter->writeAttribute("jid", d->mucInvitationJid); + xmlWriter->writeStartElement(QStringLiteral("x")); + xmlWriter->writeAttribute(QStringLiteral("xmlns"), ns_conference); + xmlWriter->writeAttribute(QStringLiteral("jid"), d->mucInvitationJid); if (!d->mucInvitationPassword.isEmpty()) - xmlWriter->writeAttribute("password", d->mucInvitationPassword); + xmlWriter->writeAttribute(QStringLiteral("password"), d->mucInvitationPassword); if (!d->mucInvitationReason.isEmpty()) - xmlWriter->writeAttribute("reason", d->mucInvitationReason); + xmlWriter->writeAttribute(QStringLiteral("reason"), d->mucInvitationReason); xmlWriter->writeEndElement(); } // XEP-0333: Chat Markers if (d->markable) { - xmlWriter->writeStartElement("markable"); - xmlWriter->writeAttribute("xmlns", ns_chat_markers); + xmlWriter->writeStartElement(QStringLiteral("markable")); + xmlWriter->writeAttribute(QStringLiteral("xmlns"), ns_chat_markers); xmlWriter->writeEndElement(); } if (d->marker != NoMarker) { - xmlWriter->writeStartElement(marker_types[d->marker]); - xmlWriter->writeAttribute("xmlns", ns_chat_markers); - xmlWriter->writeAttribute("id", d->markedId); + xmlWriter->writeStartElement(MARKER_TYPES.at(d->marker)); + xmlWriter->writeAttribute(QStringLiteral("xmlns"), ns_chat_markers); + xmlWriter->writeAttribute(QStringLiteral("id"), d->markedId); if (!d->markedThread.isNull() && !d->markedThread.isEmpty()) { - xmlWriter->writeAttribute("thread", d->markedThread); + xmlWriter->writeAttribute(QStringLiteral("thread"), d->markedThread); } xmlWriter->writeEndElement(); } // XEP-0280: Message Carbons if (d->privatemsg) { - xmlWriter->writeStartElement("private"); - xmlWriter->writeAttribute("xmlns", ns_carbons); + xmlWriter->writeStartElement(QStringLiteral("private")); + xmlWriter->writeAttribute(QStringLiteral("xmlns"), ns_carbons); xmlWriter->writeEndElement(); } // XEP-0066: Out of Band Data if (!d->outOfBandUrl.isEmpty()) { - xmlWriter->writeStartElement("x"); - xmlWriter->writeAttribute("xmlns", ns_oob); - xmlWriter->writeTextElement("url", d->outOfBandUrl); + xmlWriter->writeStartElement(QStringLiteral("x")); + xmlWriter->writeAttribute(QStringLiteral("xmlns"), ns_oob); + xmlWriter->writeTextElement(QStringLiteral("url"), d->outOfBandUrl); xmlWriter->writeEndElement(); } // XEP-0308: Last Message Correction if (!d->replaceId.isEmpty()) { - xmlWriter->writeStartElement("replace"); - xmlWriter->writeAttribute("xmlns", ns_message_correct); - xmlWriter->writeAttribute("id", d->replaceId); + xmlWriter->writeStartElement(QStringLiteral("replace")); + xmlWriter->writeAttribute(QStringLiteral("xmlns"), ns_message_correct); + xmlWriter->writeAttribute(QStringLiteral("id"), d->replaceId); xmlWriter->writeEndElement(); } @@ -1051,41 +883,41 @@ void QXmppMessage::toXml(QXmlStreamWriter *xmlWriter) const for (quint8 i = 0; i < HINT_TYPES.size(); i++) { if (hasHint(Hint(1 << i))) { xmlWriter->writeStartElement(HINT_TYPES.at(i)); - xmlWriter->writeAttribute("xmlns", ns_message_processing_hints); + xmlWriter->writeAttribute(QStringLiteral("xmlns"), ns_message_processing_hints); xmlWriter->writeEndElement(); } } // XEP-0367: Message Attaching if (!d->attachId.isEmpty()) { - xmlWriter->writeStartElement("attach-to"); - xmlWriter->writeAttribute("xmlns", ns_message_attaching); - xmlWriter->writeAttribute("id", d->attachId); + xmlWriter->writeStartElement(QStringLiteral("attach-to")); + xmlWriter->writeAttribute(QStringLiteral("xmlns"), ns_message_attaching); + xmlWriter->writeAttribute(QStringLiteral("id"), d->attachId); xmlWriter->writeEndElement(); } // XEP-0369: Mediated Information eXchange (MIX) if (!d->mixUserJid.isEmpty() || !d->mixUserNick.isEmpty()) { - xmlWriter->writeStartElement("mix"); - xmlWriter->writeAttribute("xmlns", ns_mix); - helperToXmlAddTextElement(xmlWriter, "jid", d->mixUserJid); - helperToXmlAddTextElement(xmlWriter, "nick", d->mixUserNick); + xmlWriter->writeStartElement(QStringLiteral("mix")); + xmlWriter->writeAttribute(QStringLiteral("xmlns"), ns_mix); + helperToXmlAddTextElement(xmlWriter, QStringLiteral("jid"), d->mixUserJid); + helperToXmlAddTextElement(xmlWriter, QStringLiteral("nick"), d->mixUserNick); xmlWriter->writeEndElement(); } // XEP-0380: Explicit Message Encryption if (!d->encryptionMethod.isEmpty()) { - xmlWriter->writeStartElement("encryption"); - xmlWriter->writeAttribute("xmlns", ns_eme); - xmlWriter->writeAttribute("namespace", d->encryptionMethod); - helperToXmlAddAttribute(xmlWriter, "name", d->encryptionName); + xmlWriter->writeStartElement(QStringLiteral("encryption")); + xmlWriter->writeAttribute(QStringLiteral("xmlns"), ns_eme); + xmlWriter->writeAttribute(QStringLiteral("namespace"), d->encryptionMethod); + helperToXmlAddAttribute(xmlWriter, QStringLiteral("name"), d->encryptionName); xmlWriter->writeEndElement(); } // XEP-0382: Spoiler messages if (d->isSpoiler) { - xmlWriter->writeStartElement("spoiler"); - xmlWriter->writeAttribute("xmlns", ns_spoiler); + xmlWriter->writeStartElement(QStringLiteral("spoiler")); + xmlWriter->writeAttribute(QStringLiteral("xmlns"), ns_spoiler); xmlWriter->writeCharacters(d->spoilerHint); xmlWriter->writeEndElement(); } @@ -1096,3 +928,125 @@ void QXmppMessage::toXml(QXmlStreamWriter *xmlWriter) const xmlWriter->writeEndElement(); } /// \endcond + +/// Parses message extensions +/// +/// \param element child element of the message to be parsed +/// \param unknownExtensions extensions not known are added to this list as QXmppElement + +void QXmppMessage::parseExtension(const QDomElement &element, QXmppElementList &unknownExtensions) +{ + if (element.tagName() == QStringLiteral("x")) { + parseXElement(element, unknownExtensions); + // XEP-0071: XHTML-IM + } else if (checkElement(element, QStringLiteral("html"), ns_xhtml_im)) { + QDomElement bodyElement = element.firstChildElement(QStringLiteral("body")); + if (!bodyElement.isNull() && bodyElement.namespaceURI() == ns_xhtml) { + QTextStream stream(&d->xhtml, QIODevice::WriteOnly); + bodyElement.save(stream, 0); + + d->xhtml = d->xhtml.mid(d->xhtml.indexOf('>') + 1); + d->xhtml.replace( + QStringLiteral(" xmlns=\"http://www.w3.org/1999/xhtml\""), + QString() + ); + d->xhtml.replace(QStringLiteral("</body>"), QString()); + d->xhtml = d->xhtml.trimmed(); + } + // XEP-0085: Chat State Notifications + } else if (element.namespaceURI() == ns_chat_states) { + int i = CHAT_STATES.indexOf(element.tagName()); + if (i > 0) + d->state = static_cast<QXmppMessage::State>(i); + // XEP-0184: Message Delivery Receipts + } else if (checkElement(element, QStringLiteral("received"), ns_message_receipts)) { + d->receiptId = element.attribute(QStringLiteral("id")); + + // compatibility with old-style XEP + if (d->receiptId.isEmpty()) + d->receiptId = id(); + } else if (checkElement(element, QStringLiteral("request"), ns_message_receipts)) { + d->receiptRequested = true; + // XEP-0203: Delayed Delivery + } else if (checkElement(element, QStringLiteral("delay"), ns_delayed_delivery)) { + d->stamp = QXmppUtils::datetimeFromString( + element.attribute(QStringLiteral("stamp")) + ); + d->stampType = DelayedDelivery; + // XEP-0224: Attention + } else if (checkElement(element, QStringLiteral("attention"), ns_attention)) { + d->attentionRequested = true; + // XEP-0280: Message Carbons + } else if (checkElement(element, QStringLiteral("private"), ns_carbons)) { + d->privatemsg = true; + // XEP-0308: Last Message Correction + } else if (checkElement(element, QStringLiteral("replace"), ns_message_correct)) { + d->replaceId = element.attribute(QStringLiteral("id")); + // XEP-0333: Chat Markers + } else if (element.namespaceURI() == ns_chat_markers) { + if (element.tagName() == QStringLiteral("markable")) { + d->markable = true; + } else { + int marker = MARKER_TYPES.indexOf(element.tagName()); + if (marker != -1) { + d->marker = static_cast<QXmppMessage::Marker>(marker); + d->markedId = element.attribute(QStringLiteral("id")); + d->markedThread = element.attribute(QStringLiteral("thread")); + } + } + // XEP-0334: Message Processing Hints + } else if (element.namespaceURI() == ns_message_processing_hints && + HINT_TYPES.contains(element.tagName())) { + addHint(Hint(1 << HINT_TYPES.indexOf(element.tagName()))); + // XEP-0367: Message Attaching + } else if (checkElement(element, QStringLiteral("attach-to"), ns_message_attaching)) { + d->attachId = element.attribute(QStringLiteral("id")); + // XEP-0369: Mediated Information eXchange (MIX) + } else if (checkElement(element, QStringLiteral("mix"), ns_mix)) { + d->mixUserJid = element.firstChildElement(QStringLiteral("jid")).text(); + d->mixUserNick = element.firstChildElement(QStringLiteral("nick")).text(); + // XEP-0380: Explicit Message Encryption + } else if (checkElement(element, QStringLiteral("encryption"), ns_eme)) { + d->encryptionMethod = element.attribute(QStringLiteral("namespace")); + d->encryptionName = element.attribute(QStringLiteral("name")); + // XEP-0382: Spoiler messages + } else if (checkElement(element, QStringLiteral("spoiler"), ns_spoiler)) { + d->isSpoiler = true; + d->spoilerHint = element.text(); + } else { + // other extensions + unknownExtensions << QXmppElement(element); + } +} + +/// Parses <x/> child elements of the message +/// +/// \param element child element of the message to be parsed +/// \param unknownExtensions extensions not known are added to this list as QXmppElement + +void QXmppMessage::parseXElement(const QDomElement &element, QXmppElementList &unknownExtensions) +{ + if (element.namespaceURI() == ns_legacy_delayed_delivery) { + // if XEP-0203 exists, XEP-0091 has no need to parse because XEP-0091 + // is no more standard protocol) + if (d->stamp.isNull()) { + // XEP-0091: Legacy Delayed Delivery + d->stamp = QDateTime::fromString( + element.attribute(QStringLiteral("stamp")), + QStringLiteral("yyyyMMddThh:mm:ss") + ); + d->stamp.setTimeSpec(Qt::UTC); + d->stampType = LegacyDelayedDelivery; + } + } else if (element.namespaceURI() == ns_conference) { + // XEP-0249: Direct MUC Invitations + d->mucInvitationJid = element.attribute(QStringLiteral("jid")); + d->mucInvitationPassword = element.attribute(QStringLiteral("password")); + d->mucInvitationReason = element.attribute(QStringLiteral("reason")); + } else if (element.namespaceURI() == ns_oob) { + // XEP-0066: Out of Band Data + d->outOfBandUrl = element.firstChildElement(QStringLiteral("url")).text(); + } else { + unknownExtensions << QXmppElement(element); + } +} |
