From 7650b1b0aa057df686e7d44bae58eaeba03b9b93 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Fri, 28 Aug 2020 20:16:04 +0300 Subject: Jabber: MAM adaptation for OpenFire --- protocols/JabberG/src/jabber_mam.cpp | 30 ++++++++++++---- protocols/JabberG/src/jabber_proto.h | 1 + protocols/JabberG/src/jabber_thread.cpp | 61 +++++++++++++++++++-------------- 3 files changed, 59 insertions(+), 33 deletions(-) (limited to 'protocols/JabberG') diff --git a/protocols/JabberG/src/jabber_mam.cpp b/protocols/JabberG/src/jabber_mam.cpp index f369dcb0c4..4fb0359e93 100644 --- a/protocols/JabberG/src/jabber_mam.cpp +++ b/protocols/JabberG/src/jabber_mam.cpp @@ -69,13 +69,26 @@ void CJabberProto::MamSetMode(int iNewMode) void CJabberProto::MamRetrieveMissingMessages() { CMStringA szLastId = getMStringA("LastMamId"); - if (szLastId.IsEmpty()) - return; XmlNodeIq iq("set", SerialNext()); - auto *set = iq << XCHILDNS("query", JABBER_FEAT_MAM) << XCHILDNS("set", "http://jabber.org/protocol/rsm"); - set << XCHILD("max", "100"); - set << XCHILD("after", szLastId); + auto *query = iq << XCHILDNS("query", JABBER_FEAT_MAM); + + if (szLastId.IsEmpty()) { + m_bMamDisableMessages = true; // our goal is to save message id, not to store messages + + char buf[100]; + time2str(time(0), buf, _countof(buf)); + + auto *form = query << XCHILDNS("x", JABBER_FEAT_DATA_FORMS) << XATTR("type", "submit"); + form << XCHILD("field") << XATTR("var", "FORM_TYPE") << XATTR("type", "hidden") << XCHILD("value", JABBER_FEAT_MAM); + form << XCHILD("field") << XATTR("var", "end") << XCHILD("value", buf); + } + else { + auto *set = query << XCHILDNS("set", "http://jabber.org/protocol/rsm"); + set << XCHILD("max", "1000"); + set << XCHILD("after", szLastId); + } + m_ThreadInfo->send(iq); } @@ -84,6 +97,9 @@ void CJabberProto::MamRetrieveMissingMessages() void CJabberProto::OnIqResultRsm(const TiXmlElement *iqNode, CJabberIqInfo *pInfo) { + // even if that flag was enabled, unset it + m_bMamDisableMessages = false; + if (auto *fin = XmlGetChildByTag(iqNode, "fin", "xmlns", JABBER_FEAT_MAM)) { // if dataset is complete, there's nothing more to do if (!mir_strcmp(XmlGetAttr(fin, "complete"), "true")) @@ -98,7 +114,7 @@ void CJabberProto::OnIqResultRsm(const TiXmlElement *iqNode, CJabberIqInfo *pInf XmlNodeIq iq(pReq); auto *query = iq << XCHILDNS("query", JABBER_FEAT_MAM); - auto *x = query << XCHILDNS("x", "jabber:x:data") << XATTR("type", "submit"); + auto *x = query << XCHILDNS("x", JABBER_FEAT_DATA_FORMS) << XATTR("type", "submit"); x << XCHILD("var", "FORM_TYPE") << XATTR("type", "hidden") << XCHILD("value", JABBER_FEAT_MAM); x << XCHILD("var", "with") << XCHILD("value", jid); auto *rsm = query << XCHILDNS("set", "http://jabber.org/protocol/rsm"); @@ -128,7 +144,7 @@ INT_PTR __cdecl CJabberProto::OnMenuLoadHistory(WPARAM hContact, LPARAM) XmlNodeIq iq(pReq); auto *query = iq << XCHILDNS("query", JABBER_FEAT_MAM); - auto *x = query << XCHILDNS("x", "jabber:x:data") << XATTR("type", "submit"); + auto *x = query << XCHILDNS("x", JABBER_FEAT_DATA_FORMS) << XATTR("type", "submit"); x << XCHILD("var", "FORM_TYPE") << XATTR("type", "hidden") << XCHILD("value", JABBER_FEAT_MAM); x << XCHILD("var", "with") << XCHILD("value", jid); query << XCHILDNS("set", "http://jabber.org/protocol/rsm") << XCHILD("max", "100"); diff --git a/protocols/JabberG/src/jabber_proto.h b/protocols/JabberG/src/jabber_proto.h index c09b07ce34..64e17bb539 100755 --- a/protocols/JabberG/src/jabber_proto.h +++ b/protocols/JabberG/src/jabber_proto.h @@ -251,6 +251,7 @@ struct CJabberProto : public PROTO, public IJabberInterface bool m_bPepSupported; bool m_bStreamSent; bool m_bMamPrefsAvailable; + bool m_bMamDisableMessages; HWND m_hwndJabberChangePassword; HWND m_hwndPrivacyRule; diff --git a/protocols/JabberG/src/jabber_thread.cpp b/protocols/JabberG/src/jabber_thread.cpp index f295adbfc7..a9b3a6c78d 100755 --- a/protocols/JabberG/src/jabber_thread.cpp +++ b/protocols/JabberG/src/jabber_thread.cpp @@ -1005,18 +1005,49 @@ void CJabberProto::OnProcessMessage(const TiXmlElement *node, ThreadData *info) if (!node->Name() || mir_strcmp(node->Name(), "message")) return; - const char *from, *type = XmlGetAttr(node, "type"); - if ((from = XmlGetAttr(node, "from")) == nullptr) { + bool bEnableDelivery = true; + time_t msgTime = 0; + auto *from = XmlGetAttr(node, "from"), *type = XmlGetAttr(node, "type"), *idStr = XmlGetAttr(node, "id"); + const char *szMsgId = nullptr; // MAM support + + // check for MAM response + if (auto *mamResult = XmlGetChildByTag(node, "result", "xmlns", JABBER_FEAT_MAM)) { + szMsgId = XmlGetAttr(mamResult, "id"); + if (szMsgId) + setString("LastMamId", szMsgId); + + // we only collect ids, no need to store messages + if (m_bMamDisableMessages) + return; + + auto *xmlForwarded = XmlGetChildByTag(mamResult, "forwarded", "xmlns", JABBER_XMLNS_FORWARD); + if (auto *xmlMessage = XmlFirstChild(xmlForwarded, "message")) { + node = xmlMessage; + type = XmlGetAttr(node, "type"); + from = XmlGetAttr(node, "from"); + if (!mir_strcmpi(from, info->fullJID)) { + debugLogA("MAM: outgoing message from this machine (%s), ignored", from); + return; + } + } + + if (auto *xmlDelay = XmlGetChildByTag(xmlForwarded, "delay", "xmlns", JABBER_FEAT_DELAY)) + if (auto *ptszTimeStamp = XmlGetAttr(xmlDelay, "stamp")) + msgTime = JabberIsoToUnixTime(ptszTimeStamp); + + bEnableDelivery = false; + } + + if (from == nullptr) { debugLogA("no 'from' attribute, returning"); return; } - const char *idStr = XmlGetAttr(node, "id"); pResourceStatus pFromResource(ResourceInfoFromJID(from)); // Message receipts delivery request. Reply here, before a call to HandleMessagePermanent() to make sure message receipts are handled for external plugins too. bool bSendMark = false; - if ((!type || mir_strcmpi(type, "error"))) { + if (bEnableDelivery && (!type || mir_strcmpi(type, "error"))) { bool bSendReceipt = XmlGetChildByTag(node, "request", "xmlns", JABBER_FEAT_MESSAGE_RECEIPTS) != 0; bSendMark = XmlGetChildByTag(node, "markable", "xmlns", JABBER_FEAT_CHAT_MARKERS) != 0; if (bSendReceipt || bSendMark) { @@ -1040,8 +1071,6 @@ void CJabberProto::OnProcessMessage(const TiXmlElement *node, ThreadData *info) return; } - time_t msgTime = 0; - // Handle carbons. The message MUST be coming from our bare JID. const TiXmlElement *carbon = nullptr; bool carbonSent = false; //2 cases: received or sent. @@ -1087,24 +1116,6 @@ void CJabberProto::OnProcessMessage(const TiXmlElement *node, ThreadData *info) } } } - else { // check for MAM response - if (auto *mamResult = XmlGetChildByTag(node, "result", "xmlns", JABBER_FEAT_MAM)) { - auto *xmlForwarded = XmlGetChildByTag(mamResult, "forwarded", "xmlns", JABBER_XMLNS_FORWARD); - if (auto *xmlMessage = XmlFirstChild(xmlForwarded, "message")) { - node = xmlMessage; - type = XmlGetAttr(node, "type"); - from = XmlGetAttr(node, "from"); - if (!mir_strcmpi(from, info->fullJID)) { - debugLogA("MAM: outgoing message from this machine (%s), ignored", from); - return; - } - } - if (auto *xmlDelay = XmlGetChildByTag(xmlForwarded, "delay", "xmlns", JABBER_FEAT_DELAY)) { - if (auto *ptszTimeStamp = XmlGetAttr(xmlDelay, "stamp")) - msgTime = JabberIsoToUnixTime(ptszTimeStamp); - } - } - } } MCONTACT hContact = HContactFromJID(from); @@ -1146,8 +1157,6 @@ void CJabberProto::OnProcessMessage(const TiXmlElement *node, ThreadData *info) if (bodyNode != nullptr) szMessage.Append(bodyNode->GetText()); - // check MAM support - const char *szMsgId = nullptr; if (auto *n = XmlGetChildByTag(node, "stanza-id", "xmlns", JABBER_FEAT_SID)) if (szMsgId = n->Attribute("id")) setString("LastMamId", szMsgId); -- cgit v1.2.3