summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xprotocols/JabberG/src/jabber_caps.cpp1
-rwxr-xr-xprotocols/JabberG/src/jabber_caps.h4
-rwxr-xr-xprotocols/JabberG/src/jabber_iqid.cpp3
-rwxr-xr-xprotocols/JabberG/src/jabber_proto.h2
-rwxr-xr-xprotocols/JabberG/src/jabber_thread.cpp53
5 files changed, 63 insertions, 0 deletions
diff --git a/protocols/JabberG/src/jabber_caps.cpp b/protocols/JabberG/src/jabber_caps.cpp
index 4b99b77219..83a13dcd39 100755
--- a/protocols/JabberG/src/jabber_caps.cpp
+++ b/protocols/JabberG/src/jabber_caps.cpp
@@ -76,6 +76,7 @@ const JabberFeatCapPair g_JabberFeatCapPairs[] = {
{ JABBER_FEAT_ROSTER_EXCHANGE, JABBER_CAPS_ROSTER_EXCHANGE, LPGENW("Supports Roster Exchange") },
{ JABBER_FEAT_DIRECT_MUC_INVITE, JABBER_CAPS_DIRECT_MUC_INVITE, LPGENW("Supports direct chat invitations (XEP-0249)") },
{ JABBER_FEAT_OMEMO_DEVICELIST_NOTIFY, JABBER_CAPS_OMEMO_DEVICELIST_NOTIFY, LPGENW("Receives information about OMEMO devices") },
+ { JABBER_FEAT_CARBONS, JABBER_CAPS_CARBONS, LPGENW("Supports message carbons (XEP-0280)")},
{ nullptr }
};
diff --git a/protocols/JabberG/src/jabber_caps.h b/protocols/JabberG/src/jabber_caps.h
index 66f033119d..fe69024b21 100755
--- a/protocols/JabberG/src/jabber_caps.h
+++ b/protocols/JabberG/src/jabber_caps.h
@@ -154,6 +154,9 @@ typedef unsigned __int64 JabberCapsBits;
#define JABBER_FEAT_PUBSUB_EVENT L"http://jabber.org/protocol/pubsub#event"
#define JABBER_FEAT_PUBSUB_NODE_CONFIG L"http://jabber.org/protocol/pubsub#node_config"
+#define JABBER_FEAT_CARBONS L"urn:xmpp:carbons:2"
+#define JABBER_CAPS_CARBONS ((JabberCapsBits)1<<43)
+
#define JABBER_CAPS_MESSAGE_EVENTS_NO_DELIVERY ((JabberCapsBits)1<<63)
#define JABBER_CAPS_OTHER_SPECIAL (JABBER_CAPS_MESSAGE_EVENTS_NO_DELIVERY|JABBER_RESOURCE_CAPS_ERROR) // must contain all the caps not listed in g_JabberFeatCapPairs, to prevent using these bits for features registered through IJabberNetInterface::RegisterFeature()
@@ -168,6 +171,7 @@ typedef unsigned __int64 JabberCapsBits;
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 L"urn:xmpp:forward:0"
#define JABBER_EXT_SECUREIM L"secureim"
#define JABBER_EXT_MIROTR L"mirotr"
diff --git a/protocols/JabberG/src/jabber_iqid.cpp b/protocols/JabberG/src/jabber_iqid.cpp
index da7c1260f6..4ecac9d48e 100755
--- a/protocols/JabberG/src/jabber_iqid.cpp
+++ b/protocols/JabberG/src/jabber_iqid.cpp
@@ -135,6 +135,9 @@ void CJabberProto::OnProcessLoginRq(ThreadData *info, DWORD rq)
if (info->jabberServerCaps & JABBER_CAPS_ARCHIVE_AUTO)
EnableArchive(m_options.EnableMsgArchive != 0);
+ if (info->jabberServerCaps & JABBER_CAPS_CARBONS)
+ EnableCarbons(true);
+
if (m_options.AutoJoinBookmarks) {
LIST<JABBER_LIST_ITEM> ll(10);
LISTFOREACH(i, this, LIST_BOOKMARK)
diff --git a/protocols/JabberG/src/jabber_proto.h b/protocols/JabberG/src/jabber_proto.h
index b04f639967..350b5e438c 100755
--- a/protocols/JabberG/src/jabber_proto.h
+++ b/protocols/JabberG/src/jabber_proto.h
@@ -737,6 +737,8 @@ struct CJabberProto : public PROTO<CJabberProto>, public IJabberInterface
bool ProcessCaptcha(HXML node, HXML parentNode, ThreadData *info);
+ void EnableCarbons(bool bEnable);
+
//---- jabber_util.c -----------------------------------------------------------------
pResourceStatus ResourceInfoFromJID(const wchar_t *jid);
diff --git a/protocols/JabberG/src/jabber_thread.cpp b/protocols/JabberG/src/jabber_thread.cpp
index 60cf077661..1177020ab0 100755
--- a/protocols/JabberG/src/jabber_thread.cpp
+++ b/protocols/JabberG/src/jabber_thread.cpp
@@ -1051,6 +1051,43 @@ void CJabberProto::OnProcessMessage(HXML node, ThreadData *info)
if (m_messageManager.HandleMessagePermanent(node, info))
return;
+ //Handle carbons. The message MUST be coming from our bare JID.
+ HXML carbon = nullptr;
+ bool carbonSent = false; //2 cases: received or sent.
+ if (this->IsMyOwnJID(from)) {
+ carbon = XmlGetChildByTag(node, "received", "xmlns", JABBER_FEAT_CARBONS);
+ if (!carbon) {
+ carbon = XmlGetChildByTag(node, "sent", "xmlns", JABBER_FEAT_CARBONS);
+ if (carbon)
+ carbonSent = true;
+ }
+ if (carbon) {
+ HXML forwarded = NULL;
+ HXML message = NULL;
+ //Carbons MUST have forwarded/message content
+ if (!(forwarded = XmlGetChildByTag(carbon, "forwarded", "xmlns", JABBER_XMLNS_FORWARD))
+ || !(message = XmlGetChild(forwarded, "message")))
+ return;
+
+ //Unwrap the carbon in any case
+ node = message;
+ type = XmlGetAttrValue(node, L"type");
+
+ if (!carbonSent) {
+ //Received should just be treated like incoming messages, except maybe not flash the flasher. Simply unwrap.
+ from = XmlGetAttrValue(node, L"from");
+ if (from == nullptr)
+ return;
+ }
+ else {
+ //Sent should set SENT flag and invert from/to.
+ from = XmlGetAttrValue(node, L"to");
+ if (from == nullptr)
+ return;
+ }
+ }
+ }
+
MCONTACT hContact = HContactFromJID(from);
JABBER_LIST_ITEM *chatItem = ListGetItemPtr(LIST_CHATROOM, from);
if (chatItem) {
@@ -1416,6 +1453,11 @@ void CJabberProto::OnProcessMessage(HXML node, ThreadData *info)
msgTime = now;
PROTORECVEVENT recv = { 0 };
+ if (carbon) {
+ recv.flags |= PREF_CREATEREAD;
+ if (carbonSent)
+ recv.flags |= PREF_SENT;
+ }
recv.timestamp = (DWORD)msgTime;
recv.szMessage = buf;
recv.lParam = (LPARAM)((pFromResource != nullptr && m_options.EnableRemoteControl) ? pFromResource->m_tszResourceName : 0);
@@ -1941,6 +1983,17 @@ void CJabberProto::OnProcessRegIq(HXML node, ThreadData *info)
}
}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Carbons -- this might need to go into its own module
+
+void CJabberProto::EnableCarbons(bool bEnable)
+{
+ m_ThreadInfo->send(XmlNodeIq(L"set", SerialNext())
+ << XCHILDNS((bEnable) ? L"enable" : L"disable", JABBER_FEAT_CARBONS));
+}
+
+
/////////////////////////////////////////////////////////////////////////////////////////
// ThreadData constructor & destructor