From 0d54e69d920faef14771c45d75b03bf50824f2bc Mon Sep 17 00:00:00 2001
From: George Hazan <ghazan@miranda.im>
Date: Thu, 1 Sep 2022 18:23:46 +0300
Subject: Jabber: fix for XEP-0198 processing

---
 protocols/JabberG/src/jabber_proto.h       |  1 +
 protocols/JabberG/src/jabber_strm_mgmt.cpp |  5 +++
 protocols/JabberG/src/jabber_strm_mgmt.h   |  1 +
 protocols/JabberG/src/jabber_thread.cpp    | 60 ++++++++++++++++++++----------
 4 files changed, 47 insertions(+), 20 deletions(-)

(limited to 'protocols/JabberG/src')

diff --git a/protocols/JabberG/src/jabber_proto.h b/protocols/JabberG/src/jabber_proto.h
index dfd9fb9dcd..daed6fa219 100644
--- a/protocols/JabberG/src/jabber_proto.h
+++ b/protocols/JabberG/src/jabber_proto.h
@@ -814,6 +814,7 @@ struct CJabberProto : public PROTO<CJabberProto>, public IJabberInterface
 	bool       m_isSessionAvailable, m_isAuthAvailable;
 	
 	void       __cdecl ServerThread(JABBER_CONN_DATA *info);
+	bool       ServerThreadStub(ThreadData &info);
 		        
 	void       OnProcessFailure(const TiXmlElement *node, ThreadData *info);
 	void       OnProcessFailed(const TiXmlElement *node, ThreadData *info);
diff --git a/protocols/JabberG/src/jabber_strm_mgmt.cpp b/protocols/JabberG/src/jabber_strm_mgmt.cpp
index 93bacf04de..204aab62c8 100644
--- a/protocols/JabberG/src/jabber_strm_mgmt.cpp
+++ b/protocols/JabberG/src/jabber_strm_mgmt.cpp
@@ -214,6 +214,11 @@ void strm_mgmt::ResetState()
 	m_sStrmMgmtResumeId.clear();
 }
 
+void strm_mgmt::HandleConnectionLost()
+{
+	m_bStrmMgmtEnabled = false;
+}
+
 bool strm_mgmt::HandleIncommingNode(const TiXmlElement *node)
 {
 	if (!m_bStrmMgmtEnabled)
diff --git a/protocols/JabberG/src/jabber_strm_mgmt.h b/protocols/JabberG/src/jabber_strm_mgmt.h
index 0cfa01f1df..d8ad0b63fc 100644
--- a/protocols/JabberG/src/jabber_strm_mgmt.h
+++ b/protocols/JabberG/src/jabber_strm_mgmt.h
@@ -49,6 +49,7 @@ public:
 	void EnableStrmMgmt();
 	void HandleOutgoingNode(TiXmlElement *node);
 	bool HandleIncommingNode(const TiXmlElement *node);
+	void HandleConnectionLost();
 	void OnProcessEnabled(const TiXmlElement *node, ThreadData *info);
 	void OnProcessResumed(const TiXmlElement *node, ThreadData *info);
 	void OnProcessFailed(const TiXmlElement *node, ThreadData * info);
diff --git a/protocols/JabberG/src/jabber_thread.cpp b/protocols/JabberG/src/jabber_thread.cpp
index f64651169d..18bcb17cb6 100644
--- a/protocols/JabberG/src/jabber_thread.cpp
+++ b/protocols/JabberG/src/jabber_thread.cpp
@@ -234,11 +234,18 @@ void CJabberProto::xmlStreamInitializeNow(ThreadData *info)
 
 void CJabberProto::ServerThread(JABBER_CONN_DATA *pParam)
 {
-	ThreadData info(this, pParam);
-	ptrA tszValue;
+	Thread_SetName("Jabber: ServerThread");
 
+	do {
+		ThreadData info(this, pParam);
+		if (!ServerThreadStub(info))
+			return;
+	} while (true);
+}
+
+bool CJabberProto::ServerThreadStub(ThreadData &info)
+{
 	debugLogA("Thread started: type=%d", info.bIsReg);
-	Thread_SetName("Jabber: ServerThread");
 
 	if (m_bManualConnect == TRUE) {
 		ptrA szManualHost(getStringA("ManualHost"));
@@ -256,13 +263,15 @@ void CJabberProto::ServerThread(JABBER_CONN_DATA *pParam)
 		// e.g. username, password, etc. from the database.
 		if (m_ThreadInfo != nullptr) {
 			debugLogA("Thread ended, another normal thread is running");
-			return;
+			return true;
 		}
 
 		m_ThreadInfo = &info;
 
-		if ((tszValue = getUStringA("LoginName")) != nullptr)
-			strncpy_s(info.conn.username, tszValue, _TRUNCATE);
+		if (char *pszValue = getUStringA("LoginName")) {
+			strncpy_s(info.conn.username, pszValue, _TRUNCATE);
+			mir_free(pszValue);
+		}
 
 		if (*rtrim(info.conn.username) == '\0') {
 			DWORD dwSize = _countof(info.conn.username);
@@ -281,7 +290,7 @@ LBL_FatalError:
 			int oldStatus = m_iStatus;
 			m_iDesiredStatus = m_iStatus = ID_STATUS_OFFLINE;
 			ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldStatus, m_iStatus);
-			return;
+			return true;
 		}
 
 		ptrA szValue(getStringA("LoginServer"));
@@ -299,7 +308,8 @@ LBL_FatalError:
 				strncpy_s(info.resource, "Miranda", _TRUNCATE);
 		}
 		else {
-			if ((tszValue = getUStringA("Resource")) != nullptr)
+			ptrA tszValue(getUStringA("Resource"));
+			if (tszValue != nullptr)
 				strncpy_s(info.resource, tszValue, _TRUNCATE);
 			else
 				mir_strcpy(info.resource, "Miranda");
@@ -356,7 +366,7 @@ LBL_FatalError:
 	}
 
 	int jabberNetworkBufferSize = 2048;
-	if ((info.buffer = (char*)mir_alloc(jabberNetworkBufferSize + 1)) == nullptr) {	// +1 is for '\0' when debug logging this buffer
+	if ((info.buffer = (char *)mir_alloc(jabberNetworkBufferSize + 1)) == nullptr) {	// +1 is for '\0' when debug logging this buffer
 		debugLogA("Cannot allocate network buffer, thread ended");
 		if (info.bIsReg)
 			info.conn.SetProgress(100, TranslateT("Error: Not enough memory"));
@@ -439,7 +449,7 @@ recvRest:
 				if (p) {
 					char *q = strchr(p + 15, '>');
 					if (q) {
-						CMStringA tmp(info.buffer, int(q - info.buffer)+1);
+						CMStringA tmp(info.buffer, int(q - info.buffer) + 1);
 						tmp.Append("</stream:stream>");
 
 						if (0 == root.Parse(tmp)) {
@@ -451,7 +461,7 @@ recvRest:
 					}
 				}
 			}
-			
+
 			if (bytesParsed == 0) {
 				if (0 == root.Parse(info.buffer)) {
 					for (auto *n : TiXmlEnum(&root))
@@ -471,7 +481,7 @@ recvRest:
 				//jabberNetworkBufferSize += 65536;
 				jabberNetworkBufferSize *= 2;
 				debugLogA("Increasing network buffer size to %d", jabberNetworkBufferSize);
-				if ((info.buffer = (char*)mir_realloc(info.buffer, jabberNetworkBufferSize + 1)) == nullptr) {
+				if ((info.buffer = (char *)mir_realloc(info.buffer, jabberNetworkBufferSize + 1)) == nullptr) {
 					debugLogA("Cannot reallocate more network buffer, go offline now");
 					break;
 				}
@@ -487,7 +497,6 @@ recvRest:
 
 		if (!info.bIsReg) {
 			m_impl.m_keepAlive.Stop();
-			m_iqManager.ExpireAll();
 			m_bJabberOnline = false;
 			info.zlibUninit();
 			EnableMenuItems(false);
@@ -495,6 +504,17 @@ recvRest:
 				// Since this is a different thread, simulate the click on the cancel button instead
 				SendMessage(m_hwndJabberChangePassword, WM_COMMAND, MAKEWORD(IDCANCEL, 0), 0);
 
+			if (m_StrmMgmt.IsResumeIdPresent()) {
+				m_StrmMgmt.HandleConnectionLost();
+				int oldStatus = m_iStatus;
+				m_iStatus = ID_STATUS_CONNECTING;
+				ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldStatus, m_iStatus);
+				return false;
+			}
+
+			m_iqManager.ExpireAll();
+			m_StrmMgmt.ResetState(); // fully reset strm_mgmt state
+
 			// Quit all chatrooms (will send quit message)
 			LISTFOREACH(i, this, LIST_CHATROOM)
 				if (JABBER_LIST_ITEM *item = ListGetItemPtrFromIndex(i))
@@ -513,11 +533,8 @@ recvRest:
 
 			// Set all contacts to offline
 			debugLogA("leaving worker thread");
-			if (!m_StrmMgmt.IsResumeIdPresent()) {
-				m_StrmMgmt.ResetState(); // fully reset strm_mgmt state
-				for (auto &hContact : AccContacts())
-					SetContactOfflineStatus(hContact);
-			}
+			for (auto &hContact : AccContacts())
+				SetContactOfflineStatus(hContact);
 
 			mir_free(m_szJabberJID);
 			m_szJabberJID = nullptr;
@@ -542,6 +559,7 @@ recvRest:
 
 	info.close();
 	debugLogA("Exiting ServerThread");
+	return true;
 }
 
 void CJabberProto::PerformRegistration(ThreadData *info)
@@ -2127,10 +2145,12 @@ int ThreadData::send(TiXmlElement *node)
 		node = parent->ToElement();
 	}
 
-	if (proto->m_bEnableStreamMgmt)
+	int res = send_no_strm_mgmt(node);
+
+	if (res > 0 && proto->m_bEnableStreamMgmt)
 		proto->m_StrmMgmt.HandleOutgoingNode(node); //TODO: is this a correct place ?, looks like some nodes does not goes here...
 
-	return send_no_strm_mgmt(node);
+	return res;
 }
 
 // this function required for send <r/>, <a/> and more important, for resend stuck nodes by strm_mgmt (xep-0198)
-- 
cgit v1.2.3