From 016a44540e5f937f2144cfea312e46b414c34420 Mon Sep 17 00:00:00 2001 From: George Hazan <ghazan@miranda.im> Date: Fri, 4 Sep 2020 19:23:29 +0300 Subject: Jabber: MAM code rework & optimization --- protocols/JabberG/src/jabber_mam.cpp | 66 +++++++++++++++++---------------- protocols/JabberG/src/jabber_proto.h | 3 +- protocols/JabberG/src/jabber_thread.cpp | 31 +++++++++++----- 3 files changed, 57 insertions(+), 43 deletions(-) (limited to 'protocols/JabberG') diff --git a/protocols/JabberG/src/jabber_mam.cpp b/protocols/JabberG/src/jabber_mam.cpp index dbdd1a67b3..9d5ba27b64 100644 --- a/protocols/JabberG/src/jabber_mam.cpp +++ b/protocols/JabberG/src/jabber_mam.cpp @@ -45,8 +45,8 @@ void CJabberProto::OnIqResultMamInfo(const TiXmlElement *iqNode, CJabberIqInfo * } // shall we retrieve missing messages? - // if (pInfo->GetUserData()) - // MamRetrieveMissingMessages(); + if (pInfo->GetUserData()) + MamRetrieveMissingMessages(); } void CJabberProto::MamSetMode(int iNewMode) @@ -75,6 +75,7 @@ void CJabberProto::MamRetrieveMissingMessages() if (szLastId.IsEmpty()) { m_bMamDisableMessages = true; // our goal is to save message id, not to store messages + m_bMamCreateRead = false; char buf[100]; time2str(time(0), buf, _countof(buf)); @@ -95,6 +96,27 @@ void CJabberProto::MamRetrieveMissingMessages() ///////////////////////////////////////////////////////////////////////////////////////// // Contact's history loader +void CJabberProto::MamSendForm(const char *pszWith, const char *pszAfter) +{ + auto *pReq = AddIQ(&CJabberProto::OnIqResultRsm, JABBER_IQ_TYPE_SET); + pReq->SetParamsToParse(JABBER_IQ_PARSE_FROM); + + XmlNodeIq iq(pReq); + auto *query = iq << XCHILDNS("query", JABBER_FEAT_MAM); + + 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); + if (pszWith != nullptr) + form << XCHILD("field") << XATTR("var", "with") << XCHILD("value", pszWith); + + auto *rsm = query << XCHILDNS("set", "http://jabber.org/protocol/rsm"); + rsm << XCHILD("max", "1000"); + if (pszAfter != nullptr) + rsm << XCHILD("after", pszAfter); + m_ThreadInfo->send(iq); +} + + void CJabberProto::OnIqResultRsm(const TiXmlElement *iqNode, CJabberIqInfo *pInfo) { // even if that flag was enabled, unset it @@ -105,23 +127,9 @@ void CJabberProto::OnIqResultRsm(const TiXmlElement *iqNode, CJabberIqInfo *pInf if (!mir_strcmp(XmlGetAttr(fin, "complete"), "true")) return; - auto *lastId = XmlGetChildText(fin, "last"); - if (lastId) { - ptrA jid(getUStringA(pInfo->GetHContact(), "jid")); - - auto *pReq = AddIQ(&CJabberProto::OnIqResultRsm, JABBER_IQ_TYPE_SET); - pReq->SetParamsToParse(JABBER_IQ_PARSE_FROM); - - XmlNodeIq iq(pReq); - auto *query = iq << XCHILDNS("query", JABBER_FEAT_MAM); - 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", "with") << XCHILD("value", jid); - auto *rsm = query << XCHILDNS("set", "http://jabber.org/protocol/rsm"); - rsm << XCHILD("max", "100"); - rsm << XCHILD("after", lastId); - m_ThreadInfo->send(iq); - } + if (auto *set = XmlGetChildByTag(fin, "set", "xmlns", "http://jabber.org/protocol/rsm")) + if (auto *lastId = XmlGetChildText(set, "last")) + MamSendForm(ptrA(getUStringA(pInfo->GetHContact(), "jid")), lastId); } } @@ -131,24 +139,18 @@ INT_PTR __cdecl CJabberProto::OnMenuLoadHistory(WPARAM hContact, LPARAM) return 0; // wipe out old history first - DB::ECPTR pCursor(DB::Events(hContact)); - while (pCursor.FetchNext()) - pCursor.DeleteEvent(); + if (IDYES == MessageBoxW(NULL, TranslateT("Do you want to erase local history before loading it from server?"), m_tszUserName, MB_YESNOCANCEL | MB_ICONQUESTION)) { + DB::ECPTR pCursor(DB::Events(hContact)); + while (pCursor.FetchNext()) + pCursor.DeleteEvent(); + } // load remaining items from server if (m_bJabberOnline) { ptrA jid(getUStringA(hContact, "jid")); if (jid != nullptr) { - auto *pReq = AddIQ(&CJabberProto::OnIqResultRsm, JABBER_IQ_TYPE_SET); - pReq->SetParamsToParse(JABBER_IQ_PARSE_FROM); - - XmlNodeIq iq(pReq); - auto *query = iq << XCHILDNS("query", JABBER_FEAT_MAM); - 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", "with") << XCHILD("value", jid); - query << XCHILDNS("set", "http://jabber.org/protocol/rsm") << XCHILD("max", "100"); - m_ThreadInfo->send(iq); + m_bMamCreateRead = true; + MamSendForm(jid); } } return 0; diff --git a/protocols/JabberG/src/jabber_proto.h b/protocols/JabberG/src/jabber_proto.h index 64e17bb539..9d78f99b63 100755 --- a/protocols/JabberG/src/jabber_proto.h +++ b/protocols/JabberG/src/jabber_proto.h @@ -251,7 +251,7 @@ struct CJabberProto : public PROTO<CJabberProto>, public IJabberInterface bool m_bPepSupported; bool m_bStreamSent; bool m_bMamPrefsAvailable; - bool m_bMamDisableMessages; + bool m_bMamDisableMessages, m_bMamCreateRead; HWND m_hwndJabberChangePassword; HWND m_hwndPrivacyRule; @@ -644,6 +644,7 @@ struct CJabberProto : public PROTO<CJabberProto>, public IJabberInterface void OnIqResultMamInfo(const TiXmlElement *iqNode, CJabberIqInfo *pInfo); void OnIqResultRsm(const TiXmlElement *iqNode, CJabberIqInfo *pInfo); + void MamSendForm(const char *pszWith, const char *pszAfter = nullptr); void MamRetrieveMissingMessages(void); void MamSetMode(int iNewMode); diff --git a/protocols/JabberG/src/jabber_thread.cpp b/protocols/JabberG/src/jabber_thread.cpp index a9b3a6c78d..2f1b96a73a 100755 --- a/protocols/JabberG/src/jabber_thread.cpp +++ b/protocols/JabberG/src/jabber_thread.cpp @@ -1005,8 +1005,8 @@ void CJabberProto::OnProcessMessage(const TiXmlElement *node, ThreadData *info) if (!node->Name() || mir_strcmp(node->Name(), "message")) return; - bool bEnableDelivery = true; time_t msgTime = 0; + bool bEnableDelivery = true, bCreateRead = false, bWasSent = false; auto *from = XmlGetAttr(node, "from"), *type = XmlGetAttr(node, "type"), *idStr = XmlGetAttr(node, "id"); const char *szMsgId = nullptr; // MAM support @@ -1025,17 +1025,28 @@ void CJabberProto::OnProcessMessage(const TiXmlElement *node, ThreadData *info) node = xmlMessage; type = XmlGetAttr(node, "type"); from = XmlGetAttr(node, "from"); - if (!mir_strcmpi(from, info->fullJID)) { + auto *to = XmlGetAttr(node, "to"); + + char szJid[JABBER_MAX_JID_LEN]; + JabberStripJid(from, szJid, _countof(szJid)); + if (!mir_strcmpi(szJid, m_szJabberJID)) { + bWasSent = true; + std::swap(from, to); + } + + // we disable message reading with our resource only for the missing messages + if (!m_bMamCreateRead && !mir_strcmpi(to, 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 *xmlDelay = XmlGetChildByTag(xmlForwarded, "delay", "xmlns", "urn:xmpp:delay")) if (auto *ptszTimeStamp = XmlGetAttr(xmlDelay, "stamp")) - msgTime = JabberIsoToUnixTime(ptszTimeStamp); + msgTime = str2time(ptszTimeStamp); bEnableDelivery = false; + bCreateRead = m_bMamCreateRead; } if (from == nullptr) { @@ -1073,12 +1084,11 @@ void CJabberProto::OnProcessMessage(const TiXmlElement *node, ThreadData *info) // Handle carbons. The message MUST be coming from our bare JID. const TiXmlElement *carbon = nullptr; - bool carbonSent = false; //2 cases: received or sent. if (IsMyOwnJID(from)) { carbon = XmlGetChildByTag(node, "received", "xmlns", JABBER_FEAT_CARBONS); if (!carbon) { if (carbon = XmlGetChildByTag(node, "sent", "xmlns", JABBER_FEAT_CARBONS)) - carbonSent = true; + bWasSent = true; } if (carbon) { // If carbons are disabled in options, we should ignore occasional carbons sent to us by server @@ -1087,6 +1097,7 @@ void CJabberProto::OnProcessMessage(const TiXmlElement *node, ThreadData *info) return; } + bCreateRead = true; auto *xmlForwarded = XmlGetChildByTag(carbon, "forwarded", "xmlns", JABBER_XMLNS_FORWARD); auto *xmlMessage = XmlFirstChild(xmlForwarded, "message"); // Carbons MUST have forwarded/message content @@ -1099,7 +1110,7 @@ void CJabberProto::OnProcessMessage(const TiXmlElement *node, ThreadData *info) node = xmlMessage; type = XmlGetAttr(node, "type"); - if (!carbonSent) { + if (!bWasSent) { // Received should just be treated like incoming messages, except maybe not flash the flasher. Simply unwrap. from = XmlGetAttr(node, "from"); if (from == nullptr) { @@ -1278,7 +1289,7 @@ void CJabberProto::OnProcessMessage(const TiXmlElement *node, ThreadData *info) return; } - if (carbon && carbonSent) + if (carbon && bWasSent) szMessage = TranslateU("Unable to decrypt a carbon copy of the encrypted outgoing message"); else { // XEP-0027 is not strict enough, different clients have different implementations @@ -1387,9 +1398,9 @@ void CJabberProto::OnProcessMessage(const TiXmlElement *node, ThreadData *info) msgTime = now; PROTORECVEVENT recv = {}; - if (carbon) { + if (bCreateRead) { recv.flags |= PREF_CREATEREAD; - if (carbonSent) + if (bWasSent) recv.flags |= PREF_SENT; } recv.timestamp = (DWORD)msgTime; -- cgit v1.2.3