summaryrefslogtreecommitdiff
path: root/protocols/JabberG
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2020-06-11 22:20:11 +0300
committerGeorge Hazan <ghazan@miranda.im>2020-06-11 22:20:18 +0300
commit5fb805622a3a3368ffb3de0c649074376e70256a (patch)
tree64f0149c8e5d692cf19e5fcebb60b0fba59e3d93 /protocols/JabberG
parente6bf9c2a41622424c2cd4006326455e08c80812a (diff)
fixes #1149 (XMPP/Jabber: Implement XEP-0313 ( mam / Message Archive Management )
Diffstat (limited to 'protocols/JabberG')
-rwxr-xr-xprotocols/JabberG/jabber.vcxproj1
-rwxr-xr-xprotocols/JabberG/jabber.vcxproj.filters3
-rw-r--r--protocols/JabberG/res/jabber.rc21
-rwxr-xr-xprotocols/JabberG/src/jabber_caps.cpp1
-rwxr-xr-xprotocols/JabberG/src/jabber_caps.h7
-rwxr-xr-xprotocols/JabberG/src/jabber_iqid.cpp10
-rw-r--r--protocols/JabberG/src/jabber_mam.cpp78
-rwxr-xr-xprotocols/JabberG/src/jabber_opt.cpp14
-rwxr-xr-xprotocols/JabberG/src/jabber_proto.cpp1
-rwxr-xr-xprotocols/JabberG/src/jabber_proto.h44
-rwxr-xr-xprotocols/JabberG/src/jabber_thread.cpp27
-rw-r--r--protocols/JabberG/src/resource.h3
12 files changed, 175 insertions, 35 deletions
diff --git a/protocols/JabberG/jabber.vcxproj b/protocols/JabberG/jabber.vcxproj
index 9495f2516f..7eb80b6e17 100755
--- a/protocols/JabberG/jabber.vcxproj
+++ b/protocols/JabberG/jabber.vcxproj
@@ -51,6 +51,7 @@
<ClCompile Include="src\jabber_iq_handlers.cpp" />
<ClCompile Include="src\jabber_libstr.cpp" />
<ClCompile Include="src\jabber_list.cpp" />
+ <ClCompile Include="src\jabber_mam.cpp" />
<ClCompile Include="src\jabber_menu.cpp" />
<ClCompile Include="src\jabber_message_handlers.cpp" />
<ClCompile Include="src\jabber_message_manager.cpp" />
diff --git a/protocols/JabberG/jabber.vcxproj.filters b/protocols/JabberG/jabber.vcxproj.filters
index 72b6943026..3a72f63b4b 100755
--- a/protocols/JabberG/jabber.vcxproj.filters
+++ b/protocols/JabberG/jabber.vcxproj.filters
@@ -164,6 +164,9 @@
<ClCompile Include="src\stdafx.cxx">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="src\jabber_mam.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\jabber_byte.h">
diff --git a/protocols/JabberG/res/jabber.rc b/protocols/JabberG/res/jabber.rc
index 6280d2c403..5e6bb8a04e 100644
--- a/protocols/JabberG/res/jabber.rc
+++ b/protocols/JabberG/res/jabber.rc
@@ -91,7 +91,7 @@ BEGIN
PUSHBUTTON "Export to file",IDC_EXPORT,272,268,71,15
END
-IDD_OPT_JABBER DIALOGEX 0, 0, 304, 208
+IDD_OPT_JABBER DIALOGEX 0, 0, 304, 222
STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
EXSTYLE WS_EX_CONTROLPARENT
FONT 8, "MS Shell Dlg", 0, 0, 0x1
@@ -103,6 +103,7 @@ BEGIN
EDITTEXT IDC_EDIT_PASSWORD,66,30,86,12,ES_PASSWORD | ES_AUTOHSCROLL
PUSHBUTTON "Change password",IDC_BUTTON_CHANGE_PASSWORD,156,30,78,13
CONTROL "Save password",IDC_SAVEPASSWORD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,66,45,89,10
+ CONTROL "Use Domain Login",IDC_USEDOMAINLOGIN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,157,45,137,9
LTEXT "Priority:",IDC_PRIORITY_LABEL,12,59,41,8
EDITTEXT IDC_PRIORITY,66,57,85,12,ES_AUTOHSCROLL
CONTROL "Spin1",IDC_PRIORITY_SPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_NOTHOUSANDS,151,57,12,12
@@ -120,18 +121,19 @@ BEGIN
CONTROL "Use TLS",IDC_USE_TLS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,189,100,97,10
PUSHBUTTON "Register new user",IDC_BUTTON_REGISTER,156,16,78,13
PUSHBUTTON "Unregister",IDC_UNREGISTER,235,16,56,13
- GROUPBOX "Expert",IDC_STATIC,4,120,295,85
+ GROUPBOX "Expert",IDC_STATIC,4,120,295,99
CONTROL "Manually specify connection host",IDC_MANUAL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,134,223,10
RTEXT "Host:",IDC_STATIC,26,147,30,8
EDITTEXT IDC_HOST,57,145,90,12,ES_AUTOHSCROLL | WS_DISABLED
RTEXT "Port:",IDC_STATIC,156,147,27,8
EDITTEXT IDC_HOSTPORT,186,145,31,12,ES_AUTOHSCROLL | ES_NUMBER | WS_DISABLED
- CONTROL "Keep connection alive",IDC_KEEPALIVE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,158,221,10
+ CONTROL "Keep connection alive",IDC_KEEPALIVE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,159,283,10
CONTROL "Automatically delete contacts not in my roster",IDC_ROSTER_SYNC,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,172,221,10
- LTEXT "Language for human-readable resources:",IDC_MSGLANG_LABEL,11,188,170,8
- COMBOBOX IDC_MSGLANG,188,186,103,69,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
- CONTROL "Use Domain Login",IDC_USEDOMAINLOGIN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,157,45,137,9
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,172,283,10
+ LTEXT "History recording mode",IDC_STATIC,12,187,170,8
+ COMBOBOX IDC_MAM_MODE,188,185,103,69,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Language for human-readable resources:",IDC_MSGLANG_LABEL,11,202,170,8
+ COMBOBOX IDC_MSGLANG,188,200,103,69,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
END
IDD_OPT_JABBER2 DIALOGEX 0, 0, 304, 228
@@ -712,6 +714,11 @@ BEGIN
BEGIN
END
+ IDD_OPT_JABBER, DIALOG
+ BEGIN
+ BOTTOMMARGIN, 208
+ END
+
IDD_OPT_REGISTER, DIALOG
BEGIN
RIGHTMARGIN, 165
diff --git a/protocols/JabberG/src/jabber_caps.cpp b/protocols/JabberG/src/jabber_caps.cpp
index d1e8b987f9..bce11fb61f 100755
--- a/protocols/JabberG/src/jabber_caps.cpp
+++ b/protocols/JabberG/src/jabber_caps.cpp
@@ -68,6 +68,7 @@ const JabberFeatCapPair g_JabberFeatCapPairs[] =
{ JABBER_FEAT_USER_TUNE_NOTIFY, JABBER_CAPS_USER_TUNE_NOTIFY, LPGEN("Receives information about the music to which a user is listening") },
{ JABBER_FEAT_PRIVATE_STORAGE, JABBER_CAPS_PRIVATE_STORAGE, LPGEN("Supports private XML Storage (for bookmarks and other)") },
{ JABBER_FEAT_ATTENTION, JABBER_CAPS_ATTENTION, LPGEN("Supports attention requests ('nudge')") },
+ { JABBER_FEAT_MAM, JABBER_CAPS_MAM, LPGEN("Support Message Archive Management (XEP-0313)") },
{ JABBER_FEAT_USER_ACTIVITY, JABBER_CAPS_USER_ACTIVITY, LPGEN("Can report information about user activity") },
{ JABBER_FEAT_USER_ACTIVITY_NOTIFY, JABBER_CAPS_USER_ACTIVITY_NOTIFY, LPGEN("Receives information about user activity") },
{ JABBER_FEAT_MIRANDA_NOTES, JABBER_CAPS_MIRANDA_NOTES, LPGEN("Supports Miranda NG notes extension") },
diff --git a/protocols/JabberG/src/jabber_caps.h b/protocols/JabberG/src/jabber_caps.h
index 052ee09cf5..980ff36777 100755
--- a/protocols/JabberG/src/jabber_caps.h
+++ b/protocols/JabberG/src/jabber_caps.h
@@ -144,6 +144,9 @@ typedef unsigned __int64 JabberCapsBits;
#define JABBER_FEAT_PRIVATE_STORAGE "jabber:iq:private"
#define JABBER_CAPS_PRIVATE_STORAGE ((JabberCapsBits)1<<33)
+#define JABBER_FEAT_MAM "urn:xmpp:mam:2"
+#define JABBER_CAPS_MAM ((JabberCapsBits)1<<34)
+
#define JABBER_FEAT_ATTENTION "urn:xmpp:attention:0"
#define JABBER_CAPS_ATTENTION ((JabberCapsBits)1<<36)
@@ -211,8 +214,8 @@ typedef unsigned __int64 JabberCapsBits;
JABBER_CAPS_ROSTER_EXCHANGE | JABBER_CAPS_DIRECT_MUC_INVITE | JABBER_CAPS_CHAT_MARKERS | JABBER_CAPS_BITS | JABBER_CAPS_XHTML)
#define JABBER_CAPS_MIRANDA_ALL (JABBER_CAPS_MIRANDA_PARTIAL | JABBER_CAPS_COMMANDS | \
- JABBER_CAPS_USER_MOOD_NOTIFY | JABBER_CAPS_USER_TUNE_NOTIFY | JABBER_CAPS_USER_ACTIVITY_NOTIFY \
- | JABBER_CAPS_PLATFORMX86 | JABBER_CAPS_PLATFORMX64)
+ JABBER_CAPS_USER_MOOD_NOTIFY | JABBER_CAPS_USER_TUNE_NOTIFY | JABBER_CAPS_USER_ACTIVITY_NOTIFY | \
+ JABBER_CAPS_PLATFORMX86 | JABBER_CAPS_PLATFORMX64)
#define JABBER_XMLNS_FORWARD "urn:xmpp:forward:0"
diff --git a/protocols/JabberG/src/jabber_iqid.cpp b/protocols/JabberG/src/jabber_iqid.cpp
index e342f39410..bdaa73dc5d 100755
--- a/protocols/JabberG/src/jabber_iqid.cpp
+++ b/protocols/JabberG/src/jabber_iqid.cpp
@@ -123,10 +123,14 @@ void CJabberProto::OnProcessLoginRq(ThreadData *info, DWORD rq)
DWORD dwMask = JABBER_LOGIN_ROSTER | JABBER_LOGIN_BOOKMARKS | JABBER_LOGIN_SERVERINFO;
if ((info->dwLoginRqs & dwMask) == dwMask && !(info->dwLoginRqs & JABBER_LOGIN_BOOKMARKS_AJ)) {
- if (info->jabberServerCaps & JABBER_CAPS_CARBONS) {
- // Server seems to support carbon copies, let's enable/disable them
+
+ // Server seems to support carbon copies, let's enable/disable them
+ if (info->jabberServerCaps & JABBER_CAPS_CARBONS)
m_ThreadInfo->send(XmlNodeIq("set", SerialNext()) << XCHILDNS((m_bEnableCarbons) ? "enable" : "disable", JABBER_FEAT_CARBONS));
- }
+
+ // Server seems to support MAM, let's retrieve MAM settings
+ if (info->jabberServerCaps & JABBER_CAPS_MAM)
+ m_ThreadInfo->send(XmlNodeIq(AddIQ(&CJabberProto::OnIqResultMamInfo, JABBER_IQ_TYPE_GET, 0, this)) << XCHILDNS("prefs", JABBER_FEAT_MAM));
if (m_bAutoJoinBookmarks) {
LIST<JABBER_LIST_ITEM> ll(10);
diff --git a/protocols/JabberG/src/jabber_mam.cpp b/protocols/JabberG/src/jabber_mam.cpp
new file mode 100644
index 0000000000..41a3482119
--- /dev/null
+++ b/protocols/JabberG/src/jabber_mam.cpp
@@ -0,0 +1,78 @@
+/*
+
+Jabber Protocol Plugin for Miranda NG
+
+Copyright (c) 2002-04 Santithorn Bunchua
+Copyright (c) 2005-12 George Hazan
+Copyright (c) 2007 Maxim Mluhov
+Copyright (C) 2012-20 Miranda NG team
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "stdafx.h"
+#include "jabber_iq.h"
+#include "jabber_caps.h"
+
+void CJabberProto::OnIqResultMamInfo(const TiXmlElement *iqNode, CJabberIqInfo *pInfo)
+{
+ if (pInfo->GetIqType() != JABBER_IQ_TYPE_RESULT)
+ return;
+
+ if (auto *n = XmlFirstChild(iqNode, "prefs")) {
+ if (auto *type = n->Attribute("default")) {
+ if (!strcmp(type, "never"))
+ m_iMamMode = 0;
+ else if (!strcmp(type, "roster"))
+ m_iMamMode = 1;
+ else
+ m_iMamMode = 2;
+ }
+ }
+
+ // shall we retrieve missing messages?
+ if (pInfo->GetUserData())
+ MamRetrieveMissingMessages();
+}
+
+void CJabberProto::MamSetMode(int iNewMode)
+{
+ const char *szMode;
+ switch (iNewMode) {
+ case 0: szMode = "never"; break;
+ case 1: szMode = "roster"; break;
+ default: szMode = "always"; break;
+ }
+
+ XmlNodeIq iq(AddIQ(&CJabberProto::OnIqResultMamInfo, JABBER_IQ_TYPE_SET));
+ auto *node = iq << XCHILDNS("prefs", JABBER_FEAT_MAM) << XATTR("default", szMode);
+ node << XCHILD("always"); node << XCHILD("never");
+ m_ThreadInfo->send(iq);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CJabberProto::MamRetrieveMissingMessages()
+{
+ CMStringA szLastId = getMStringA("LastMamId");
+
+ XmlNodeIq iq("set", SerialNext());
+ auto *set = iq << XCHILDNS("query", JABBER_FEAT_MAM) << XCHILDNS("set", "http://jabber.org/protocol/rsm");
+ set << XCHILD("max", "100");
+ if (!szLastId.IsEmpty())
+ set << XCHILD("after", szLastId);
+ m_ThreadInfo->send(iq);
+}
diff --git a/protocols/JabberG/src/jabber_opt.cpp b/protocols/JabberG/src/jabber_opt.cpp
index 7ee006d64b..65d95086e9 100755
--- a/protocols/JabberG/src/jabber_opt.cpp
+++ b/protocols/JabberG/src/jabber_opt.cpp
@@ -348,7 +348,7 @@ class CDlgOptAccount : public CJabberDlgBase
CCtrlEdit m_txtManualPort;
CCtrlCheck m_chkKeepAlive;
CCtrlCheck m_chkAutoDeleteContacts;
- CCtrlCombo m_cbLocale;
+ CCtrlCombo m_cbLocale, m_cbMam;
CCtrlButton m_btnRegister;
CCtrlButton m_btnUnregister;
CCtrlButton m_btnChangePassword;
@@ -364,6 +364,7 @@ public:
m_cbResource(this, IDC_COMBO_RESOURCE),
m_chkUseHostnameAsResource(this, IDC_HOSTNAME_AS_RESOURCE),
m_chkUseDomainLogin(this, IDC_USEDOMAINLOGIN),
+ m_cbMam(this, IDC_MAM_MODE),
m_cbServer(this, IDC_EDIT_LOGIN_SERVER),
m_txtPort(this, IDC_PORT),
m_chkUseSsl(this, IDC_USE_SSL),
@@ -429,6 +430,14 @@ protected:
for (auto &it : szResources)
m_cbResource.AddString(it);
+
+ // fill MAM modes
+ wchar_t *szMamModes[] = { LPGENW("Never"), LPGENW("Roster"), LPGENW("Always") };
+ for (auto &it : szMamModes)
+ m_cbMam.AddString(it, int(&it - szMamModes));
+ m_cbMam.SetCurSel(m_proto->m_iMamMode);
+ m_cbMam.Enable(m_proto->m_ThreadInfo && (m_proto->m_ThreadInfo->jabberServerCaps & JABBER_CAPS_MAM));
+
// append computer name to the resource list
wchar_t szCompName[MAX_COMPUTERNAME_LENGTH + 1];
DWORD dwCompNameLength = MAX_COMPUTERNAME_LENGTH;
@@ -488,6 +497,9 @@ protected:
}
}
+ if (m_cbMam.Enabled() && m_cbMam.GetCurSel() != m_proto->m_iMamMode)
+ m_proto->MamSetMode(m_cbMam.GetCurSel());
+
sttStoreJidFromUI(m_proto, m_txtUsername, m_cbServer);
if (m_proto->m_bJabberOnline) {
diff --git a/protocols/JabberG/src/jabber_proto.cpp b/protocols/JabberG/src/jabber_proto.cpp
index 349d68646b..5c496b1e6f 100755
--- a/protocols/JabberG/src/jabber_proto.cpp
+++ b/protocols/JabberG/src/jabber_proto.cpp
@@ -129,6 +129,7 @@ CJabberProto::CJabberProto(const char *aProtoName, const wchar_t *aUserName) :
m_bUseSSL(this, "UseSSL", false),
m_bUseTLS(this, "UseTLS", true),
+ m_iMamMode(this, "MamMode", 0),
m_iConnectionKeepAliveInterval(this, "ConnectionKeepAliveInterval", 60000),
m_iConnectionKeepAliveTimeout(this, "ConnectionKeepAliveTimeout", 50000)
{
diff --git a/protocols/JabberG/src/jabber_proto.h b/protocols/JabberG/src/jabber_proto.h
index 32fcd80d64..f6a292029e 100755
--- a/protocols/JabberG/src/jabber_proto.h
+++ b/protocols/JabberG/src/jabber_proto.h
@@ -224,6 +224,7 @@ struct CJabberProto : public PROTO<CJabberProto>, public IJabberInterface
CMOption<bool> m_bUseSSL;
CMOption<bool> m_bUseTLS;
+ CMOption<int> m_iMamMode;
CMOption<DWORD> m_iConnectionKeepAliveInterval;
CMOption<DWORD> m_iConnectionKeepAliveTimeout;
@@ -419,24 +420,6 @@ struct CJabberProto : public PROTO<CJabberProto>, public IJabberInterface
void AddMucListItem(JABBER_MUC_JIDLIST_INFO* jidListInfo, const char *str, const char *reason);
void DeleteMucListItem(JABBER_MUC_JIDLIST_INFO* jidListInfo, const char* jid);
- //---- jabber_omemo.cpp --------------------------------------------------------------
-
- bool OmemoHandleMessage(const TiXmlElement *node, const char *jid, time_t msgTime);
- void OmemoPutMessageToOutgoingQueue(MCONTACT hContact, int, const char* pszSrc);
- void OmemoPutMessageToIncommingQueue(const TiXmlElement *node, const char *jid, time_t msgTime);
- void OmemoHandleMessageQueue();
- void OmemoHandleDeviceList(const TiXmlElement *node);
- void OmemoInitDevice();
- void OmemoAnnounceDevice();
- void OmemoSendBundle();
- void OmemoPublishNodes();
- bool OmemoCheckSession(MCONTACT hContact);
- int OmemoEncryptMessage(XmlNode &msg, const char *msg_text, MCONTACT hContact);
- bool OmemoIsEnabled(MCONTACT hContact);
- void OmemoOnIqResultGetBundle(const TiXmlElement *iqNode, CJabberIqInfo *pInfo);
-
- omemo::omemo_impl m_omemo;
-
//---- jabber_console.cpp ------------------------------------------------------------
INT_PTR __cdecl OnMenuHandleConsole(WPARAM wParam, LPARAM lParam);
@@ -639,6 +622,13 @@ struct CJabberProto : public PROTO<CJabberProto>, public IJabberInterface
void SetBookmarkRequest(XmlNodeIq &iqId);
void UpdateItem(JABBER_LIST_ITEM *pItem, const char *name);
+ //---- jabber_mam.cpp ----------------------------------------------------------------
+
+ void OnIqResultMamInfo(const TiXmlElement *iqNode, CJabberIqInfo *pInfo);
+
+ void MamRetrieveMissingMessages(void);
+ void MamSetMode(int iNewMode);
+
//---- jabber_menu.cpp ---------------------------------------------------------------
INT_PTR __cdecl OnMenuHandleRequestAuth(WPARAM wParam, LPARAM lParam);
@@ -686,6 +676,24 @@ struct CJabberProto : public PROTO<CJabberProto>, public IJabberInterface
CMStringA ExtractImage(const TiXmlElement *node);
const char* GetSoftName(const char *wszName);
+ //---- jabber_omemo.cpp --------------------------------------------------------------
+
+ bool OmemoHandleMessage(const TiXmlElement *node, const char *jid, time_t msgTime);
+ void OmemoPutMessageToOutgoingQueue(MCONTACT hContact, int, const char *pszSrc);
+ void OmemoPutMessageToIncommingQueue(const TiXmlElement *node, const char *jid, time_t msgTime);
+ void OmemoHandleMessageQueue();
+ void OmemoHandleDeviceList(const TiXmlElement *node);
+ void OmemoInitDevice();
+ void OmemoAnnounceDevice();
+ void OmemoSendBundle();
+ void OmemoPublishNodes();
+ bool OmemoCheckSession(MCONTACT hContact);
+ int OmemoEncryptMessage(XmlNode &msg, const char *msg_text, MCONTACT hContact);
+ bool OmemoIsEnabled(MCONTACT hContact);
+ void OmemoOnIqResultGetBundle(const TiXmlElement *iqNode, CJabberIqInfo *pInfo);
+
+ omemo::omemo_impl m_omemo;
+
//---- jabber_password.cpp --------------------------------------------------------------
INT_PTR __cdecl OnMenuHandleChangePassword(WPARAM wParam, LPARAM lParam);
diff --git a/protocols/JabberG/src/jabber_thread.cpp b/protocols/JabberG/src/jabber_thread.cpp
index 30a2128c29..57b3727c90 100755
--- a/protocols/JabberG/src/jabber_thread.cpp
+++ b/protocols/JabberG/src/jabber_thread.cpp
@@ -1078,6 +1078,8 @@ 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.
@@ -1124,6 +1126,20 @@ 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 (auto *xmlDelay = XmlGetChildByTag(xmlForwarded, "delay", "xmlns", JABBER_FEAT_DELAY)) {
+ if (auto *ptszTimeStamp = XmlGetAttr(xmlDelay, "stamp"))
+ msgTime = JabberIsoToUnixTime(ptszTimeStamp);
+ }
+ }
+ }
}
MCONTACT hContact = HContactFromJID(from);
@@ -1168,15 +1184,14 @@ void CJabberProto::OnProcessMessage(const TiXmlElement *node, ThreadData *info)
// check MAM support
const char *szMsgId = nullptr;
if (auto *n = XmlGetChildByTag(node, "stanza-id", "xmlns", JABBER_FEAT_SID))
- szMsgId = n->GetText();
+ if (szMsgId = n->Attribute("id"))
+ setString("LastMamId", szMsgId);
// If message is from a stranger (not in roster), item is nullptr
JABBER_LIST_ITEM *item = ListGetItemPtr(LIST_ROSTER, from);
if (item == nullptr)
item = ListGetItemPtr(LIST_VCARD_TEMP, from);
- time_t msgTime = 0;
-
// check chatstates availability
if (pFromResource && XmlGetChildByTag(node, "active", "xmlns", JABBER_FEAT_CHATSTATES))
pFromResource->m_jcbManualDiscoveredCaps |= JABBER_CAPS_CHATSTATES;
@@ -1370,6 +1385,12 @@ void CJabberProto::OnProcessMessage(const TiXmlElement *node, ThreadData *info)
return;
}
+ // we ignore messages without server id either if MAM is enabled
+ if ((info->jabberServerCaps & JABBER_CAPS_MAM) && m_iMamMode != 0 && szMsgId == nullptr) {
+ debugLogA("MAM is enabled, but there's no stanza-id: ignoting a message");
+ return;
+ }
+
szMessage.Replace("\n", "\r\n");
if (item != nullptr) {
diff --git a/protocols/JabberG/src/resource.h b/protocols/JabberG/src/resource.h
index a3e3f5987f..ae97f821f8 100644
--- a/protocols/JabberG/src/resource.h
+++ b/protocols/JabberG/src/resource.h
@@ -114,9 +114,10 @@
#define IDC_MSGLANG 1049
#define IDC_PASSWORD 1050
#define IDC_JID 1051
-#define IDC_NEWPASSWD2 1052
#define IDC_ROSTER_SYNC 1052
#define IDC_OLDPASSWD 1053
+#define IDC_MAM_MODE 1054
+#define IDC_NEWPASSWD2 1055
#define IDC_ADDRESS1 1056
#define IDC_ADDRESS2 1057
#define IDC_CITY 1058