diff options
| author | Linus Jahn <lnj@kaidan.im> | 2021-09-05 16:29:09 +0200 |
|---|---|---|
| committer | Linus Jahn <lnj@kaidan.im> | 2021-09-28 17:08:08 +0200 |
| commit | 48d3eb28ab8f115ce999c2264303925f9c7ce2a7 (patch) | |
| tree | 3602342cbefb4c34bcbb61e08d17960e5ec69d3f /src/base/QXmppMessage.cpp | |
| parent | 22be2464b5d253e840d4731fbc86e9633a394e8c (diff) | |
| download | qxmpp-48d3eb28ab8f115ce999c2264303925f9c7ce2a7.tar.gz | |
Implement stanza parsing for Stanza Content Encryption
Diffstat (limited to 'src/base/QXmppMessage.cpp')
| -rw-r--r-- | src/base/QXmppMessage.cpp | 721 |
1 files changed, 404 insertions, 317 deletions
diff --git a/src/base/QXmppMessage.cpp b/src/base/QXmppMessage.cpp index e97731ae..c6313c65 100644 --- a/src/base/QXmppMessage.cpp +++ b/src/base/QXmppMessage.cpp @@ -1222,6 +1222,11 @@ void QXmppMessage::setTrustMessageElement(const std::optional<QXmppTrustMessageE /// \cond void QXmppMessage::parse(const QDomElement &element) { + parse(element, QXmpp::SceAll); +} + +void QXmppMessage::parse(const QDomElement &element, QXmpp::SceMode sceMode) +{ QXmppStanza::parse(element); // message type @@ -1232,58 +1237,43 @@ void QXmppMessage::parse(const QDomElement &element) d->type = QXmppMessage::Normal; QXmppElementList extensions; - 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(); - d->parentThread = childElement.attribute(QStringLiteral("parent")); - - // 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")) { - // add to unknown extensions, if element couldn't be parsed - if (!parseExtension(childElement)) { + for (auto childElement = element.firstChildElement(); + !childElement.isNull(); + childElement = childElement.nextSiblingElement()) { + if (!checkElement(childElement, QStringLiteral("addresses"), ns_extended_addressing) && + childElement.tagName() != QStringLiteral("error")) { + // try to parse; add to unknown extensions, if element couldn't be parsed + if (!parseExtension(childElement, sceMode)) { // other extensions extensions << QXmppElement(childElement); } } - childElement = childElement.nextSiblingElement(); } setExtensions(extensions); } -void QXmppMessage::toXml(QXmlStreamWriter *xmlWriter) const -{ - 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, QStringLiteral("subject"), d->subject); - if (!d->body.isEmpty()) - helperToXmlAddTextElement(xmlWriter, QStringLiteral("body"), d->body); - if (!d->thread.isEmpty()) { - xmlWriter->writeStartElement(QStringLiteral("thread")); - helperToXmlAddAttribute(xmlWriter, QStringLiteral("parent"), d->parentThread); - xmlWriter->writeCharacters(d->thread); - xmlWriter->writeEndElement(); - } - error().toXml(xmlWriter); +void QXmppMessage::toXml(QXmlStreamWriter *writer) const +{ + toXml(writer, QXmpp::SceAll); +} + +void QXmppMessage::toXml(QXmlStreamWriter *writer, QXmpp::SceMode sceMode) const +{ + writer->writeStartElement(QStringLiteral("message")); + helperToXmlAddAttribute(writer, QStringLiteral("xml:lang"), lang()); + helperToXmlAddAttribute(writer, QStringLiteral("id"), id()); + helperToXmlAddAttribute(writer, QStringLiteral("to"), to()); + helperToXmlAddAttribute(writer, QStringLiteral("from"), from()); + helperToXmlAddAttribute(writer, QStringLiteral("type"), MESSAGE_TYPES.at(d->type)); + error().toXml(writer); // extensions - serializeExtensions(xmlWriter); + serializeExtensions(writer, sceMode); // other, unknown extensions - QXmppStanza::extensionsToXml(xmlWriter); + QXmppStanza::extensionsToXml(writer); - xmlWriter->writeEndElement(); + writer->writeEndElement(); } /// \endcond @@ -1294,342 +1284,439 @@ void QXmppMessage::toXml(QXmlStreamWriter *xmlWriter) const /// function may be executed multiple times with different elements. /// /// \param element child element of the message to be parsed +/// \param sceMode Which elements to be parsed from the DOM (all known / only +/// public / only sensitive) /// /// \return True, if the element was successfully parsed. /// /// \since QXmpp 1.5 /// -bool QXmppMessage::parseExtension(const QDomElement &element) +bool QXmppMessage::parseExtension(const QDomElement &element, QXmpp::SceMode sceMode) { - if (element.tagName() == QStringLiteral("x")) { - 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; + if (sceMode & QXmpp::ScePublic) { + // XEP-0280: Message Carbons + if (checkElement(element, QStringLiteral("private"), ns_carbons)) { + d->privatemsg = true; + return true; + } + // XEP-0334: Message Processing Hints + if (element.namespaceURI() == ns_message_processing_hints && + HINT_TYPES.contains(element.tagName())) { + addHint(Hint(1 << HINT_TYPES.indexOf(element.tagName()))); + return true; + } + // XEP-0359: Unique and Stable Stanza IDs + if (checkElement(element, QStringLiteral("stanza-id"), ns_sid)) { + d->stanzaId = element.attribute(QStringLiteral("id")); + d->stanzaIdBy = element.attribute(QStringLiteral("by")); + return true; + } + if (checkElement(element, QStringLiteral("origin-id"), ns_sid)) { + d->originId = element.attribute(QStringLiteral("id")); + return true; + } + // XEP-0369: Mediated Information eXchange (MIX) + if (checkElement(element, QStringLiteral("mix"), ns_mix)) { + d->mixUserJid = element.firstChildElement(QStringLiteral("jid")).text(); + d->mixUserNick = element.firstChildElement(QStringLiteral("nick")).text(); + return true; + } + // XEP-0380: Explicit Message Encryption + if (checkElement(element, QStringLiteral("encryption"), ns_eme)) { + d->encryptionMethod = element.attribute(QStringLiteral("namespace")); + d->encryptionName = element.attribute(QStringLiteral("name")); + return true; + } + // XEP-0384: OMEMO Encryption + if (QXmppOmemoElement::isOmemoElement(element)) { + QXmppOmemoElement omemoElement; + omemoElement.parse(element); + d->omemoElement = omemoElement; + return true; + } + // XEP-0428: Fallback Indication + if (checkElement(element, QStringLiteral("fallback"), ns_fallback_indication)) { + d->isFallback = true; + return true; + } + } + if (sceMode & QXmpp::SceSensitive) { + if (element.tagName() == QStringLiteral("body")) { + d->body = element.text(); + return true; + } + if (element.tagName() == QStringLiteral("subject")) { + d->subject = element.text(); + return true; + } + if (element.tagName() == QStringLiteral("thread")) { + d->thread = element.text(); + d->parentThread = element.attribute(QStringLiteral("parent")); + return true; + } + if (element.tagName() == QStringLiteral("x")) { + 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; + } + return true; } - } 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) { + if (element.namespaceURI() == ns_conference) { + d->mucInvitationJid = element.attribute(QStringLiteral("jid")); + d->mucInvitationPassword = element.attribute(QStringLiteral("password")); + d->mucInvitationReason = element.attribute(QStringLiteral("reason")); + return true; + } // XEP-0066: Out of Band Data - d->outOfBandUrl = element.firstChildElement(QStringLiteral("url")).text(); - } else { - return false; + if (element.namespaceURI() == ns_oob) { + d->outOfBandUrl = element.firstChildElement(QStringLiteral("url")).text(); + return true; + } } - } else if (checkElement(element, QStringLiteral("html"), ns_xhtml_im)) { // XEP-0071: 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(); + 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(); + } + return true; } - } else if (element.namespaceURI() == ns_chat_states) { // XEP-0085: Chat State Notifications - int i = CHAT_STATES.indexOf(element.tagName()); - if (i > 0) - d->state = static_cast<QXmppMessage::State>(i); - } else if (checkElement(element, QStringLiteral("received"), ns_message_receipts)) { + if (element.namespaceURI() == ns_chat_states) { + int i = CHAT_STATES.indexOf(element.tagName()); + if (i > 0) + d->state = static_cast<QXmppMessage::State>(i); + return true; + } // XEP-0184: Message Delivery 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; - } else if (checkElement(element, QStringLiteral("delay"), ns_delayed_delivery)) { + 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(); + return true; + } + if (checkElement(element, QStringLiteral("request"), ns_message_receipts)) { + d->receiptRequested = true; + return true; + } // XEP-0203: Delayed Delivery - d->stamp = QXmppUtils::datetimeFromString( - element.attribute(QStringLiteral("stamp"))); - d->stampType = DelayedDelivery; - } else if (checkElement(element, QStringLiteral("attention"), ns_attention)) { + if (checkElement(element, QStringLiteral("delay"), ns_delayed_delivery)) { + d->stamp = QXmppUtils::datetimeFromString( + element.attribute(QStringLiteral("stamp"))); + d->stampType = DelayedDelivery; + return true; + } // XEP-0224: Attention - d->attentionRequested = true; - } else if (QXmppBitsOfBinaryData::isBitsOfBinaryData(element)) { + if (checkElement(element, QStringLiteral("attention"), ns_attention)) { + d->attentionRequested = true; + return true; + } // XEP-0231: Bits of Binary - QXmppBitsOfBinaryData data; - data.parseElementFromChild(element); - d->bitsOfBinaryData << data; - } else if (checkElement(element, QStringLiteral("private"), ns_carbons)) { - // XEP-0280: Message Carbons - d->privatemsg = true; - } else if (checkElement(element, QStringLiteral("replace"), ns_message_correct)) { + if (QXmppBitsOfBinaryData::isBitsOfBinaryData(element)) { + QXmppBitsOfBinaryData data; + data.parseElementFromChild(element); + d->bitsOfBinaryData << data; + return true; + } // XEP-0308: Last Message Correction - d->replaceId = element.attribute(QStringLiteral("id")); - } else if (element.namespaceURI() == ns_chat_markers) { + if (checkElement(element, QStringLiteral("replace"), ns_message_correct)) { + d->replaceId = element.attribute(QStringLiteral("id")); + return true; + } // XEP-0333: 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")); + 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")); + } } + return true; } - } else if (element.namespaceURI() == ns_message_processing_hints && - HINT_TYPES.contains(element.tagName())) { - // XEP-0334: Message Processing Hints - addHint(Hint(1 << HINT_TYPES.indexOf(element.tagName()))); - } else if (checkElement(element, QStringLiteral("stanza-id"), ns_sid)) { - // XEP-0359: Unique and Stable Stanza IDs - d->stanzaId = element.attribute(QStringLiteral("id")); - d->stanzaIdBy = element.attribute(QStringLiteral("by")); - } else if (checkElement(element, QStringLiteral("origin-id"), ns_sid)) { - d->originId = element.attribute(QStringLiteral("id")); - } else if (checkElement(element, QStringLiteral("attach-to"), ns_message_attaching)) { // XEP-0367: Message Attaching - d->attachId = element.attribute(QStringLiteral("id")); - } else if (checkElement(element, QStringLiteral("mix"), ns_mix)) { - // XEP-0369: Mediated Information eXchange (MIX) - d->mixUserJid = element.firstChildElement(QStringLiteral("jid")).text(); - d->mixUserNick = element.firstChildElement(QStringLiteral("nick")).text(); - } else if (checkElement(element, QStringLiteral("encryption"), ns_eme)) { - // XEP-0380: Explicit Message Encryption - d->encryptionMethod = element.attribute(QStringLiteral("namespace")); - d->encryptionName = element.attribute(QStringLiteral("name")); - } else if (checkElement(element, QStringLiteral("spoiler"), ns_spoiler)) { + if (checkElement(element, QStringLiteral("attach-to"), ns_message_attaching)) { + d->attachId = element.attribute(QStringLiteral("id")); + return true; + } // XEP-0382: Spoiler messages - d->isSpoiler = true; - d->spoilerHint = element.text(); - } else if (QXmppOmemoElement::isOmemoElement(element)) { - // XEP-0384: OMEMO Encryption - QXmppOmemoElement omemoElement; - omemoElement.parse(element); - d->omemoElement = omemoElement; - } else if (checkElement(element, QStringLiteral("invitation"), ns_mix_misc)) { + if (checkElement(element, QStringLiteral("spoiler"), ns_spoiler)) { + d->isSpoiler = true; + d->spoilerHint = element.text(); + return true; + } // XEP-0407: Mediated Information eXchange (MIX): Miscellaneous Capabilities - QXmppMixInvitation mixInvitation; - mixInvitation.parse(element); - d->mixInvitation = mixInvitation; - } else if (checkElement(element, QStringLiteral("fallback"), ns_fallback_indication)) { - // XEP-0428: Fallback Indication - d->isFallback = true; - } else if (QXmppTrustMessageElement::isTrustMessageElement(element)) { + if (checkElement(element, QStringLiteral("invitation"), ns_mix_misc)) { + QXmppMixInvitation mixInvitation; + mixInvitation.parse(element); + d->mixInvitation = mixInvitation; + return true; + } // XEP-0434: Trust Messages (TM) - QXmppTrustMessageElement trustMessageElement; - trustMessageElement.parse(element); - d->trustMessageElement = trustMessageElement; - } else { - return false; + if (QXmppTrustMessageElement::isTrustMessageElement(element)) { + QXmppTrustMessageElement trustMessageElement; + trustMessageElement.parse(element); + d->trustMessageElement = trustMessageElement; + return true; + } } - return true; + return false; } /// /// Serializes all additional child elements. /// +/// \param writer The XML stream writer to output the XML +/// \param sceMode The mode which decides which elements to output (only useful +/// for encryption) +/// \param baseNamespace Custom namespace added to basic XMPP-Core elements like +/// <body/> (needed when encrypting elements outside of the stream). +/// /// \since QXmpp 1.5 /// -void QXmppMessage::serializeExtensions(QXmlStreamWriter *xmlWriter) const +void QXmppMessage::serializeExtensions(QXmlStreamWriter *writer, QXmpp::SceMode sceMode, const QString &baseNamespace) const { - // XEP-0066: Out of Band Data - if (!d->outOfBandUrl.isEmpty()) { - xmlWriter->writeStartElement(QStringLiteral("x")); - xmlWriter->writeDefaultNamespace(ns_oob); - xmlWriter->writeTextElement(QStringLiteral("url"), d->outOfBandUrl); - xmlWriter->writeEndElement(); - } + if (sceMode & QXmpp::ScePublic) { + // XEP-0280: Message Carbons + if (d->privatemsg) { + writer->writeStartElement(QStringLiteral("private")); + writer->writeDefaultNamespace(ns_carbons); + writer->writeEndElement(); + } - // XEP-0071: XHTML-IM - if (!d->xhtml.isEmpty()) { - xmlWriter->writeStartElement(QStringLiteral("html")); - xmlWriter->writeDefaultNamespace(ns_xhtml_im); - xmlWriter->writeStartElement(QStringLiteral("body")); - xmlWriter->writeDefaultNamespace(ns_xhtml); - xmlWriter->writeCharacters(QStringLiteral("")); - xmlWriter->device()->write(d->xhtml.toUtf8()); - xmlWriter->writeEndElement(); - xmlWriter->writeEndElement(); - } + // XEP-0334: Message Processing Hints + for (quint8 i = 0; i < HINT_TYPES.size(); i++) { + if (hasHint(Hint(1 << i))) { + writer->writeStartElement(HINT_TYPES.at(i)); + writer->writeDefaultNamespace(ns_message_processing_hints); + writer->writeEndElement(); + } + } - // XEP-0085: Chat State Notifications - if (d->state > None && d->state <= Paused) { - xmlWriter->writeStartElement(CHAT_STATES.at(d->state)); - xmlWriter->writeDefaultNamespace(ns_chat_states); - xmlWriter->writeEndElement(); - } + // XEP-0359: Unique and Stable Stanza IDs + if (!d->stanzaId.isNull()) { + writer->writeStartElement(QStringLiteral("stanza-id")); + writer->writeDefaultNamespace(ns_sid); + writer->writeAttribute(QStringLiteral("id"), d->stanzaId); + if (!d->stanzaIdBy.isNull()) + writer->writeAttribute(QStringLiteral("by"), d->stanzaIdBy); + writer->writeEndElement(); + } - // XEP-0091: Legacy Delayed Delivery | XEP-0203: Delayed Delivery - if (d->stamp.isValid()) { - QDateTime utcStamp = d->stamp.toUTC(); - if (d->stampType == DelayedDelivery) { - // XEP-0203: Delayed Delivery - xmlWriter->writeStartElement(QStringLiteral("delay")); - xmlWriter->writeDefaultNamespace(ns_delayed_delivery); - helperToXmlAddAttribute(xmlWriter, QStringLiteral("stamp"), QXmppUtils::datetimeToString(utcStamp)); - xmlWriter->writeEndElement(); - } else { - // XEP-0091: Legacy Delayed Delivery - xmlWriter->writeStartElement(QStringLiteral("x")); - xmlWriter->writeDefaultNamespace(ns_legacy_delayed_delivery); - helperToXmlAddAttribute(xmlWriter, QStringLiteral("stamp"), utcStamp.toString(QStringLiteral("yyyyMMddThh:mm:ss"))); - xmlWriter->writeEndElement(); + if (!d->originId.isNull()) { + writer->writeStartElement(QStringLiteral("origin-id")); + writer->writeDefaultNamespace(ns_sid); + writer->writeAttribute(QStringLiteral("id"), d->originId); + writer->writeEndElement(); } - } - // XEP-0184: Message Delivery Receipts - if (!d->receiptId.isEmpty()) { - xmlWriter->writeStartElement(QStringLiteral("received")); - xmlWriter->writeDefaultNamespace(ns_message_receipts); - xmlWriter->writeAttribute(QStringLiteral("id"), d->receiptId); - xmlWriter->writeEndElement(); - } - if (d->receiptRequested) { - xmlWriter->writeStartElement(QStringLiteral("request")); - xmlWriter->writeDefaultNamespace(ns_message_receipts); - xmlWriter->writeEndElement(); - } + // XEP-0369: Mediated Information eXchange (MIX) + if (!d->mixUserJid.isEmpty() || !d->mixUserNick.isEmpty()) { + writer->writeStartElement(QStringLiteral("mix")); + writer->writeDefaultNamespace(ns_mix); + helperToXmlAddTextElement(writer, QStringLiteral("jid"), d->mixUserJid); + helperToXmlAddTextElement(writer, QStringLiteral("nick"), d->mixUserNick); + writer->writeEndElement(); + } - // XEP-0224: Attention - if (d->attentionRequested) { - xmlWriter->writeStartElement(QStringLiteral("attention")); - xmlWriter->writeDefaultNamespace(ns_attention); - xmlWriter->writeEndElement(); - } + // XEP-0380: Explicit Message Encryption + if (!d->encryptionMethod.isEmpty()) { + writer->writeStartElement(QStringLiteral("encryption")); + writer->writeDefaultNamespace(ns_eme); + writer->writeAttribute(QStringLiteral("namespace"), d->encryptionMethod); + helperToXmlAddAttribute(writer, QStringLiteral("name"), d->encryptionName); + writer->writeEndElement(); + } - // XEP-0249: Direct MUC Invitations - if (!d->mucInvitationJid.isEmpty()) { - xmlWriter->writeStartElement(QStringLiteral("x")); - xmlWriter->writeDefaultNamespace(ns_conference); - xmlWriter->writeAttribute(QStringLiteral("jid"), d->mucInvitationJid); - if (!d->mucInvitationPassword.isEmpty()) - xmlWriter->writeAttribute(QStringLiteral("password"), d->mucInvitationPassword); - if (!d->mucInvitationReason.isEmpty()) - xmlWriter->writeAttribute(QStringLiteral("reason"), d->mucInvitationReason); - xmlWriter->writeEndElement(); + // XEP-0384: OMEMO Encryption + if (d->omemoElement) { + d->omemoElement->toXml(writer); + } + + // XEP-0428: Fallback Indication + if (d->isFallback) { + writer->writeStartElement(QStringLiteral("fallback")); + writer->writeDefaultNamespace(ns_fallback_indication); + writer->writeEndElement(); + } } - // XEP-0231: Bits of Binary - for (const auto &data : std::as_const(d->bitsOfBinaryData)) - data.toXmlElementFromChild(xmlWriter); + if (sceMode & QXmpp::SceSensitive) { + const auto writeTextElement = [writer, &baseNamespace](const QString &tagName, const QString &text) { + if (!text.isEmpty()) { + writer->writeStartElement(tagName); + if (!baseNamespace.isNull()) { + writer->writeDefaultNamespace(baseNamespace); + } + writer->writeCharacters(text); + writer->writeEndElement(); + } + }; - // XEP-0280: Message Carbons - if (d->privatemsg) { - xmlWriter->writeStartElement(QStringLiteral("private")); - xmlWriter->writeDefaultNamespace(ns_carbons); - xmlWriter->writeEndElement(); - } + // XMPP-Core + writeTextElement(QStringLiteral("subject"), d->subject); + writeTextElement(QStringLiteral("body"), d->body); - // XEP-0308: Last Message Correction - if (!d->replaceId.isEmpty()) { - xmlWriter->writeStartElement(QStringLiteral("replace")); - xmlWriter->writeDefaultNamespace(ns_message_correct); - xmlWriter->writeAttribute(QStringLiteral("id"), d->replaceId); - xmlWriter->writeEndElement(); - } + if (!d->thread.isEmpty()) { + writer->writeStartElement(QStringLiteral("thread")); + if (!baseNamespace.isNull()) { + writer->writeDefaultNamespace(baseNamespace); + } + helperToXmlAddAttribute(writer, QStringLiteral("parent"), d->parentThread); + writer->writeCharacters(d->thread); + writer->writeEndElement(); + } - // XEP-0333: Chat Markers - if (d->markable) { - xmlWriter->writeStartElement(QStringLiteral("markable")); - xmlWriter->writeDefaultNamespace(ns_chat_markers); - xmlWriter->writeEndElement(); - } - if (d->marker != NoMarker) { - xmlWriter->writeStartElement(MARKER_TYPES.at(d->marker)); - xmlWriter->writeDefaultNamespace(ns_chat_markers); - xmlWriter->writeAttribute(QStringLiteral("id"), d->markedId); - if (!d->markedThread.isNull() && !d->markedThread.isEmpty()) { - xmlWriter->writeAttribute(QStringLiteral("thread"), d->markedThread); + // XEP-0066: Out of Band Data + if (!d->outOfBandUrl.isEmpty()) { + writer->writeStartElement(QStringLiteral("x")); + writer->writeDefaultNamespace(ns_oob); + writer->writeTextElement(QStringLiteral("url"), d->outOfBandUrl); + writer->writeEndElement(); } - xmlWriter->writeEndElement(); - } - // XEP-0334: Message Processing Hints - for (quint8 i = 0; i < HINT_TYPES.size(); i++) { - if (hasHint(Hint(1 << i))) { - xmlWriter->writeStartElement(HINT_TYPES.at(i)); - xmlWriter->writeDefaultNamespace(ns_message_processing_hints); - xmlWriter->writeEndElement(); + // XEP-0071: XHTML-IM + if (!d->xhtml.isEmpty()) { + writer->writeStartElement(QStringLiteral("html")); + writer->writeDefaultNamespace(ns_xhtml_im); + writer->writeStartElement(QStringLiteral("body")); + writer->writeDefaultNamespace(ns_xhtml); + writer->writeCharacters(QStringLiteral("")); + writer->device()->write(d->xhtml.toUtf8()); + writer->writeEndElement(); + writer->writeEndElement(); } - } - // XEP-0359: Unique and Stable Stanza IDs - if (!d->stanzaId.isNull()) { - xmlWriter->writeStartElement(QStringLiteral("stanza-id")); - xmlWriter->writeDefaultNamespace(ns_sid); - xmlWriter->writeAttribute(QStringLiteral("id"), d->stanzaId); - if (!d->stanzaIdBy.isNull()) - xmlWriter->writeAttribute(QStringLiteral("by"), d->stanzaIdBy); - xmlWriter->writeEndElement(); - } + // XEP-0085: Chat State Notifications + if (d->state > None && d->state <= Paused) { + writer->writeStartElement(CHAT_STATES.at(d->state)); + writer->writeDefaultNamespace(ns_chat_states); + writer->writeEndElement(); + } - if (!d->originId.isNull()) { - xmlWriter->writeStartElement(QStringLiteral("origin-id")); - xmlWriter->writeDefaultNamespace(ns_sid); - xmlWriter->writeAttribute(QStringLiteral("id"), d->originId); - xmlWriter->writeEndElement(); - } + // XEP-0091: Legacy Delayed Delivery | XEP-0203: Delayed Delivery + if (d->stamp.isValid()) { + QDateTime utcStamp = d->stamp.toUTC(); + if (d->stampType == DelayedDelivery) { + // XEP-0203: Delayed Delivery + writer->writeStartElement(QStringLiteral("delay")); + writer->writeDefaultNamespace(ns_delayed_delivery); + helperToXmlAddAttribute(writer, QStringLiteral("stamp"), QXmppUtils::datetimeToString(utcStamp)); + writer->writeEndElement(); + } else { + // XEP-0091: Legacy Delayed Delivery + writer->writeStartElement(QStringLiteral("x")); + writer->writeDefaultNamespace(ns_legacy_delayed_delivery); + helperToXmlAddAttribute(writer, QStringLiteral("stamp"), utcStamp.toString(QStringLiteral("yyyyMMddThh:mm:ss"))); + writer->writeEndElement(); + } + } - // XEP-0367: Message Attaching - if (!d->attachId.isEmpty()) { - xmlWriter->writeStartElement(QStringLiteral("attach-to")); - xmlWriter->writeDefaultNamespace(ns_message_attaching); - xmlWriter->writeAttribute(QStringLiteral("id"), d->attachId); - xmlWriter->writeEndElement(); - } + // XEP-0184: Message Delivery Receipts + if (!d->receiptId.isEmpty()) { + writer->writeStartElement(QStringLiteral("received")); + writer->writeDefaultNamespace(ns_message_receipts); + writer->writeAttribute(QStringLiteral("id"), d->receiptId); + writer->writeEndElement(); + } + if (d->receiptRequested) { + writer->writeStartElement(QStringLiteral("request")); + writer->writeDefaultNamespace(ns_message_receipts); + writer->writeEndElement(); + } - // XEP-0369: Mediated Information eXchange (MIX) - if (!d->mixUserJid.isEmpty() || !d->mixUserNick.isEmpty()) { - xmlWriter->writeStartElement(QStringLiteral("mix")); - xmlWriter->writeDefaultNamespace(ns_mix); - helperToXmlAddTextElement(xmlWriter, QStringLiteral("jid"), d->mixUserJid); - helperToXmlAddTextElement(xmlWriter, QStringLiteral("nick"), d->mixUserNick); - xmlWriter->writeEndElement(); - } + // XEP-0224: Attention + if (d->attentionRequested) { + writer->writeStartElement(QStringLiteral("attention")); + writer->writeDefaultNamespace(ns_attention); + writer->writeEndElement(); + } - // XEP-0380: Explicit Message Encryption - if (!d->encryptionMethod.isEmpty()) { - xmlWriter->writeStartElement(QStringLiteral("encryption")); - xmlWriter->writeDefaultNamespace(ns_eme); - xmlWriter->writeAttribute(QStringLiteral("namespace"), d->encryptionMethod); - helperToXmlAddAttribute(xmlWriter, QStringLiteral("name"), d->encryptionName); - xmlWriter->writeEndElement(); - } + // XEP-0249: Direct MUC Invitations + if (!d->mucInvitationJid.isEmpty()) { + writer->writeStartElement(QStringLiteral("x")); + writer->writeDefaultNamespace(ns_conference); + writer->writeAttribute(QStringLiteral("jid"), d->mucInvitationJid); + if (!d->mucInvitationPassword.isEmpty()) + writer->writeAttribute(QStringLiteral("password"), d->mucInvitationPassword); + if (!d->mucInvitationReason.isEmpty()) + writer->writeAttribute(QStringLiteral("reason"), d->mucInvitationReason); + writer->writeEndElement(); + } - // XEP-0382: Spoiler messages - if (d->isSpoiler) { - xmlWriter->writeStartElement(QStringLiteral("spoiler")); - xmlWriter->writeDefaultNamespace(ns_spoiler); - xmlWriter->writeCharacters(d->spoilerHint); - xmlWriter->writeEndElement(); - } + // XEP-0231: Bits of Binary + for (const auto &data : std::as_const(d->bitsOfBinaryData)) + data.toXmlElementFromChild(writer); - // XEP-0384: OMEMO Encryption - if (d->omemoElement) { - d->omemoElement->toXml(xmlWriter); - } + // XEP-0308: Last Message Correction + if (!d->replaceId.isEmpty()) { + writer->writeStartElement(QStringLiteral("replace")); + writer->writeDefaultNamespace(ns_message_correct); + writer->writeAttribute(QStringLiteral("id"), d->replaceId); + writer->writeEndElement(); + } - // XEP-0407: Mediated Information eXchange (MIX): Miscellaneous Capabilities - if (d->mixInvitation) { - d->mixInvitation->toXml(xmlWriter); - } + // XEP-0333: Chat Markers + if (d->markable) { + writer->writeStartElement(QStringLiteral("markable")); + writer->writeDefaultNamespace(ns_chat_markers); + writer->writeEndElement(); + } + if (d->marker != NoMarker) { + writer->writeStartElement(MARKER_TYPES.at(d->marker)); + writer->writeDefaultNamespace(ns_chat_markers); + writer->writeAttribute(QStringLiteral("id"), d->markedId); + if (!d->markedThread.isNull() && !d->markedThread.isEmpty()) { + writer->writeAttribute(QStringLiteral("thread"), d->markedThread); + } + writer->writeEndElement(); + } - // XEP-0428: Fallback Indication - if (d->isFallback) { - xmlWriter->writeStartElement(QStringLiteral("fallback")); - xmlWriter->writeDefaultNamespace(ns_fallback_indication); - xmlWriter->writeEndElement(); - } + // XEP-0367: Message Attaching + if (!d->attachId.isEmpty()) { + writer->writeStartElement(QStringLiteral("attach-to")); + writer->writeDefaultNamespace(ns_message_attaching); + writer->writeAttribute(QStringLiteral("id"), d->attachId); + writer->writeEndElement(); + } - // XEP-0434: Trust Messages (TM) - if (d->trustMessageElement) { - d->trustMessageElement->toXml(xmlWriter); + // XEP-0382: Spoiler messages + if (d->isSpoiler) { + writer->writeStartElement(QStringLiteral("spoiler")); + writer->writeDefaultNamespace(ns_spoiler); + writer->writeCharacters(d->spoilerHint); + writer->writeEndElement(); + } + + // XEP-0407: Mediated Information eXchange (MIX): Miscellaneous Capabilities + if (d->mixInvitation) { + d->mixInvitation->toXml(writer); + } + + // XEP-0434: Trust Messages (TM) + if (d->trustMessageElement) { + d->trustMessageElement->toXml(writer); + } } } |
